Hello,
I've been trying to implement variance shadow map with a directional light for my terrain viewer (OpenGL + CgFX), however I'm getting the following result:
The terrain is 128x128 with the origin at the center, so it ranges from -64 to 64. Traditional depth-based shadow map works fine. My VSM implementation was also working when I had a point light and perspective projection for it.
I have checked the depth output of the shadow map generation pass and the render pass, and the texture coordinates transformed by the texture matrix, they all look fine. The artifacts only appear in the values fetched from the shadow map texture.
I set the framebuffer as follows:
Light projection matrix:
Texture matrix:
Shadow map generation setup:
Shadow map generation shader (snippets):
Terrain rendering shader:
Tested on GeForce 8800 GTS. Any help is appreciated. Thanks!
I've been trying to implement variance shadow map with a directional light for my terrain viewer (OpenGL + CgFX), however I'm getting the following result:
The terrain is 128x128 with the origin at the center, so it ranges from -64 to 64. Traditional depth-based shadow map works fine. My VSM implementation was also working when I had a point light and perspective projection for it.
I have checked the depth output of the shadow map generation pass and the render pass, and the texture coordinates transformed by the texture matrix, they all look fine. The artifacts only appear in the values fetched from the shadow map texture.
I set the framebuffer as follows:
Code:
glGenTextures(1, &texShadowMap);
glBindTexture(GL_TEXTURE_2D, texShadowMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, shadowMapSize, shadowMapSize, 0, GL_RGBA, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glGenFramebuffersEXT(1, &fboShadowMap);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboShadowMap);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texShadowMap, 0);
Light projection matrix:
Code:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-65, 65, -65, 65, -200.0, 200.0);
Texture matrix:
Code:
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glTranslatef(0.5f, 0.5f, 0.5f);
glScalef(0.5f, 0.5f, 0.5f);
glMultMatrixf(lightProjection);
glMultMatrixf(lightModelView);
Shadow map generation setup:
Code:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboShadowMap);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, shadowMapSize, shadowMapSize);
land->Draw();
glPopAttrib();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
Shadow map generation shader (snippets):
Code:
//vertex
float lightSpaceZ = mul(lightModelView, position).z;
float nearClipPlane = 200;
float farClipPlane = -200;
oDepth = (lightSpaceZ - nearClipPlane) / (farClipPlane - nearClipPlane);
//fragment
float dx = ddx(depth);
float dy = ddy(depth);
return float4(depth, depth * depth + 0.25*(dx*dx + dy*dy), 0.0f, 1.0f);
Terrain rendering shader:
Code:
//vertex
float lightSpaceZ = mul(lightModelView, position).z;
float nearClipPlane = 200;
float farClipPlane = -200;
OUT.lightDepth = (lightSpaceZ - nearClipPlane) / (farClipPlane - nearClipPlane);
OUT.texCoordProj = mul(textureMatrix, position);
//fragment
float chebyshev_upper_bound(float2 moments, float t)
{
float p = (t<=moments.x);
float variance = moments.y - (moments.x*moments.x);
variance = max(variance, 0.00001);
float d = t - moments.x;
float p_max = variance/(variance + d*d);
return max(p, p_max);
}
float2 moments = tex2Dproj(shadowMap, IN.texCoordProj).xy;
float shadowCoeff = chebyshev_upper_bound(moments, IN.lightDepth);
Tested on GeForce 8800 GTS. Any help is appreciated. Thanks!