OpenGL Odd Shadow Display Behavior

I am working on a 3D game in C ++ and OpenGL 3.2 with SFML. I tried my best to implement point-by-point rendering of shadows. What I have done so far seems to be consistent with what I learned and the examples I saw, but still there are no shadows.

What I did was write a simplified list of all the code that I use, in the order in which I use it, but not as the complete source code, but only the corresponding code (because my project is divided into several classes):

Omnidirectional shadow mapping C++ - Initialization -- Use shadow pass shader program -- Generate + bind the shadow frame buffer glGenFramebuffers(1, &shadowFrameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, shadowFrameBuffer); -- Generate a texture glGenTextures(1, &shadowMap); -- Bind texture as cubemap glBindTexture(GL_TEXTURE_CUBE_MAP); -- Set texture parameters glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -- Generate empty 1024 x 1024 for every face of the cube for (int face = 0; face < 6; face++) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT32F , 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); -- Attach the cubemap to the framebuffer glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowMap, 0); -- Only draw depth to framebuffer glDrawBuffer(GL_NONE); - Every frame -- Clear screen glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -- Render shadow map --- Bind shadow frame buffer glBindFramebuffer(GL_FRAMEBUFFER, shadowFrameBuffer); --- Set the viewport to the size of the shadow map glViewport(0, 0, 1024, 1024); -- Cull front faces glCullFace(GL_FRONT); -- Use shadow mapping program --- Define projection matrix for rendering each face glm::mat4 depthProjectionMatrix = glm::perspective(90.0f, 1.0f, 1.0f, 10.0f); --- Define view matrices for all six faces std::vector<glm::mat4> depthViewMatrices; depthViewMatrices.push_back(glm::lookAt(lightInvDir, glm::vec3(1,0,0), glm::vec3(0,-1,0) )); // +X depthViewMatrices.push_back(glm::lookAt(lightInvDir, glm::vec3(-1,0,0), glm::vec3(0,1,0) )); // -X depthViewMatrices.push_back(glm::lookAt(lightInvDir, glm::vec3(0,1,0), glm::vec3(0,0,1) )); // +Y depthViewMatrices.push_back(glm::lookAt(lightInvDir, glm::vec3(0,-1,0), glm::vec3(0,0,-1) )); // -Y depthViewMatrices.push_back(glm::lookAt(lightInvDir, glm::vec3(0,0,1), glm::vec3(0,-1,0) )); // +Z depthViewMatrices.push_back(glm::lookAt(lightInvDir, glm::vec3(0,0,-1), glm::vec3(0,1,0) )); // -Z --- For every object in the scene ---- Bind the VBO of the object ---- Define the model matrix for the object based on its position and orientation ---- For all six sides of the cube ----- Set the correct side to render to glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, shadowMap, 0); ----- Clear depth buffer glClear(GL_DEPTH_BUFFER_BIT); ----- Send model, view and projection matrices to shadow mapping shader glUniformMatrix4fv(glGetUniformLocation(shadowMapper, "lightModelMatrix"), 1, GL_FALSE, glm::value_ptr(depthModelMatrix)); glUniformMatrix4fv(glGetUniformLocation(shadowMapper, "lightViewMatrix"), 1, GL_FALSE, glm::value_ptr(depthViewMatrices[i])); glUniformMatrix4fv(glGetUniformLocation(shadowMapper, "lightProjectionMatrix"), 1, GL_FALSE, glm::value_ptr(depthProjectionMatrix)); ----- Draw the object glDrawElements(....); - END SHADOW MAP DRAW -- Cull back faces glCullFace(GL_BACK); -- Use standard shader program -- Bind default framebuffer glBindFramebuffer(GL_FRAMEBUFFER, 0); -- Activate cubemap texture glActiveTexture(GL_TEXTURE1); -- Bind cubemap texture glBindTexture(GL_TEXTURE_CUBE_MAP, shadowMap); -- Tell shader to use first texture glUniform1i(glGetUniformLocation(currentProgram->id, "shadowmap"), 1); -- Send standard MVPs and draw objects glDrawElements(...); - END C++ ================================= GLSL shadowpass vertex shader source #version 150 in vec3 position; out vec3 worldPosition; uniform mat4 lightModelMatrix; uniform mat4 lightViewMatrix; uniform mat4 lightProjectionMatrix; void main() { gl_Position = lightProjectionMatrix * lightViewMatrix * lightModelMatrix * vec4(position, 1.0); worldPosition = (lightModelMatrix * vec4(position, 1.0)).xyz; // Send world position of vertex to fragment shader } shadowpass fragment shader source #version 150 in vec3 worldPosition; // Vertex position in world space out float distance; // Distance from vertex position to light position vec3 lightWorldPosition = vec3(0.0, 0.0, 0.0); // Light position in world space void main() { distance = length(worldPosition - lightWorldPosition); // Distance from point to light // Distance will be written to the cubemap } standard vertex shader source #version 150 in vec3 position; in vec3 normal; in vec2 texcoord; uniform mat4 modelMatrix; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; out vec3 fragnormal; out vec3 fragnormaldirection; out vec2 fragtexcoord; out vec4 fragposition; out vec4 fragshadowcoord; void main() { fragposition = vec4(position, 1.0); // Position of vertex in object space fragtexcoord = texcoord; fragnormaldirection = normalize(modelInverseTranspose * normal); fragnormal = normalize(normal); gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0); } standard fragment shader source #version 150 out vec4 outColour; in vec3 fragnormaldirection; in vec2 fragtexcoord; in vec3 fragnormal; in vec4 fragposition; uniform mat4 modelMatrix; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; uniform mat4 viewMatrixInversed; uniform sampler2D tex; uniform samplerCube shadowmap; void main() { vec3 lightpos = vec3(0.0, 0.0, 0.0); vec3 pointToLight = (fragposition * modelMatrix).xyz - lightpos; // Get vector between this point and the light float dist = texture(shadowmap, pointToLight).x; // Get distance written in texture float shadowfactor = 1.0; if (length(pointToLight) > dist) // Is it occluded? shadowfactor = 0.5; outColour = texture(tex, fragtexcoord) * shadowfactor; } 

