Reputation: 13489
I use deferred rendering and I store a fragment position in the camera view space. When I perform a shadow calculation I need to transform a camera view space to the shadow map space. I build a shadow matrix this way:
shadowMatrix = shadowBiasMatrix * lightProjectionMatrix * lightViewMatrix * inverseCameraViewMatrix;
shadowBiasMatrix shifts values from [-1,1] to [0,1] range. lightProjectionMatrix that's orthographic projection matrix for a directional light. lightViewMatrix looks at the frustum center and contains a light direction. inverseCameraViewMatrix transforms a fragment position from a camera view space to the world space.
I wonder if it is correct to multiply the inverse camera view matrix with the other matrices ? Maybe I should use the inverse camera view matrix separately ?
First scenario:
vec4 shadowCoord = shadowMatrix * vec4(cameraViewSpacePosition, 1.0);
Second scenario, a inverse camera view matrix is use separately:
vec4 worldSpacePosition = inverseCameraViewSpaceMatrix * vec4(cameraViewSpacePosition, 1.0);
vec4 shadowCoord = shadowMatrix * worldSpacePosition;
Upvotes: 2
Views: 2444
Reputation: 81
Precomputing the shadow matrix in the described way is the correct approach and should work as expected.
Because of the associativity of matrix multiplication the results of the three scenarios should be identical (ignoring floating point precision) and are thus interchangeable. But because these calculations are done in the fragment shader, it is best to premultiply the matrixes in the main program to do as few operations as possible per fragment.
I'm also writing a deferred renderer currently and calculate my matrices in the same way without any problems.
// precomputed: lightspace_mat = light_projection * light_view * inverse_cam_view
// calculate position in clip-space of the lightsource
vec4 lightspace_pos = lightspace_mat * vec4(viewspace_pos, 1.0);
// perspective divide
lightspace_pos/=lightspace_pos.w;
// move range from [-1.0, 1.0] to [0.0, 1.0]
lightspace_pos = lightspace_pos * vec4(0.5) + vec4(0.5);
// sample shadowmap
float shadowmap_depth = texture(shadowmap, lightspace_pos.xy).r;
float fragment_depth = lightspace_pos.z;
I also found this tutorial using a simillar approach, that could be helpfull: http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx
float readShadowMap(vec3 eyeDir) { mat4 cameraViewToWorldMatrix = inverse(worldToCameraViewMatrix); mat4 cameraViewToProjectedLightSpace = lightViewToProjectionMatrix * worldToLightViewMatrix * cameraViewToWorldMatrix; vec4 projectedEyeDir = cameraViewToProjectedLightSpace * vec4(eyeDir,1); projectedEyeDir = projectedEyeDir/projectedEyeDir.w; vec2 textureCoordinates = projectedEyeDir.xy * vec2(0.5,0.5) + vec2(0.5,0.5); const float bias = 0.0001; float depthValue = texture2D( tShadowMap, textureCoordinates ) - bias; return projectedEyeDir.z * 0.5 + 0.5 < depthValue; }
The eyeDir that comes in input is in View Space. To find the pixel in the shadow map we need to take that point and covert it into the light's clip space, which means going from Camera View Space into World Space, then into Light View Space, than into Light Projection Space/Clip space. All these transformations are done using matrices; if you are not familiar with space changes you may want to read my article about spaces and transformations.
Once we are in the right space we calculate the texture coordinates and we are finally ready to read from the shadow map. Bias is a small offset that we apply to the values in the map to avoid that because of rounding errors a point ends up shading itself! So we shift all the map back a bit so that all the values in the map are slightly smaller than they should.
Upvotes: 4