Shader實例:邊緣發光和描邊


效果圖:

1.邊緣發光
思路:用視方向和法線方向點乘,模型越邊緣的地方,它的法線和視方向越接近90度。點乘越接近0
那么用 1-減去上面點乘的結果,來作為顏色分量,來反映邊緣顏色強弱。

Shader "Custom/OutLine1" 
{
    Properties
    {
        _MainTex("main tex",2D) = "black"{}
        _RimColor("rim color",Color) = (1,1,1,1)//邊緣顏色
        _RimPower ("rim power",range(1,10)) = 2//邊緣強度
    }
 
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include"UnityCG.cginc"
 
            struct v2f
            {
                float4 vertex:POSITION;
                float4 uv:TEXCOORD0;
                float4 NdotV:COLOR;
            };
 
            sampler2D _MainTex;
            float4 _RimColor;
            float _RimPower;
 
            v2f vert(appdata_base v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = v.texcoord;
                float3 V = WorldSpaceViewDir(v.vertex);
                V = mul(_World2Object,V);//視方向從世界到模型坐標系的轉換
                o.NdotV.x = saturate(dot(v.normal,normalize(V)));//必須在同一坐標系才能正確做點乘運算
                return o;
            }
 
            half4 frag(v2f IN):COLOR
            {
                half4 c = tex2D(_MainTex,IN.uv);
                //用視方向和法線方向做點乘,越邊緣的地方,法線和視方向越接近90度,點乘越接近0.
                //用(1- 上面點乘的結果)*顏色,來反映邊緣顏色情況
                c.rgb += pow((1-IN.NdotV.x) ,_RimPower)* _RimColor.rgb;
                return c;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

2.描邊(一)
思路:兩次渲染,第一次渲染背面,剔除正面,把模型頂點沿法線方向擴伸一定距離(用來表現描邊的粗細)
第二次渲染,渲染正面,剔除背面

Shader "Custom/OutLine2"
{
    Properties
    {
        _MainTex("main tex",2D) = ""{}
        _Factor("factor",Range(0,0.1)) = 0.01//描邊粗細因子
        _OutLineColor("outline color",Color) = (0,0,0,1)//描邊顏色
    }
 
    SubShader 
    {
        Pass
        {
            Cull Front //剔除前面
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
 
            struct v2f
            {
                float4 vertex :POSITION;
            };
 
            float _Factor;
            half4 _OutLineColor;
 
            v2f vert(appdata_full v)
            {
                v2f o;
                //v.vertex.xyz += v.normal * _Factor;
                //o.vertex = mul(UNITY_MATRIX_MVP,v.vertex);
 
                //變換到視坐標空間下,再對頂點沿法線方向進行擴展
                float4 view_vertex = mul(UNITY_MATRIX_MV,v.vertex);
                float3 view_normal = mul(UNITY_MATRIX_IT_MV,v.normal);
                view_vertex.xyz += normalize(view_normal) * _Factor; //記得normalize
                o.vertex = mul(UNITY_MATRIX_P,view_vertex);
                return o;
            }
 
            half4 frag(v2f IN):COLOR
            {
                //return half4(0,0,0,1);
                return _OutLineColor;
            }
            ENDCG
        }
 
        Pass
        {
            Cull Back //剔除后面
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
 
            struct v2f
            {
                float4 vertex :POSITION;
                float4 uv:TEXCOORD0;
            };
 
            sampler2D _MainTex;
 
            v2f vert(appdata_full v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = v.texcoord;
                return o;
            }
 
            half4 frag(v2f IN) :COLOR
            {
                //return half4(1,1,1,1);
                half4 c = tex2D(_MainTex,IN.uv);
                return c;
            }
            ENDCG
        }
    } 
    FallBack "Diffuse"
}

3.描邊(二)
思路:兩次渲染。第一次渲染背面,剔除正面。利用Offset指令,向離攝像機更近的方式偏移
第二次正常渲染物體(不剔除),(或者可以渲染正面,剔除背面)。

Offset:深度偏移
Offset Factor,Units
Factor參數表示 Z縮放的最大斜率的值。
Units參數表示可分辨的最小深度緩沖區的值。

我的理解:深度偏移,Unity是左手坐標系,Z的正方向是朝屏幕里面。
沿Z的負方向偏移就是離攝像機更近,
沿Z的正方向偏移就是離攝像機更遠。

作用:可以強制使位於同一位置上的兩個幾合體中的一個幾何體繪制在另一個的上層
比如:幾何體A的Z值比幾何體B更遠,此時B是在A的上層。
但是,給A設置了Offset 往Z的負方向偏移,此時A比B更近了,A就在B上層了。
在深度測試(Z test)的時候,會去比較Z值,近的會繪制在遠的上面。

所以上面的思路,要么第一次渲染背面,往Z的負方向偏移
要么第二次渲染的,往Z的正方向偏移,都是可以的。

Shader "Custom/OutLine3" 
{
    Properties
    {
        _MainTex("main tex", 2D) = ""{ }
        _OutLineColor("outline color",Color) = (0,0,0,1)//描邊顏色
    }
 
    SubShader
    {
        //描邊
        pass
        {
            Cull Front
            Offset -5,-1 //深度偏移
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
 
            sampler2D _MainTex;
            half4 _OutLineColor;
 
            struct v2f
            {
                float4  pos : SV_POSITION;
            };
 
            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                return o;
            }
 
            float4 frag(v2f i) : COLOR
            {
                return _OutLineColor;
            }
            ENDCG
        }
 
        //正常渲染物體
        pass
        {
            //Cull Back
            //Offset 5,-1
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
 
            sampler2D _MainTex;
            float4 _MainTex_ST;
 
            struct v2f
            {
                float4  pos : SV_POSITION;
                float2  uv : TEXCOORD0;
            };
 
            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }
 
            float4 frag(v2f i) : COLOR
            {
                float4 c = tex2D(_MainTex,i.uv);
                return c;
            }
            ENDCG
        }
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM