I am trying to implement shadow mapping. I am able to render a depth map onto a framebuffer texture. and send it to the shader, as well as the lights orthographic matrix to test if a fragment is in the shadow. But the results are not correct. Instead of creating shadows all fragments are just painted solibly if they are "inside" the light matrix it seems like.
As you can see on the bottom left the generated depth texture is correct.
I've tried many tutorials but none mention any problems like this. It might because the light direction and orthographic projection is wrong, but I can't seem to find a working light direction that produces any shadows.
This is how I generate the frame buffer and texture(frameBuffer and framebufferTexture are instantiated in the class header):
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
//texture buffer for frame buffer
glGenTextures(1, &framebufferTexture);
glBindTexture(GL_TEXTURE_2D, framebufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 896, 504, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
//Set framebufferTexture as our color attachment #0
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, framebufferTexture, 0);
glDrawBuffer(GL_NONE);
This is how I create the depth texture
glCullFace(GL_BACK);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer);
//Setup depth texture framebuffer rendering
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(2.0f, 2.0f);
glViewport(0, 0, 896, 504);
glClear(GL_DEPTH_BUFFER_BIT);
glUniform1i(glGetUniformLocation(shaderProgram, "fragmentTypeTarget"), -1);
glm::vec3 lightInvDir = glm::vec3(5, 17, 1);
//Calculate the matrix for drawing the framebuffer
//Make it an orthographic that takes the whole screen
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-17, 17, -17, 17, 0, 37);
glm::mat4 depthViewMatrix = glm::lookAt(
lightInvDir,
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0));
glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix;
//Render the objects
for (int i = 0; i < objectPool.size(); i++) {
objectPool[i]->draw(lightSpaceMatrix);
}
This is how I send the shadow map matrix for drawing the shadows:
glm::mat4 Model = glm::translate(glm::mat4(1.0), glm::vec3(x, y, z));
glm::vec3 lightInvDir = glm::vec3(5, 17, 1);
//Calculate the matrix for drawing the framebuffer
//Make it an orthographic that takes the whole screen
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-17, 17, -17, 17, 0, 37);
glm::mat4 depthViewMatrix = glm::lookAt(
lightInvDir,
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0));
glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix * Model;
glUniformMatrix4fv(glGetUniformLocation(shader, "shadowMatrix"), 1, GL_FALSE, &lightSpaceMatrix[0][0]);
My fragment shader:
#version 330 core
layout(location = 0) out vec4 outColor;
in vec2 UV;
in vec4 ShadowCoord;
uniform sampler2D textureSampler;
uniform sampler2D shadowMap;
uniform int fragmentTypeTarget;
// 'colorImage' is a sampler2D with the depth image
// read from the current depth buffer bound to it.
float LinearizeDepth(in vec2 uv, sampler2D t)
{
float zNear = 1.0;
float zFar = 5.0;
float depth = texture2D(t, uv).x;
return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
}
void main(){
if(fragmentTypeTarget == -1){//draw frame buffer
}else if(fragmentTypeTarget == 0){//Draw everything normal
vec4 tex = texture2D(textureSampler, UV);
outColor = vec4(tex.rgb, tex.a);
}else if(fragmentTypeTarget == 1){//Draw depth texture
//vec2 res = gl_FragCoord.xy / vec2(1024, 1024);
outColor = texture(textureSampler, UV);
float c = LinearizeDepth(UV, textureSampler);
outColor = vec4(c, c, c, 1.0);
}else if(fragmentTypeTarget == 2){//Draw everything but apply the shadow
float visibility = 1.0;
float bias = 0.0039;
if(texture(shadowMap, ShadowCoord.xy).z < ShadowCoord.z){
visibility = 0.3;
}
vec4 tex = texture2D(textureSampler, UV);
outColor = visibility * vec4(tex.rgb, tex.a);
}
}
My vertex shader:
#version 330 core
in vec2 UVsIn;
out vec2 UV;
in vec3 position;
in vec3 vertexColor;
out vec3 fragmentColor;
uniform mat4 mvp;
uniform mat4 shadowMatrix;
out vec4 ShadowCoord;
void main(){
gl_Position = mvp * vec4(position, 1.0);
fragmentColor = vertexColor;
UV = UVsIn;
ShadowCoord = shadowMatrix * vec4(position, 1.0);
}
The result should look more like this:
EDIT:
I got it to work I think. When generating the framebuffer texture I used the wrong compare function. It should be: "GL_COMPARE_R_TO_TEXTURE" instead of "GL_COMPARE_REF_TO_TEXTURE".
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
The openGl documentation says: GL_COMPARE_R_TO_TEXTURE: Specifies that the interpolated and clamped r texture coordinate should be compared to the value in the currently bound depth texture
Which is exactly what I want.
I also found out that texture coordinates are in (s, t, r) instead of (x, y, z).
since I want to compare depths of the matrices and texture I need to use r instead of z. so the fragment shader should have been written like:
float visibility = 1.0;
vec2 mapUV = ShadowCoord.xy * 0.5 + 0.5;
float depthFrag = ShadowCoord.z * 0.5 + 0.5;
float depthMap = texture(shadowMap, mapUV).r;//r instead of z since its (s, t, r)
if(depthMap < depthFrag){
visibility = 0.3;
}
vec4 tex = texture2D(textureSampler, UV);
outColor = visibility * vec4(tex.rgb, tex.a);
" * 0.5 + 0.5" was also needed to be added from Rabbid76 response.