消除貼圖重復(fù)感

搬磚----解決貼圖重復(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
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我用100字結(jié)束了2018年的日更寫作,現(xiàn)在,在進入2019年的最初幾分鐘,我也將用100字開始我的2019年日更...
    謙這武器閱讀 78評論 0 0
  • 還記得畢業(yè)時候的你嗎,你工作的第一年,還沒有把握好工作和感情,一邊忙著行里的年終決算,一邊想著該怎么解釋那晚的遲到...
    truce閱讀 185評論 0 0
  • 不知道應(yīng)該用神馬做標(biāo)題,那就用今天的日期吧。不知不覺,到了2019年。嗯。傳說中我犯太歲的這一年也終于來了?;仡櫸?..
    解雨臣家的西府海棠閱讀 177評論 0 0
  • 《喬布斯傳》中有一句讓人印象深刻的話:“只有那些瘋狂到以為自己能夠改變世界的人,才能真正改變世界!”而喬布斯正是這...
    甜茶不加奶閱讀 1,081評論 0 8
  • 文/邀歌 一、詠桂樹 我怎么遙看你這一汪翠綠 和那點點滴滴的鵝黃 像幾只小鴨子在草叢中戲玩 又似清湖中的點點星光 ...
    邀歌閱讀 402評論 5 4

友情鏈接更多精彩內(nèi)容