搬磚----解決貼圖重復(fù)
參考自巨佬iq的文章,文章用兩種方法消除了貼圖重復(fù)問題。
本文在unity里實現(xiàn)了第一種。第二種實現(xiàn)依靠Voronoi分布,以后在說
先看效果----右邊是處理后的效果,消除了重復(fù)感

基本的原理是:對每塊地磚位置的uv進行隨機的翻轉(zhuǎn)和平移,讓每塊紋理出現(xiàn)不同的采樣,然后在地磚邊界處進行混合,消除接縫問題。
1.寫在前面:隨機函數(shù)、ddx/ddy()、uv處理
2.最簡Shader
(請先掃一遍shader部分,我前面寫的有點跳)
1.Hash函數(shù),求偽隨機值
float4 hash4( float2 p ) { return frac(sin ( float4( 1.0+dot(p,float2(37.0,17.0)),
2.0+dot(p,float2(11.0,47.0)),
3.0+dot(p,float2(41.0,29.0)),
4.0+dot(p,float2(23.0,31.0))))*103.0); }
先看frac(sin(x))與frac(sin(x)*103.0)的函數(shù)圖


后者通過乘上103,加大了頻率形成偽隨機數(shù)【偽隨機數(shù)很重要,意味著輸入相同的值,輸出相同的值(不會有time等因素做干擾);如不是隨機數(shù)將無法在每塊磚之間做準(zhǔn)確的融合】。還要注意一點我們的隨機值落在【0,1】之間,方便我們用sign隨機+-號;圖中的x部分也就是Hash里的(a+dot(uv,float(37.,17.)),目的是將uv做降維。【Hash函數(shù)還有很多,有時間總結(jié)一波】
2.ddx() 和 ddy(),分別對應(yīng) x, y 軸上,在屏幕空間中,像素塊中各種變量的變化率。
float2 dx = ddx( uv );
float2 dy = ddy( uv );
dx與dy將用在tex2D(_Tex,uv,dx,dy)上,通過對傳入的uv的偏導(dǎo)數(shù)(很好理解,見下圖),決定到底選擇哪個mipmap的level;dx、dy的缺省值為ddx(uv)/ddy(uv),所以當(dāng)我們改變貼圖的采樣方向時,應(yīng)同時改變dx、dy的±

3.為什么是 float2(0.0,0.0) (1.0,0.0) (1.0,1.0) (0.0,1.0)
float4 ofa = hash4( iuv + float2(0.0,0.0) );
float4 ofb = hash4( iuv + float2(1.0,0.0) );
float4 ofc = hash4( iuv + float2(0.0,1.0) );
float4 ofd = hash4( iuv + float2(1.0,1.0) );
//請先看return
float2 b = smoothstep(_BlendScale,1-_BlendScale,fuv);
return lerp( lerp( tex2D( samp, uva, ddxa, ddya ),
tex2D( samp, uvb, ddxb, ddyb ), b.x ),
lerp( tex2D( samp, uvc, ddxc, ddyc ),
tex2D( samp, uvd, ddxd, ddyd ), b.x), b.y );
從return中可看到我們是先通過 fuv的x分量 將 ↙↘和↖↗分別融合,再通過y分量將上下兩部分融合。所以ofb、ofc、ofd應(yīng)分別對應(yīng)該磚塊位置的x+1、y+1、(x+1,y+1)
完整Shader
Shader "LZ/NoTile"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BlendScale("BlendScale",Range(0,0.5))=0.25
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _BlendScale;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
//制造隨機
float4 hash4( float2 p ) { return frac(sin ( float4( 1.0+dot(p,float2(37.0,17.0)),
2.0+dot(p,float2(11.0,47.0)),
3.0+dot(p,float2(41.0,29.0)),
4.0+dot(p,float2(23.0,31.0))))*103.0); }
float4 textureNoTile( sampler2D samp, float2 uv )
{
//iuv得到該片元所在的磚塊坐標(biāo) fuv該片元在此磚上的位置(常用)
float2 iuv = floor( uv );
float2 fuv = frac( uv );
// 制造隨機4個隨機因子,xy分量用來做位移、zw分量用來做橫向、縱向的貼圖翻轉(zhuǎn)(固值區(qū)0-1之間)
float4 ofa = hash4( iuv + float2(0.0,0.0) );
float4 ofb = hash4( iuv + float2(1.0,0.0) );
float4 ofc = hash4( iuv + float2(0.0,1.0) );
float4 ofd = hash4( iuv + float2(1.0,1.0) );
//ddx 和 ddy,分別對應(yīng) x, y 軸上,在屏幕空間中,像素塊中各種變量的變化率。
float2 dx = ddx( uv );
float2 dy = ddy( uv );
// 上面說zw分量為0-1之間的隨機數(shù),-0.5后用sign求隨機的±
ofa.zw = sign(ofa.zw-0.5);
ofb.zw = sign(ofb.zw-0.5);
ofc.zw = sign(ofc.zw-0.5);
ofd.zw = sign(ofd.zw-0.5);
//對uv改變+-再加偏移 對uv偏導(dǎo)數(shù)區(qū)±
float2 uva = uv*ofa.zw + ofa.xy; float2 ddxa = dx*ofa.zw; float2 ddya = dy*ofa.zw;
float2 uvb = uv*ofb.zw + ofb.xy; float2 ddxb = dx*ofb.zw; float2 ddyb = dy*ofb.zw;
float2 uvc = uv*ofc.zw + ofc.xy; float2 ddxc = dx*ofc.zw; float2 ddyc = dy*ofc.zw;
float2 uvd = uv*ofd.zw + ofd.xy; float2 ddxd = dx*ofd.zw; float2 ddyd = dy*ofd.zw;
// 設(shè)置手動調(diào)節(jié)的融合
float2 b = smoothstep(_BlendScale,1-_BlendScale,fuv);
//先通過 fuv的x分量 將 ↙↘和↖↗分別融合,再通過y分量將上下兩部分融合。
return lerp( lerp( tex2D( samp, uva, ddxa, ddya ),
tex2D( samp, uvb, ddxb, ddyb ), b.x ),
lerp( tex2D( samp, uvc, ddxc, ddyc ),
tex2D( samp, uvd, ddxd, ddyd ), b.x), b.y );
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = textureNoTile(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}