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
