Hi there,
in the last few days i was fiddeling around with variance shadow maps. I tried hard to implement them in the engine i'm using and finally managed to do it
I then added shadow transparency and the colormap. Looking really good so far
Now i want to blur the shadows, but to be honest i don't have a clue on how to do that. I tried to render the shadowmap to a separate view, then blur it and project it back to the scene, but as you may have already guessed by now i get nasty halo effects. As far as i know, there should be a way better way to blur the shadow. If I didn't get that wrong, then that's the whole thing about vsm: having a good base to blur the shadows.
Here's my code (basically AndyTX's code, with some minor changes so the engine can use it)
Is someone able to help me out here?
in the last few days i was fiddeling around with variance shadow maps. I tried hard to implement them in the engine i'm using and finally managed to do it
I then added shadow transparency and the colormap. Looking really good so far
Now i want to blur the shadows, but to be honest i don't have a clue on how to do that. I tried to render the shadowmap to a separate view, then blur it and project it back to the scene, but as you may have already guessed by now i get nasty halo effects. As far as i know, there should be a way better way to blur the shadow. If I didn't get that wrong, then that's the whole thing about vsm: having a good base to blur the shadows.
Here's my code (basically AndyTX's code, with some minor changes so the engine can use it)
Code:
//------------------------------------------------------------------------------
// Lighting Pass Shaders
//------------------------------------------------------------------------------
struct LightingVSOutput
{
float4 position_screen : POSITION;
float3 position_world : TEXCOORD0;
float3 normal_world : TEXCOORD1;
float3 light_position : TEXCOORD2;
float3 light_direction : TEXCOORD3;
float3 TexCoords : TEXCOORD4;
};
LightingVSOutput lighting_VS(
float4 position : POSITION,
float3 normal : NORMAL,
uniform float4x4 tshadow)
{
LightingVSOutput output = (LightingVSOutput)0;
//--------------------------------------------
//calculate ViewInv
//find an other way to do this!
tshadow[0].x = matMtl[0].x;
tshadow[0].y = matMtl[1].x;
tshadow[0].z = matMtl[2].x;
tshadow[0].w = matMtl[0].w;
tshadow[1].x = matMtl[0].y;
tshadow[1].y = matMtl[1].y;
tshadow[1].z = matMtl[2].y;
tshadow[1].w = matMtl[1].w;
tshadow[2].x = matMtl[0].z;
tshadow[2].y = matMtl[1].z;
tshadow[2].z = matMtl[2].z;
tshadow[2].w = matMtl[2].w;
tshadow[3].x = vecSkill5;
tshadow[3].y = vecSkill9;
tshadow[3].z = vecSkill13;
tshadow[3].w = matMtl[3].w;
//-------------------------------------------
output.position_screen = mul(position, matWorldViewProj);
output.position_world = mul(position, matWorld).xyz;
output.normal_world = mul(float4(normal, 0), matWorld).xyz;
// Work out the light position and direction in world space
output.light_position = float3(tshadow._41, tshadow._42, tshadow._43);
output.light_direction = float3(tshadow._31, tshadow._32, tshadow._33);
//colormap texcoords
output.TexCoords = mul(position, matWorldView).xyz;
return output;
}
struct LightingPSOutput
{
float4 color : COLOR;
};
LightingPSOutput lighting_PS(
LightingVSOutput input,
uniform float4x4 shadow_view_projection)
{
LightingPSOutput output = (LightingPSOutput)0;
// Renormalize
float3 normal_world = normalize(input.normal_world);
float3 light_direction = normalize(input.light_direction);
// Sum the contributions from all lights
float3 lit_color = float3(0, 0, 0);
// Light Shader:
float3 light_contrib;
float3 dir_to_light;
float dist_to_light;
float n_dot_l;
{
// Unnormalized light vector
dir_to_light = input.light_position - input.position_world;
dist_to_light = length(dir_to_light);
float atten_amount =
clamp((dist_to_light - light_atten_begin) /
(light_atten_end - light_atten_begin),
0.0, 1.0);
// Radial attenuation
dir_to_light = normalize(dir_to_light);
float2 cos_angle_atten = cos_light_angle_atten;
float cos_angle = dot(-dir_to_light, light_direction);
float angle_atten_amount =
clamp((cos_angle - cos_angle_atten.x) /
(cos_angle_atten.y - cos_angle_atten.x),
0.0, 1.0);
// Compose the light shader outputs
light_contrib = (1.0 - atten_amount) * (1.0 - angle_atten_amount) * vecLightColor[0];
n_dot_l = dot(normal_world, dir_to_light);
}
// Variance Shadow Mapping:
{
// Transform the surface into light space and project
// NB: Could be done in the vertex shader, but doing it here keeps the "light
// shader" abstraction and doesn't limit # of shadowed lights.
float4 surf_tex = mul(float4(input.position_world, 1.0), shadow_view_projection);
surf_tex = surf_tex / surf_tex.w;
// Rescale viewport to be [0,1] (texture coordinate space)
float2 shadow_tex = surf_tex.xy * float2(0.5, -0.5) + 0.5;
float4 moments;
// TODO: Emulate bilinear filtering on unsupporting hardware
moments = tex2D(light_shadow_map, shadow_tex);
// Rescale light distance and check if we're in shadow
float rescaled_dist_to_light = dist_to_light / light_atten_end;
rescaled_dist_to_light -= light_shadow_bias;
float lit_factor = (rescaled_dist_to_light <= moments.x);
// Variance shadow mapping
float E_x2 = moments.y;
float Ex_2 = moments.x * moments.x;
float variance = min(max(E_x2 - Ex_2, 0.0) + (light_vsm_epsilon), 1.0);
float m_d = (moments.x - rescaled_dist_to_light)*4000;
float p = variance / (variance + m_d * m_d);
// Adjust the light color based on the shadow attenuation
light_contrib *= max(lit_factor, p);
}
// Evaluate basic diffuse lighting
float self_shadow = clamp(n_dot_l * 2.0, 0.0, 1.0);
float3 direct_contrib = diffuse_color * n_dot_l;
lit_color += (light_contrib) * self_shadow * direct_contrib;
//output.color = float4(lit_color, 1.0)+ShadowAmbient;
//colormap
float2 tPos = input.TexCoords.xy/input.TexCoords.z;
tPos.y = 1 - (tPos.y*0.657 + 0.5);
tPos.x = tPos.x*0.499 + 0.5;
//output.color *= tex2D(color_map, tPos.xy)*ColorAmbient;
output.color = (float4(lit_color, 1.0)+ShadowAmbient)*(tex2D(color_map, tPos.xy)*ColorAmbient);
return output;
}
Is someone able to help me out here?