I'm trying to make an omnidirectional shadow map (from a point light) in OpenGL. To avoid passing tons of matrices around and having to move in between world space and light space with a depth map, I thought I might be able to use a color texture and just encode the distance (in world space) into it. I've found a couple of other stackoverflow responses saying that this is how it's usually done nowadays, but none actually detailing the process.
For the most part, I am following this tutorial: http://ogldev.atspace.co.uk/www/tutorial43/tutorial43.html
This is my initialization function:
glGenFramebuffers(1, &depthBuffer);
glGenTextures(1, &shadowMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, shadowMap);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
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);
for (uint i = 0 ; i < 6 ; i++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_R32F, 1024, 1024, 0, GL_RED, GL_FLOAT, NULL);
}
glBindFramebuffer(GL_FRAMEBUFFER, depthBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X, shadowMap, 0);
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 1024, 1024);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffer);
And this is my first render pass:
struct CameraDirection {
GLenum CubemapFace;
glm::vec3 Target;
glm::vec3 up;
};
CameraDirection gCameraDirections[6] =
{
{ GL_TEXTURE_CUBE_MAP_POSITIVE_X, glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f) },
{ GL_TEXTURE_CUBE_MAP_NEGATIVE_X, glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f) },
{ GL_TEXTURE_CUBE_MAP_POSITIVE_Y, glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f) },
{ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f) },
{ GL_TEXTURE_CUBE_MAP_POSITIVE_Z, glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f) },
{ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 1.0f, 0.0f) }
};
shadowShader->Enable();
glCullFace(GL_FRONT);
glBindFramebuffer(GL_FRAMEBUFFER, depthBuffer);
glViewport(0,0,1024,1024);
glm::mat4 oldView = view;
glm::mat4 oldProj = projection;
glm::vec3 offset = *Object::globalOffset;
offset *= -1;
projection = glm::perspective(45.0f, 1.0f, .1f, 1000000.0f);
glClearColor(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
for (auto& gCameraDirection : gCameraDirections) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gCameraDirection.CubemapFace, shadowMap, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
view = glm::lookAt(offset, offset + gCameraDirection.Target, gCameraDirection.up);
renderScene();
}
view = oldView;
projection = oldProj;
glViewport(0, 0, windowWidth, windowHeight);
And my Shadow Shaders:
#version 330
layout (location = 0) in vec3 positionM;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelMatrix;
out vec3 worldPos;
void main(void) {
gl_Position = modelViewProjectionMatrix * vec4(positionM, 1.0);
worldPos = (modelMatrix * vec4(positionM, 1.0)).xyz;
}
Fragment:
#version 330 core
in vec3 worldPos;
uniform vec3 lightW3;
layout (location = 0) out float fragDepth;
void main(void) {
fragDepth = length(worldPos - lightW3);
}
In my normal rendering fragment shader, I sample the cubemap:
...
uniform samplerCube gShadowMap;
void main(void) {
float distance = length(lightW3 - positionW);
if(texture(gShadowMap, positionW - lightW3).x - distance >= 0.01 ) {
frag_color.rgba = vec4(1.0, 0.0, 0.0, 1.0);
} else {
frag_color.rgba = vec4(0.0, 0.0, 0.0, 1.0);
}
}
I'm rendering a sphere right now, so I'm expecting the side of the sphere facing the light to be red, and the side facing away to be black, but the entire sphere is red, which leads me to believe that my shadow pass isn't actually drawing to the texture properly, and leaving everything as the default FLT_MAX. What am I doing wrong?
Edit: Added render buffer based on @Rabbid76 's suggestion