Unity Shader模板測試-描邊
阿新 • • 發佈:2020-11-19
Unity Shader模板測試描邊效果,常用於 rpg 專案中主角被遮擋的情況,將被遮擋的部分的輪廓描邊繪製出來,這樣可以在任何情況都能知道主角在哪裡。(還有另外一種就是使用X光效果,但這種效果不需要用到模板測試,所以這裡用 描邊效果 舉例子)
效果如下: 思路 實現這種效果需要兩個pass 1、正常繪製,即深度測試 LEqual,正常遮擋,同時往 模板緩衝區 寫入一個 參考值 Ref=1(即使深度測試失敗的值也要寫入,保證 角色所有畫素在模板緩衝區的值 都是 參考值 Ref=1) 2、只繪製被遮擋部分的描邊- 先把模型的 頂點 往 法線方向 偏移一個值(這個就是描邊的寬度值,可以理解為將模型放大了),可以在觀察空間 或者 世界空間、模型空間 偏移,只要和 法線 在同一空間下。
- 對比 模板緩衝區 的參考值 Ref=1,因為第一個 pass 寫入的參考值是 1,所以這個pass中就要不等1才讓它通過,這樣就能得到一個 差值區域,即描邊的區域。
- 深度測試,讓被遮擋部分才讓它通過,即 ZTest Greater,done!
Shader "Custom/Unlit-Texture-Outline" { Properties{ _MainTex("Base (RGB)", 2D) = "white" {} _OutlineColor("Outline Color", Color) = (1,1,0,1) //描邊顏色 _Outline("Outline width", Range(0.0, 0.5)) = 0.03 // 描邊寬度 } CGINCLUDE #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; float3 normal : NORMAL; }; struct v2f { float4 vertex : SV_POSITION; half2 texcoord : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; float _Outline; float4 _OutlineColor; v2f vert(appdata_t v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } v2f vert_outline(appdata_t v) { v2f o; // 方式一,觀察空間 下往法線偏移頂點 float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex); //float3 viewNorm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal); float3 viewNorm = mul(v.normal, (float3x3)UNITY_MATRIX_T_MV); float3 offset = normalize(viewNorm) * _Outline; viewPos.xyz += offset; o.vertex = mul(UNITY_MATRIX_P, viewPos); //方式二,世界空間 下往法線偏移頂點 //float4 worldPos = mul(unity_ObjectToWorld, v.vertex); //float3 worldNormal = UnityObjectToWorldNormal(v.normal); //float3 offset = normalize(worldNormal) * _Outline; //worldPos.xyz += offset; //o.vertex = mul(UNITY_MATRIX_VP, worldPos); return o; } ENDCG SubShader{ Tags{ "Queue" = "Transparent" "RenderType" = "Opaque" } Pass{ // 正常繪製 Stencil { Ref 1 Comp Always Pass Replace ZFail Replace } ZTest LEqual CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 frag(v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.texcoord); return col; } ENDCG } Pass{ // 遮擋部分繪製描邊 ZTest Greater ZWrite Off //Blend DstAlpha OneMinusDstAlpha Stencil{ Ref 1 Comp NotEqual } CGPROGRAM #pragma vertex vert_outline #pragma fragment frag half4 frag(v2f i) :COLOR { return _OutlineColor; } ENDCG } } }
// 這種方式的描邊不適合做遮擋部分描邊,且不遮擋部分的效果也沒有 模板測試 那種方式好 Shader "ITS/test/testOutline_cull" { Properties{ _MainTex("Base (RGB)", 2D) = "white" {} _OutlineColor("Outline Color", Color) = (1,1,0,1) _Outline("Outline width", Range(0.0, 0.5)) = 0.03 } CGINCLUDE #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; float2 texcoord : TEXCOORD0; float3 normal : NORMAL; }; struct v2f { float4 vertex : SV_POSITION; half2 texcoord : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; float _Outline; float4 _OutlineColor; v2f vert(appdata_t v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); return o; } v2f vert_outline(appdata_t v) { v2f o; // 方式一,觀察空間 下往法線偏移頂點 float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex); //float3 viewNorm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal); float3 viewNorm = mul(v.normal, (float3x3)UNITY_MATRIX_T_MV); float3 offset = normalize(viewNorm) * _Outline; viewPos.xyz += offset; o.vertex = mul(UNITY_MATRIX_P, viewPos); //方式二,世界空間 下往法線偏移頂點 //float4 worldPos = mul(unity_ObjectToWorld, v.vertex); //float3 worldNormal = UnityObjectToWorldNormal(v.normal); //float3 offset = normalize(worldNormal) * _Outline; //worldPos.xyz += offset; //o.vertex = mul(UNITY_MATRIX_VP, worldPos); return o; } ENDCG SubShader{ Tags{ "Queue" = "Transparent" "RenderType" = "Opaque" } Pass{ ZTest LEqual Cull Back CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 frag(v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.texcoord); return col; } ENDCG } Pass{ // ZTest Greater ZWrite Off Cull Front Offset 100,0 CGPROGRAM #pragma vertex vert_outline #pragma fragment frag half4 frag(v2f i) : COLOR { return _OutlineColor; } ENDCG } } }