Vertex and Fragment shader with vertex displacement *and* shadows
Can anyone point me to an example of a vertex and fragment shader that has vertex displacement, and has custom shadow caster and shadow collector passes to cast the shadows from the displaced geometry?
For context I am writing a shader to be used on an entire scene as a replaced shader on the main camera. So the shader needs to be able to both cast and receive shadows as a deformed object.
Answer by wheelissa · Feb 29, 2016 at 04:48 PM
In case it helps anyone, here is the solution that I created. The vertex displacement is just a translation in this code, but you could apply whatever transformation you like in both the vertex program and the shadow caster pass.
My next question: is it possible to have multiple shadow casting passes in a shader? The shader I want to write has multiple passes, each of which performs a vertex displacement (each pass creates a copy of the geometry translated to a unique location). Then I want to cast a shadow from each of these translated geometries. It seems that this requires multiple shadow casting passes, but when I try this, only one of the shadow casting passes seems to work.
Shader "Custom/shadowTest" {
Properties{
_Color ("Color", Color) = (1,1,1,1)
[NoScaleOffset] _MainTex("Texture", 2D) = "white" {}
}
SubShader{
Tags{ "RenderType" = "Opaque" }
LOD 200
Cull Off
Pass
{
Tags{ "LightMode" = "ForwardBase" }
CGPROGRAM
#pragma vertex VertexProgram addshadow
#pragma fragment FragmentProgram
#include "UnityCG.cginc"
// shadow stuff:
#pragma multi_compile_fwdbase
#include "Lighting.cginc"
#include "AutoLight.cginc"
struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
LIGHTING_COORDS(1, 2)
//SHADOW_COORDS(3)
fixed3 diff : COLOR0;
fixed3 ambient : COLOR1;
};
v2f VertexProgram(appdata_full v)
{
v2f o;
// find the world coords of the vertex
float3 u = mul(_Object2World, v.vertex);
// transformation
//u.y = 0.5*u.y;
u.y += 5;
// convert to view coordinates, store the position
v.vertex.xyz = u;
o.pos = mul(UNITY_MATRIX_VP, v.vertex);
// just pass on the uv texture:
o.uv = v.texcoord;
// lighting:
half3 worldNormal = UnityObjectToWorldNormal(v.normal);
// take dot product between normal and light direction for standard
// diffuse (Lambert) lighting
half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
// factor in light color:
o.diff = nl*_LightColor0.rgb;
// add ambient lighting:
o.ambient = ShadeSH9(half4(worldNormal, 1.0));
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}
// Texture to sample, Color
sampler2D _MainTex;
fixed4 _Color;
fixed4 FragmentProgram(v2f i) : SV_Target
{
float atten = LIGHT_ATTENUATION(i);
// Return the relevant color and texture
fixed4 u = tex2D(_MainTex, i.uv);
// darken light's illumination with shadow, keep ambient intact
fixed3 lighting = i.diff*atten + i.ambient;
u.rgb *= lighting;
u *= _Color;
return u;
}
ENDCG
}
// Shadowcaster pass modified to use same vertex transformation as original shader
Pass
{
Tags{ "LightMode" = "ShadowCaster" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert(appdata_full v)
{
v2f o;
TRANSFER_SHADOW_CASTER(o) // this has to be BEFORE the transformation!!!
//// find the world coords of the vertex
float4 u = mul(_Object2World, v.vertex);
////// transformation, use same as above
//u.y = 0.5*u.y;
u.y += 5;
//// convert to view coordinates, store the position
v.vertex.xyz = u;
o.pos = mul(UNITY_MATRIX_VP, v.vertex);
return o;
}
float4 frag(v2f i) : SV_Target
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
//FallBack "Diffuse"
}
Did you find a solution how to avoid the duplication of transformation code?