Here is an image of what my code is doing now:

Broken shadow mapping

This is a strange effect, but it seems to be close to what I had in mind. It seems that any surface exposed to light at 0, 0, 0 has an unpainted circle in the center of it, and everything else is not indicated.

+8
c ++ opengl shadow-mapping
source share
1 answer

One very useful way to debug shadow cards really has the ability to display the contents of shadow cards as squares on the screen. 6 quads in case of shadow cards of a cube. which can be implemented as a debugging Easter egg, where you can display the full texture on the whole screen and "go to the next face" so that you can shift 6 faces using a different keyboard shortcut.

Then one of the most important things in cubic shadow maps is the range of depths. Spotlight does not have an infinite range, so usually you want to scale the depth store according to the range of illumination.

You can use the texture of brightness (or the red channel) with a floating point while preserving the depth of the world (spherical, which means the true length (from the ray to the intersection) using a little calculation in the pixel shader) Or you can use the linear depth (the same view, which stored in the classic ZBuffer, which is the coordinate depth of the normalized device. This is the depth after the projection matrix. In this case, to restore the world position once when lighting the shader (next pass), problems It is to be divided by w after you multiply by the projection of the reverse lookup cube camera.

The key to debugging shadow cards is all in shader scripting. Start by using colors to visualize the depth stored on your shadow maps, as perceived by the pixels of your world. This was the only way to help create shadow maps with fixed points in my company engine. You can make a color code using a combination of mix and clip, like blue, from 0 to 0.3, red from 0.3 to 0.6, green from 0.6 to 1. If you have remote storage in the world, this easier, but still interesting to draw it through color codes. just use the same function, but divide the distance by the expected world range.

Using this vizu scheme, you can immediately see the shaded area, because they all have the same color (since the “beam” was intercepted by a closer surface). As soon as you get to this point; everything else will go smoothly.

good luck :)

+4
source share

All Articles