Hello, I am trying to make a shader that makes a silhouette of an object visible when the object is occluded by something based off of answers in this thread. I'm running into an issue however where only the first pass of the shader gets executed and the second one is seemingly ignored. If I switch the order around, whichever the first one is is the one that works. I cannot for the life of me figure out what could cause this, no errors are thrown or anything. The only remotely relevant google result is someone who had an extra bracket and ignored the error telling them they had an extra bracket. This has really been driving me nuts so I appreciate any help offered. Code for reference: Code (CSharp): Shader "Unlit/Universal outline shader v2" { Properties { _MainTex ("Texture", 2D) = "white" {} _OutlineColor("Outline Color", Color) = (0,0,0,0) _ScaleFactor("Scale Factor", Range(0.0, 2.0)) = 0.01 } SubShader { Tags { "RenderType"="Opaque" "Queue"="Geometry+1" } //silhouette pass Pass { Name "Silhouette" ZTest Greater ZWrite Off 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; float4 _OutlineColor; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag(v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); return _OutlineColor; } ENDCG } //regular pass Pass { Name "StandardUnlit" Tags {"Queue"="Geometry+2"} ZTest LEqual ZWrite On 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; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } }
URP doesn't automatically run all shader passes for performance reasons. You could make a second material that has the other pass enabled and add it to the object's material list. It would effectively be the same.
I had been doing that, but as I understand it I need to have this be one shader so I can be certain that the silhouette is drawn before the object in order to prevent the silhouette being visible through the object itself. Also Unity yells at me for doing that and says that it costs performance. Is there no way to force it to run every pass?
You just need to set the Render Queue on the Silhouette material to be lower than the queue value on the other one. That warning is why it doesn't run every pass any more, because multiple passes were a hidden cost many weren't aware of. You can ignore this warning since you are aware now that rendering the object multiple times (shader passes), is more costly. The other option is to manually render the passes from code. But it's simpler to just have 2 materials.
Hello @Invertex do you know how to bypass that and execute the second pass? I've even written a question in StackOverflow I am using this on mobile so I prefer to use one material with two passes if possible
Just updating, I found two solutions and posted 'em in depth in that StackOverflow thread. I was able to bypass the passes to my needs