Suuure, it's not too impressive - there's no PSSM or VSM or any of that fancy crap, since I just use it for structure and nature geometry. But it's really easy to implement.
Load:
CameraShadow = TVCameraFactory.CreateCamera();
CameraShadow.SetViewIsometric(512.0f, 1024.0f, 1.0f);
SurfaceShadow = TVScene.CreateRenderSurface(1024, 1024, true, CONST_TV_RENDERSURFACEFORMAT.TV_TEXTUREFORMAT_HDR_R32F);
SurfaceShadow.SetNewCamera(CameraShadow);
SurfaceShadow.SetBackgroundColor(TVMath.Globals.RGBA(0.0f, 0.0f, 1.0f, 1.0f));
Update:
TV_4DVECTOR ShadowPosition = new TV_4DVECTOR(Position.x + 256.0f, 768.0f, Position.z + 256.0f, 1024.0f);
CameraShadow.SetCamera(ShadowPosition.x, ShadowPosition.y, ShadowPosition.z, Position.x, 0.0f, Position.z);
TV_3DMATRIX ShadowMatrix = new TV_3DMATRIX();
TVMath.Math.TVMatrixMultiply(ref ShadowMatrix, CameraShadow.GetViewMatrix(), CameraShadow.GetProjectionMatrix());
foreach (FWorld World in Scene.WorldList)
{
World.ShaderTerrain.SetEffectParamVector("ShadowPosition", ShadowPosition);
World.ShaderTerrain.SetEffectParamMatrix("ShadowMatrix", ShadowMatrix);
World.ShaderTerrainDepth.SetEffectParamVector("ShadowPosition", ShadowPosition);
}
//Render using depth shader
SurfaceShadow.StartRender(false);
Scene.Render(CONSTANT.RENDERMODE_DEPTH);
SurfaceShadow.EndRender();
Depth Shader:
//////////////////////////////////////////////////
//
// Shadow Shader
//
//////////////////////////////////////////////////
/////////////////////////
// ShadowPosition
// tex0 Texture
float4 ShadowPosition;
texture tex0:TEXTURE0;
sampler2D samp0 = sampler_state
{
texture = (tex0);
};
matrix WorldMatrix:World;
matrix VPMatrix:ViewProjection;
struct IN0
{
float4 pos : POSITION;
};
struct OUT0
{
float4 pos : POSITION;
float depth : TEXCOORD0;
};
OUT0 VS(IN0 IN)
{
OUT0 OUT;
float4 Wpos = mul(IN.pos,WorldMatrix);
OUT.pos = mul(Wpos,VPMatrix);
OUT.depth = saturate((ShadowPosition.y-Wpos.y)/ShadowPosition.w);
return OUT;
}
float4 PS(OUT0 IN) : COLOR
{
float Color = IN.depth;
return float4(Color,0,0,1);
}
technique Depth
{
pass P0
{
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_2_0 PS();
}
}
Okay, it didn't need the texture struct, but I keep it in there just incase anybody wants to implement alpha transparency. I've got a minimesh depth shader too, if anybody is too lazy to make one.
The REAL shader:
//////////////////////////////////////////////////
//
// Terrain Shader
//
//////////////////////////////////////////////////
/////////////////////////
// ShadowPosition;
// ShadowMatrix;
// tex0 Low Layer
// tex1 Shadow
float4 ShadowPosition;
matrix ShadowMatrix;
texture tex0:TEXTURE0;
sampler2D samp0 = sampler_state
{
texture = (tex0);
};
texture tex1:TEXTURE1;
sampler2D samp1 = sampler_state
{
texture = (tex1);
};
matrix ViewProjectionMatrix:ViewProjection;
matrix WorldMatrix:World;
float3 ViewPosition:ViewPosition;
matrix ViewMatrix={0.5,0,0,0.5,0,-0.5,0,0.5,0,0,0.5,0.5,0,0,0,1}; //Whatever you do, don't change this
float ZDepth = 0.004f; //You might have to change this
struct IN0
{
float4 pos : POSITION;
float2 uv0 : TEXCOORD0;
};
struct OUT0
{
float4 pos : POSITION;
float4 uv0 : TEXCOORD0;
float4 shadowproj : TEXCOORD1;
};
OUT0 VS(IN0 IN)
{
OUT0 OUT;
float4 Wpos = mul(IN.pos,WorldMatrix);
OUT.pos = mul(Wpos,ViewProjectionMatrix);
OUT.uv0 = IN.uv0;
OUT.shadowproj.xy = mul(ViewMatrix,mul(Wpos,ShadowMatrix));
OUT.shadowproj.z = ShadowPosition.y-Wpos.y;
Distance = float2(0.5f, 0.5f) - OUT.shadowproj.xy;
OUT.shadowproj.w = 1.0f - saturate(4.0f * dot(Distance, Distance));
return OUT;
}
float4 PS(OUT0 IN) : COLOR
{
float4 Diffuse = tex2D(samp1, IN.uv0)
float Depth = 4.0f;
//I forget what this technique is called, but it helps smooth out the edges of the shadows
Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(0.00025f,0.00025f)).r+ZDepth;
Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(-0.00025f,-0.00025f)).r+ZDepth;
Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(-0.00025f,0.00025f)).r+ZDepth;
Depth -= IN.shadowproj.z/ShadowPosition.w>tex2D(samp4, IN.shadowproj.xy+float2(0.00025f,-0.00025f)).r+ZDepth;
Depth /= 4;
Depth = lerp(1.0f, Depth, IN.shadowproj.w);
float4 Shadow = float4(0.5, 0.4, 0.3, 1.0) * Depth;
float4 RGBA = Diffuse * (Shadow + float4(0.4f, 0.4f, 0.4f, 1.0f));
return RGBA;
}
technique Albedo
{
pass P0
{
VertexShader = compile vs_2_0 VS();
PixelShader = compile ps_2_0 PS();
}
}
It's disorganized because I haven't finished everything yet! It shouldn't be too hard to figure out, though. The two float4s in the shader that aren't using a neat variable name are just directional and ambient light, which should be parametrized. So should some other things, but to me, it's not worth the effort of de-organizing everything. Oh, and this one has a neat fade at the edges instead of the clipping like the old light shader used.
My original shader has these two combined, so I've really just made it more difficult for you to use both (they should work alone, I haven't tried)
