Shadow Mapping的基本思路就不进行记录了,可以直接看 :
https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping
这里记录一些值得注意的地方
1. FrameBuffer 绑定了 GL_DEPTH_ATTACHMENT 为 depthMap,渲染场景生成depthMap的时候,没有写入任何颜色,只是写入了depth value,那么 depthMap.r 记录了对应的深度值,可以直接用 float depthValue = texture(depthMap, TexCoords).r;
// configure depth map FBO // ----------------------- const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; unsigned int depthMapFBO; glGenFramebuffers(1, &depthMapFBO); // create depth texture unsigned int depthMap; glGenTextures(1, &depthMap); glBindTexture(GL_TEXTURE_2D, depthMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // attach depth texture as FBO's depth buffer glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, 0);
2. 只有传入gl_Position 才会去做透视除法.
When we output a clip-space vertex position to gl_Position in the vertex shader, OpenGL automatically does a perspective divide e.g. transform clip-space coordinates in the range [-w,w] to [-1,1] by dividing the x, y and z component by the vec- tor’s w component. As the clip-space FragPosLightSpace is not passed to the fragment shader viagl_Position we have to do this perspective divide ourselves:
float ShadowCalculation(vec4 fragPosLightSpace)
{
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
[...]
}
3. Shadow acne 的解决办法就是:
We can solve this issue with a small little hack called a shadow bias where we simply offset the depth of the surface (or the shadow map) by a small bias amount such that fragments are not incorrectly considered below the surface.
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
4. Peter panning
To mostly fix peter panning we cull front faces. Note that you need to enable GL_CULL_FACE first.
glCullFace(GL_FRONT);
This effectively solves the peter panning issues, but only for solid objects that actually have an inside without openings. In our scene for example, this works perfectly fine on the cubes, but won’t work on the floor as culling the front face completely removes the floor from the equation. The floor is a single plane and would thus completely be culled. If one wants to solve peter panning with this trick care has to be taken to only cull the front faces of objects where it makes sense.