1. 程式人生 > >官網的shader stencilBuffer篇(續)

官網的shader stencilBuffer篇(續)

<span style="font-family: Arial, Helvetica, sans-serif;">上一篇寫到一個自負不能被擋的球,最後被擋了。</span>

這一篇做一些聯想,先對那個檔他的球的shader做一個修改,shader採用那個半黃半紅的code

Shader "HolePrepare" {
    SubShader {
        Tags { "RenderType"="Opaque" "Queue"="Geometry+3"}//這裡修改一個渲染次序,把這個球的渲染次序放在那個擋不住的球之後
        //ColorMask 0
        ZWrite off
        Stencil {
            Ref 1
            Comp always
            Pass replace
        }

        CGINCLUDE
            struct appdata {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 pos : SV_POSITION;
            };
            v2f vert(appdata v) {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                return o;
            }
            half4 frag(v2f i) : SV_Target {
                return half4(1,1,0,1);
            }
            
            half4 frag2(v2f i) : SV_Target {
                return half4(1,0,0,1);
            }
        ENDCG

        Pass {
            Cull Front
            ZTest Less
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            ENDCG
        }
        Pass {
            Cull Back
            ZTest Greater
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag2
            ENDCG
        }
    } 
}
先貼一張上次的圖,就是把上次的擋它的球的shader換成另外一個,效果如下

然後再看看這次的效果


嗯,中間那塊不一樣了

根據之前的理論,這個雙色球顯示的原理是,沒有被擋,顯示內表面的顏色(黃色),被擋,顯示正面的顏色(紅色)

推測一下,黃色區域產生的原因是,這個雙色球在這個紅色球之前,因為紅色球有一個cull front 的語句,所以,它只渲染內表面的朝向視角部分,就是說,它在深度測試通過之後應該是對深度值進行了賦值,所以depth buffer變成了它的。那對於雙色球而言,那個交叉部分就是在它之前,所以顯示為黃色。

所以說渲染順序很重要,它決定了depth buffer的值

這裡還有一個有趣的現象是,當你換個角度。


這裡中間交叉部分,紅球內表面在雙色球內外表面中間,所以雙色球不發揮作用,另一邊是雙色球內表面在紅色球之前,所以能通過深度測試,顯示出來

再換個角度,把這個紅色球放在前面。


同樣的理論,中間是紅色球在雙色球內,雙色球不發揮作用,紅色圈圈是因為雙色球被擋,所以顯示紅色

然後,對於深度測試後賦值這個推論,還要進行考證。

為此,另外製作了一個球,藍色球

Shader "Custom/ShaderForDepth" {
	SubShader {
		Tags { "RenderType"="Opaque" "Queue"="Geometry+3"}
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert

		struct Input {
			float2 uv_MainTex;
		};
		
		void surf (Input IN, inout SurfaceOutput o) {
			
			o.Albedo = half3(0,0,1);
			o.Alpha = 1.0;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

這個球和普通的球一樣,可以被平面遮擋,但是,僅有一個不同是它的渲染次序也在那個擋不住的球之後

如圖


所以,將它們放在一起


可以看到藍色球可以被平面切割,與紅色球相交部分可以遮擋紅色球

所以推論成功,深度測試之後會對深度buffer進行賦值,所以上面的渲染順序是很重要的。