Unity Shader 正確陰影的溶解效果

Unity Shader系列文章:Unity Shader目錄-初級篇

Unity Shader系列文章:Unity Shader目錄-中級篇

效果:
溶解效果

所需貼圖:


箱子貼圖
法線貼圖
噪聲貼圖

shader代碼:

// 溶解效果 (附帶正確陰影投射)
Shader "Custom/Dissolve"
{
    Properties
    {
        _BurnAmount ("Burn Amount", Range(0, 1)) = 0 // 控制消融程度
        _LineWidth ("Line Width", Range(0, 0.2)) = 0.1 // 消融時(shí)邊緣的線寬
        _MainTex ("Texture", 2D) = "white" { }
        _BumpMap ("Normal Map", 2D) = "bump" { }// 法線紋理
        _BurnFirstColor ("Burn First Color", Color) = (1, 0, 0, 1) // 消融邊緣第一種顏色
        _BurnSecondColor ("Burn Second Color", Color) = (1, 0, 0, 1) // 消融邊緣第二種顏色
        _BurnMap ("Burn Map", 2D) = "white" { }// 噪聲紋理
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" "Queue" = "Geometry" }

        // Base Pass 計(jì)算平行光蚓胸、環(huán)境光
        Pass
        {
            Tags { "LightMode" = "ForwardBase" }

            // 關(guān)閉剔除盐固,正面和背面都會渲染 (因?yàn)橄跁?dǎo)致裸露模型內(nèi)部的構(gòu)造)
            Cull Off

            CGPROGRAM

            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            // 編譯指令剖煌,保證在pass中得到Pass中得到正確的光照變量
            #pragma multi_compile_fwdbase

            #pragma vertex vert
            #pragma fragment frag

            fixed _BurnAmount;
            fixed _LineWidth;
            sampler2D _MainTex;
            sampler2D _BumpMap;
            fixed4 _BurnFirstColor;
            fixed4 _BurnSecondColor;
            sampler2D _BurnMap;

            // 紋理的縮放和偏移系數(shù)
            float4 _MainTex_ST;
            float4 _BumpMap_ST;
            float4 _BurnMap_ST;

            // 應(yīng)用傳遞給定點(diǎn)著色器的數(shù)據(jù)
            struct a2v
            {
                float4 vertex: POSITION; // 語義: 頂點(diǎn)坐標(biāo)
                float3 normal: NORMAL; // 語義: 法線
                float4 tangent: TANGENT; // 語義: 切線
                float4 texcoord: TEXCOORD0; // 語義: 紋理坐標(biāo)
            };
            
            // 頂點(diǎn)著色器傳遞給片元著色器的數(shù)據(jù)
            struct v2f
            {
                float4 pos: SV_POSITION; // 語義: 裁剪空間的頂點(diǎn)坐標(biāo)
                float2 uvMainTex: TEXCOORD0;
                float2 uvBumpMap: TEXCOORD1;
                float2 uvBurnMap: TEXCOORD2;
                float3 lightDir: TEXCOORD3;
                float3 worldPos: TEXCOORD4;
                SHADOW_COORDS(5) // 內(nèi)置宏:聲明一個(gè)用于對陰影紋理采樣的坐標(biāo) (這個(gè)宏參數(shù)需要是下一個(gè)可用的插值寄存器的索引值桦踊,這里是5)
            };

            // 頂點(diǎn)著色器
            v2f vert(a2v v)
            {
                v2f o;

                // 將頂點(diǎn)坐標(biāo)從模型空間變換到裁剪空間
                // 等價(jià)于o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.pos = UnityObjectToClipPos(v.vertex);

                // 計(jì)算紋理坐標(biāo) (縮放和平移)
                // 等價(jià)于o.uv = v.texcoord * _MainTex_ST.xy + _MainTex_ST.zw;
                o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.uvBumpMap = TRANSFORM_TEX(v.texcoord, _BumpMap);
                o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);

                // 內(nèi)置宏:TANGENT_SPACE_ROTATION(切線空間到模型空間的變換矩陣)等價(jià)于:
                // 使用模型空間下的法線方向和切線方向叉積得到副切線方向
                // float3 binormal = cross(normalize(v.normal), normalize(v.tangent.xyz)) * v.tangent.w;
                //定義 3x3 變換矩陣 rotation芳悲,分別將切線方向、副切線方向和法線方向按行擺放組成了這個(gè)矩陣漠趁。
                // float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);
                TANGENT_SPACE_ROTATION;
                // 將光向量從模型空間變換到切線空間
                o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;

                // 將觀察向量從模型空間變換到切線空間
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

                // 內(nèi)置宏:用于計(jì)算聲明的陰影紋理坐標(biāo)
                TRANSFER_SHADOW(o);

                return o;
            }

            // 片元著色器
            fixed4 frag(v2f i): SV_TARGET
            {
                fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;

                // burn.r - _BurnAmount < 0 則放棄此片元不繪制
                clip(burn.r - _BurnAmount);

                fixed3 tangentLightDir = normalize(i.lightDir);
                // 若法線紋理Texture Type未設(shè)置成Normal map离唐,
                // 要從像素映射回法線,即[0, 1]轉(zhuǎn)化到[-1, 1]
                // tangentNormal.xy = (packedNormal.xy * 2 - 1) * _BumpScale;
                
                // 如果設(shè)置了Normal map類型沸毁,Unity會根據(jù)平臺使用不同的壓縮方法峰髓,
                // _BumpMap.rbg值不是對應(yīng)的切線空間的xyz值了,要用Unity內(nèi)置函數(shù)
                fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));

                fixed3 albedo = tex2D(_MainTex, i.uvMainTex);

                // 獲得環(huán)境光
                fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

                // 計(jì)算漫反射
                // 蘭伯特公式:Id = Ip * Kd * N * L
                // IP:入射光的光顏色息尺;
                // Kd:漫反射顏色携兵;
                // N:單位法向量;
                // L:單位光向量搂誉;
                fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentLightDir, tangentNormal));

                // 使用了 smoothstep 函數(shù)來計(jì)算混合系數(shù)徐紧。當(dāng)t值為1時(shí),表明該像素位于消融的邊界處炭懊;
                // 當(dāng)t值為0時(shí)浪汪,表明該像素為正常的模型顏色,而中間的插值則表示需要模擬一個(gè)燒焦效果凛虽。
                fixed t = 1 - smoothstep(0, _LineWidth, burn.r - _BurnAmount);
                fixed3 burnColor = lerp(_BurnFirstColor, _BurnSecondColor, t);
                // 為了讓效果更接近燒焦的痕跡,還使用 pow 函數(shù)對結(jié)果進(jìn)行處理
                burnColor = pow(burnColor, 5);

                // 計(jì)算陰影值和光照衰減
                UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);

                fixed3 finalColor = lerp(ambient + diffuse * atten, burnColor, t * step(0.0001, _BurnAmount));

                return fixed4(finalColor, 1);
            }

            ENDCG

        }

        // 自定義用于投射陰影的 Pass (如果仍然使用普通的陰影 Pass广恢,那么被剔除的區(qū)域仍然會向其他物體投射陰影凯旋,造成“穿幫”。)
        Pass
        {
            Tags { "LightMode" = "ShadowCaster" }

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            #pragma multi_compile_shadowcaster

            #include "UnityCG.cginc"

            fixed _BurnAmount;
            sampler2D _BurnMap;
            float4 _BurnMap_ST;

            struct v2f
            {
                V2F_SHADOW_CASTER;
                float2 uvBurnMap: TEXCOORD1;
            };

            v2f vert(appdata_base v)
            {
                v2f o;

                TRANSFER_SHADOW_CASTER_NORMALOFFSET(o);

                o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);

                return o;
            }

            fixed4 frag(v2f i): SV_TARGET
            {
                // 已經(jīng)消融的面片,不再投影
                fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;
                clip(burn.r - _BurnAmount);

                // Unity內(nèi)置宏至非,把結(jié)果輸出到深度圖和陰影映射紋理中
                SHADOW_CASTER_FRAGMENT(i)
            }

            ENDCG

        }
    }

    Fallback "Diffuse"
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钠署,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子荒椭,更是在濱河造成了極大的恐慌谐鼎,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趣惠,死亡現(xiàn)場離奇詭異狸棍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)味悄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門草戈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人侍瑟,你說我怎么就攤上這事唐片。” “怎么了涨颜?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵费韭,是天一觀的道長。 經(jīng)常有香客問我庭瑰,道長星持,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任见擦,我火速辦了婚禮钉汗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鲤屡。我一直安慰自己损痰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布酒来。 她就那樣靜靜地躺著卢未,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堰汉。 梳的紋絲不亂的頭發(fā)上辽社,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音翘鸭,去河邊找鬼滴铅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛就乓,可吹牛的內(nèi)容都是我干的汉匙。 我是一名探鬼主播拱烁,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼噩翠!你這毒婦竟也來了戏自?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤伤锚,失蹤者是張志新(化名)和其女友劉穎擅笔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屯援,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猛们,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玄呛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阅懦。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖徘铝,靈堂內(nèi)的尸體忽然破棺而出耳胎,到底是詐尸還是另有隱情,我是刑警寧澤惕它,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布怕午,位于F島的核電站,受9級特大地震影響淹魄,放射性物質(zhì)發(fā)生泄漏郁惜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一甲锡、第九天 我趴在偏房一處隱蔽的房頂上張望兆蕉。 院中可真熱鬧,春花似錦缤沦、人聲如沸虎韵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽包蓝。三九已至,卻和暖如春企量,著一層夾襖步出監(jiān)牢的瞬間测萎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工届巩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留硅瞧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓恕汇,卻偏偏與公主長得像零酪,于是被迫代替她去往敵國和親冒嫡。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內(nèi)容