I'm trying to render my depth map, for now I've rendered it onto the objects in the scene to get a overview of what the result I'm getting is. From what I've learned, the black values are objects that are close to the light, and white is further away. Please correct me if I've gotten it wrong. This is the result I'm getting:Shadow map rendered onto a cube
With this result, I speculate that I've created the framebuffer in the wrong way. this is how I generate it:
void createFrameBuffer()
{
glGenFramebuffers(1, &frameBuffer);
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);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, DepthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
We have followed the Learn OpenGL - Shadow Mapping tutorial, and our shaders looks almost identical to his. So there shouldn't be any problem there. I think I've misunderstood something in the CPU part of shadow mapping, and not the GPU.This is how I draw everything, set up matrices and use programs.
float orthoValue = 20.0f;
glm::mat4 lightProjection = glm::ortho(-orthoValue,
orthoValue, -orthoValue, orthoValue, NEARPLANE, FARPLANE);
glm::mat4 lightView = glm::lookAt(lightPos, glm::vec3(0.0f),
glm::vec3(0.0, 1.0f, 0.0));
glm::mat4 lightSpaceMatrix = lightProjection * lightView;
//lightSpaceMatrix[3] = glm::vec4(lightPos, 1.0f);
if (shadows == true) {
glUseProgram(sShaderProgram);
glBindVertexArray(mesh.VAO);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glUniformMatrix4fv(glGetUniformLocation(sShaderProgram, "lightSpaceMatrix"),
1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
glUniformMatrix4fv(glGetUniformLocation(sShaderProgram, "modelMatrix"),
1, GL_FALSE, glm::value_ptr(mesh.modelMatrix));
glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindVertexArray(0);
setViewPort();
}
I'm really grateful for all of the tips and help in advance. If I've left out crucial information, I'll add whatever's missing.
More code of the rendering part edit, also edited the way we draw:
This is the main loop
glClearColor(0.0, 0.0, 0.5, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
//Keyboard input
keyPressed();
//Mouse movement
MousePointer();
lightProjection = glm::ortho(-orthoValue,
orthoValue, -orthoValue, orthoValue, NEARPLANE, FARPLANE);
glm::lookAt(lightPos, glm::vec3(0.0f),
glm::vec3(0.0, 1.0, 0.0));
lightSpaceMatrix = lightProjection * lightView;
glUseProgram(sShaderProgram);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glClear(GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, DepthMap);
GLint samplerLoc = glGetUniformLocation(sShaderProgram, "DepthMap");
glUniform1i(samplerLoc, 0);
glUniformMatrix4fv(glGetUniformLocation(sShaderProgram, "lightSpaceMatrix"),
1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
for (int i = 0; i < objmesh.size(); i++) {
RenderShadows(*objmesh[i]);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
setViewPort();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glDisable(GL_DEPTH_TEST);
for (int i = 0; i < objmesh.size(); i++){
RenderVertices(gShaderProgram, *objmesh[i], true);
}
}
Here we have the RenderShadows function that uses the shadow glsl program:
void RenderShadows(OBJMeshes mesh){
glUniformMatrix4fv(glGetUniformLocation(sShaderProgram, "modelMatrix"),
1, GL_FALSE, glm::value_ptr(mesh.modelMatrix));
glBindVertexArray(mesh.VAO);
glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size());
glBindVertexArray(0);
}
And finally the normal render function that renders the geometry:
void RenderVertices(GLuint shaderProgram, OBJMeshes mesh, bool shadows) {
GLuint CPUValuesID = glGetUniformLocation(gUbo, "MVP");
glBindBuffer(GL_UNIFORM_BUFFER, gUbo);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(CPUMatricies), &globalCPU);
glBindBuffer(GL_UNIFORM_BUFFER, mtlBuff);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(mtlValues), &mtl);
glUniformMatrix4fv(CPUValuesID, 1, GL_FALSE, &globalCPU.MVP[0][0]);
glUseProgram(shaderProgram);
glBindVertexArray(mesh.VAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mesh.texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, DepthMap);
GLint samplerLoc = glGetUniformLocation(shaderProgram, "DepthMap");
glUniform1i(samplerLoc, 1);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "modelMatrix"),
1, GL_FALSE, glm::value_ptr(mesh.modelMatrix));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "lightSpaceMatrix"),
1, GL_FALSE, glm::value_ptr(lightSpaceMatrix));
glUniform3f(glGetUniformLocation(shaderProgram, "lightPos"), lightPos.x, lightPos.y, lightPos.z);
glDrawArrays(GL_TRIANGLES, 0, mesh.vertices.size());
glBindVertexArray(0);
}
If you want to render your depth buffer to a texture you have to bind a texture with GL_DEPTH_COMPONENT
format to the
render buffer of your frame buffer buffer. What you did was to bind a texture to color plan 0 of your frame buffer, because you used GL_COLOR_ATTACHMENT0
to bind the texture in your code.
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ColorMap0, 0 );
What you have to do is to create a render buffer and bind it to your frame buffer.
GLuint frameBuffer;
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
GLuint renderbuffer;
glGenRenderbuffers( 1, &renderbuffer );
glBindRenderbuffer( GL_RENDERBUFFER, renderbuffer );
Then you have to bind your depth texture to the frame buffer using GL_DEPTH_ATTACHMENT
:
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, DepthMap, 0 );
Note that you can bind separate textures for the deep buffer and all color planes to the frame buffer.
After you have done this correctly you have to draw your scene and fill your buffers and/or textures.
// enable the depth test
glEnable( GL_DEPTH_TEST );
// bind frame buffer and clear the frame buffer and the depth buffer
glBindFramebuffer( GL_FRAMEBUFFER, frameBuffer );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)`
// draw the scene
// ...
// unbind frame buffer
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
// clear the drawing buffer and the depth buffer
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
After your frame buffer has been unbind, you can use its textures as input for your shadow pass.
To bind the texture to the shader, you have to bind the texture to a texture unit and assign the index of the texture unit to the uniform sampler of the shader.
Bind the texture to a texture unit:
GLuint DepthMap;
int textureUnit = 1;
glActiveTexture( GL_TEXTURE0 + textureUnit );
glBindTexture( GL_TEXTURE_2D, DepthMap );
Use the program and assign the index of the texture unit to the uniform sampler:
GLuint depthProg = ...;
glUseProgram( depthProg );
GLint depthSamplerLocation = glGetUniformLocation( u_depthAttachment );
glUniform1i( depthSamplerLocation, textureUnit );
There are some more issues in your code:
In the main loop you clear the frame buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
before you call RenderShadows
, but inside the function you bind a frame buffer glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
, so the clearing is useless.
In RenderShadows
you try to bind the DepthMap
texture to a texture sampler,
but the DepthMap
texture is the target texture of the currently bound frame buffer. A texture can't be source and destination at the same time, this would cause undefined behavior.
In RenderVertices
you have to assign the index of the texture unit to the
texture sampler not the texture object:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, DepthMap);
GLint samplerLoc = glGetUniformLocation(shaderProgram, "DepthMap");
// glUniform1i(samplerLoc, DepthMap); <- this is wrong
glUniform1i(samplerLoc, 1); // 1 because the texture is bound to GL_TEXTURE1