0

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

Otto von Bisquick
  • 177
  • 1
  • 2
  • 17
  • That's good to know, but that doesn't fix it. – Otto von Bisquick Oct 19 '17 at 17:00
  • I added a render buffer and changed my fragment shader based on what you said, and now I'm getting GL_FRAMEBUFFER_COMPLETE, but I'm still getting an entirely red sphere. You can see my updated initialization function and shader above. – Otto von Bisquick Oct 20 '17 at 01:44

0 Answers0