Using setReplacementShader alongside existing shaders

Hi all

I’m playing with shaders and, fundamentally at least, I’ve got my custom vertex shader to work.

Essentially it takes the player’s forward and right vectors to colour certain objects within the scene.

Shader "Custom/WallColour" {
    Properties {
	  _playerForward ("_playerForward", Vector) = (0,0,0,0)
	  _playerRight( "_playerRight", Vector ) = (0,0,0,0)
    }
    
SubShader 
    {
    	Tags { "Queue" = "Geometry+1" }
        Tags { "RenderType"="WallColour"} 
    
        pass
        {       
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            
            float4 _Color;
            sampler2D _MainTex;
            
            float4 _playerForward;
			float4 _playerRight;
			float4 _playerUp; 
			
			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				fixed4 color : COLOR;
			};
 
            struct v2f
            {
                float4 position : SV_POSITION;
                fixed4 color : COLOR;                
            };
 
            v2f vert( appdata input )
            {
                v2f output;
                output.position = mul( UNITY_MATRIX_MVP, input.vertex );
                output.color = input.color;
                
                float3 worldNormal = mul( (float3x3)_Object2World, input.normal );
                
                float angle = sin( dot( -worldNormal, _playerForward.xyz ) );
				if( angle < 0.9f  angle > 0.8f )
				{
					output.color *= float4(0.5,1,0.5,1);				
				}
				else
				{
					// facing the same way (right)
					angle = sin( dot( worldNormal, _playerRight.xyz ) );
					if( angle < 0.9f  angle > 0.8f )
					{
						output.color *= float4(0.5,0.5,1,1);				
					}
					else
					{
						// facing the opposite way
						angle = sin( dot( worldNormal, _playerRight.xyz ) );
						if( angle > -0.9f  angle < -0.8f )
						{
							output.color *= float4(1,0.5,0.5,1);				
						}
					}
				}
                
                return output;
            }
 
            fixed4 frag( v2f i ) : COLOR0
            {
                return i.color;
            }
            ENDCG
 
        }
    }
    
    FallBack "Diffuse"
}

This shader is used by a camera attached to each player using SetReplacementShader in a script attached to the camera

void OnPreRender()
	{
		if( !enabled )
			return;
		
		Shader.SetGlobalVector( "_playerForward", forward );
		Shader.SetGlobalVector( "_playerRight", right );
		
		camera.SetReplacementShader( wallColourMaterial.shader, "RenderType" );
	}

This works (the colours of the faces of the objects with the right material change depending on the angle between their normal and that of the player) but I lose everything that I don’t specify. So for example, those objects lose their lighting and shadows. Other geometry I have in the scene that doesn’t use the same RenderType tag are still rendered, but lose their set materials/shaders and are rendered in a dark grey. Particle effects are lost completely.

This strikes me as inconsistent as from the documentation it is suggested that if an object in the scene doesn’t have a matching RenderType tag in the replacement shader then it is ignored i.e. not rendered.

In order to try and fix things I started adding in further SubShaders to account for the other RenderType tags (“Opaque”, “Transparent” etc). So far however I’ve had no joy using UsePass “Diffuse/BASE” etc. As I’m using this shader on a camera and not on objects I don’t know how to reference their materials/textures/colours etc to display them properly. I can use UsePass “Toon/Basic Outline/OUTLINE” to get the outlines back on my objects but I can’t get the rest of the material and they have no shadows. Also, I wouldn’t want to have to specify the UsePass shader for every object since not every object will use the same shader.

Ideally I want the replacement shader to just inherit the shader from and object that isn’t tagged with the shader tag name I’m trying to replace. So, all objects that don’t have the “WallColour” tag should get rendered as they would normally. Unfortunately I’m finding the examples and documentation on this area of shaders to be somewhat lacking and I don’t know how much of it is specific to Unity/ShaderLab.

Is there an easier way to achieve this i.e. replace my chosen shader by tag and leave all other shaders unaffected?

Thanks

replacement shaders completely “replace” (the rendertype or whatever tag you want) objects shaders but you can still refference to the properties defined in the original shaders IF you define them again in your replacement shader.

So you’re saying I’d have to re-engineer the shaders? Accessing properties like Main Color etc.?

How, for example, do I know what properties of a particle shader to access? It just seems odd that I’d have to respecify a lot of code just to change the colour of a few vertices. Perhaps I’m missing something, probably more likely misunderstanding something.

Thanks for your help.

Your original shader No1:
Properties:
_MyColor
_MyTexture
_MyVariable

Subshader { RenderType=Opaque, Do Something with _MyColor, MyTexture}

Your original shader No2:
Properties:
_MyOtherColor
_MyOtherTexture
_MyVariable

Subshader { RenderType=Transparent, Do Something with _MyOtherColor, MyOtherTexture, _MyVarible}

Your Replacement shader:
Definitions:
fixed4 _MyColor
float_MyVariable

Subshader { RenderType=Opaque, Do Something with _MyColor(Which is set from the original shader1 already)}
Subshader { RenderType=Transparent, Do Something with _MyVariable(Which is set from the original2 shader already)}

This is how replacement shaders work, and if you want shadows and stuff, you can also use surface shaders as replacement shaders.

EDIT:
For a better example, you can check my Glow Per Object asset in the assetstore. Where you can see how you can also inject properties to normal shaders through scripts.