I like to make games with large outdoor areas to explore. I also want the sun (at least) to cast shadows.
But if you make a shadowmap for the entire terrain it will be very low resolution and look really ugly.
So I decided that a good comptomise would be to display hires shadows for objects close to the camera, and have these shadows fade-out as you move away (and possibly replaced with simple ‘drop’ shadows).
The great thing about this is that it’s really easy to implement. I use an orthographic light camera for the sun, and attach it to the main camera so that it moves with the camera and points directly at it (or a little in front) in the right direction for the sun. At the moment I’m doing this manually, but it would probably be better to use a compassEffect.
The only other requirement is a small change to the shadow shader as shown below:
//Cg
void vshader(float4 vtx_position : POSITION,
float2 vtx_texcoord0: TEXCOORD0,
float3 vtx_normal: NORMAL,
uniform float4x4 trans_model_to_clip_of_light,
uniform float4x4 mat_modelproj,
uniform float4 mspos_light,
uniform float4 k_ambient,
uniform float4 k_scale,
uniform float4 k_push,
out float4 l_position : POSITION,
out float2 l_texcoord0 : TEXCOORD0,
out float4 l_shadowcoord : TEXCOORD1,
out float l_smooth : TEXCOORD2,
out float4 l_lightclip : TEXCOORD3
)
{
float4 position = vtx_position * k_scale;
// vertex position
l_position = mul(mat_modelproj, position);
// Pass through texture coordinate for main texture.
l_texcoord0 = vtx_texcoord0;
// Calculate the surface lighting factor.
l_smooth = saturate(dot(vtx_normal, normalize(mspos_light - position)));
// Calculate light-space clip position.
float4 pushed = position + float4(vtx_normal * k_push, 0);
l_lightclip = mul(trans_model_to_clip_of_light, pushed);
// Calculate shadow-map texture coordinates.
l_shadowcoord = l_lightclip * float4(0.5,0.5,0.5,1.0) + l_lightclip.w * float4(0.5,0.5,0.5,0.0);
}
void fshader(in float2 l_texcoord0 : TEXCOORD0,
in float4 l_shadowcoord : TEXCOORD1,
in float l_smooth : TEXCOORD2,
in float4 l_lightclip : TEXCOORD3,
uniform sampler2D tex_0 : TEXUNIT0,
uniform sampler2D k_Ldepthmap : TEXUNIT1,
uniform float4 k_ambient,
uniform float4 k_texDisable,
out float4 o_color:COLOR)
{
float3 circleoffs = float3(l_lightclip.xy / l_lightclip.w, 0);
float falloff = saturate(1.0 - dot(circleoffs, circleoffs));
float4 baseColor = saturate(tex2D(tex_0, l_texcoord0) + k_texDisable);
float shade = tex2Dproj(k_Ldepthmap,l_shadowcoord);
/***** this is the only line that has changed *****/
o_color = baseColor * ( falloff * shade * l_smooth + (1.0-falloff)*l_smooth + k_ambient.x );
}
Obviously you can replace l_smooth with whatever other lighting calculations you want to make. I’d also like to smooth the shadows to make them look even better.
So what do you think? Can you think of any further improvements? Is anybody else using a similar method?