Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 3 123 LastLast
Results 1 to 10 of 22

Thread: Omnidirectional Shadow Maps

  1. #1
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129

    Omnidirectional Shadow Maps

    I am attempting to create omnidirectional point lights that cast shadows using a depth cube map. However, when sampling the cube map, I seem to get a value of 1 in every case (making everything look black).

    Here is how I generate the depth cube map and associated FBO:

    Code :
    glGenTextures(1, &m_cubeMapID);
     
        // Bind as cube map and set default settings
        glBindTexture(GL_TEXTURE_CUBE_MAP, m_cubeMapID);
     
     
        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);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
        //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
        //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
     
        // Generate textures for faces
        for(int f = 0; f < 6; f++)
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, 0, GL_DEPTH_COMPONENT, m_resolution, m_resolution, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
     
     
        // Generate mipmaps for the color texture
        //glGenerateMipmap(GL_TEXTURE_2D);
     
     
        GL_ERROR_CHECK();
     
     
        // ------------------------------ FBO ------------------------------
     
     
        glGenFramebuffers(1, &m_fboID);
        glBindFramebuffer(GL_FRAMEBUFFER, m_fboID);
     
     
        // Not using color buffer
        glDrawBuffer(GL_NONE);
        glReadBuffer(GL_NONE);
     
     
        // Attach at least on part of cube map so completeness check succeeds. Attach and detach sides later when rendering
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, m_cubeMapID, 0);
     
        GL_ERROR_CHECK();
     
     
    #ifdef DEBUG
        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            std::cerr << "Could not created FBO!" << std::endl;
    #endif
     
     
        // Unbind FBO, revert to main framebuffer
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
     
        // Unbind texture
        glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
     
     
        GL_ERROR_CHECK();

    I then render to it like this:

    Code :
    // For each face, render the scene    
        glBindFramebuffer(GL_FRAMEBUFFER, m_fboID);
     
     
        // Set up viewport for the map side
        glViewport(0, 0, m_resolution, m_resolution);
     
     
        // Set projection to 90 degrees
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(90.0f, 1.0f, 0.01f, distance);
        glMatrixMode(GL_MODELVIEW);
     
     
        glColorMask(false, false, false, false);
     
     
        // Side +X
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, m_cubeMapID, 0);
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluLookAt(position.x, position.y, position.z, position.x + 1.0f, position.y, position.z, 0.0f, 1.0f, 0.0f);
        pScene->ExtractFrustum();
        pScene->Render(distance);
     
     
        // Side -X
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, m_cubeMapID, 0);
     
     
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluLookAt(position.x, position.y, position.z, position.x - 1.0f, position.y, position.z, 0.0f, 1.0f, 0.0f);
        pScene->ExtractFrustum();
        pScene->Render(distance);
     
     
        // Side +Y
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, m_cubeMapID, 0);
     
     
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluLookAt(position.x, position.y, position.z, position.x, position.y + 1.0f, position.z, 0.0f, 1.0f, 0.0f);
        pScene->ExtractFrustum();
        pScene->Render(distance);
     
     
        // Side -Y
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, m_cubeMapID, 0);
     
     
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluLookAt(position.x, position.y, position.z, position.x, position.y - 1.0f, position.z, 0.0f, 1.0f, 0.0f);
        pScene->ExtractFrustum();
        pScene->Render(distance);
     
     
        // Side +Z
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, m_cubeMapID, 0);
     
     
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluLookAt(position.x, position.y, position.z, position.x, position.y, position.z + 1.0f, 0.0f, 1.0f, 0.0f);
        pScene->ExtractFrustum();
        pScene->Render(distance);
     
     
        // Side -Z
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, m_cubeMapID, 0);
     
     
        glClear(GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        gluLookAt(position.x, position.y, position.z, position.x, position.y, position.z - 1.0f, 0.0f, 1.0f, 0.0f);
        pScene->ExtractFrustum();
        pScene->Render(distance);
     
     
        glColorMask(true, true, true, true);
     
     
        glFlush();
     
     
        // Unbind the FBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
     
        GL_ERROR_CHECK();

    Rendering to the cube map worked when using color textures, but I am not sure that it is rendering properly when using the textures as depth attachments.

    Here is the shader I use for rendering the shadows:

    Vertex:

    Code :
    uniform vec3 light_position;
     
    // Used for shadow lookup
    varying vec4 shadowDir;
     
     
    void main()
    {
        shadowDir = gl_Vertex * gl_ModelViewMatrix - vec4(light_position, 1.0);
     
     
        gl_Position = ftransform();
     
     
        gl_FrontColor = gl_Color;
    }

    Fragment:

    Code :
    uniform samplerCube shadowMap;
     
    varying vec4 shadowDir;
     
     
    void main()
    {
        float frag_depth = length(shadowDir.xyz);
     
     
        vec3 norm_shadowDir = normalize(shadowDir).xyz;
     
     
        float shadow_map_depth = textureCube(shadowMap, norm_shadowDir).r;
     
     
        float light = 0.0;
     
     
        if(shadow_map_depth > frag_depth + 0.0005)
            light = 1.0;
     
        gl_FragColor = gl_Color;
        gl_FragColor.rgb *= light;
    }

    What am I doing wrong here? Thanks for any help you can offer!

  2. #2
    Senior Member OpenGL Pro BionicBytes's Avatar
    Join Date
    Mar 2009
    Location
    UK, London
    Posts
    1,170
    Are you sure you have set near and far correctly?
    // Set projection to 90 degrees
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.0f, 1.0f, 0.01f, distance);

  3. #3
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129
    I am pretty sure they are right. distance is 2000.0f. It renders fine when I use normal color textures.

  4. #4
    Senior Member OpenGL Pro BionicBytes's Avatar
    Join Date
    Mar 2009
    Location
    UK, London
    Posts
    1,170
    Have you read back the depth buffers/textures to check they contain something valid?

  5. #5
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129
    How would I go about doing that?

  6. #6
    Senior Member OpenGL Pro sqrt[-1]'s Avatar
    Join Date
    Jun 2002
    Location
    Australia
    Posts
    1,000
    Perhaps grab an XML frame with http://code.google.com/p/glintercept/ ?

  7. #7
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129
    I figured out how to render it as a normal texture. However, it is blank. If I set glClearDepth to different values the color of the grey scale depth image I render changes, but there is no visible geometry. What am I doing wrong?

  8. #8
    Senior Member OpenGL Pro BionicBytes's Avatar
    Join Date
    Mar 2009
    Location
    UK, London
    Posts
    1,170
    You need to linearise the data in the depth texture. The depth buffer/texture stores most values at one end of the 0.0 -> 1.0 range so they are all very close together. That's why the image appears to be 1 shade as the difference between them is very small.
    Here's how I do mine:
    Code :
    /*
    Render the scene depth texture to framebuffer so we can 'see' the depth'
    */
    varying vec4 vertexcolor;
    uniform vec2 depthrange;  //x=near, y=far
    uniform sampler2D depthSampler;
    float LinearizeDepth(vec2 uv)
    {
      float n = depthrange.x; // camera z near
      float f = depthrange.y; // camera z far
      float z = texture2D(depthSampler, uv).x;
      return (2.0 * n) / (f + n - z * (f - n));
    }
    void main()
    {
      float d = LinearizeDepth(gl_TexCoord[0].xy);
      float one_minus_d = 1.0 - d;
      gl_FragColor = vec4(one_minus_d, one_minus_d, one_minus_d, 1.0);
    }

  9. #9
    Junior Member Regular Contributor
    Join Date
    Mar 2012
    Posts
    129
    Thanks for your help so far, but unfortunately I still cannot see anything. I had to modify your shader to work with cube maps, but that only involved changing sampler2D to samplerCube and making the texture coordinates 3D. Again, I can change the clear depth to change the color, but it is always one continuous shade.

  10. #10
    Senior Member OpenGL Pro BionicBytes's Avatar
    Join Date
    Mar 2009
    Location
    UK, London
    Posts
    1,170
    It may be that there is not much variation in your scene's depth. My depth range tends to be large as I mostly render outdoor scenes.
    So znear might be 1.0 and zfar 50,000.0 or something.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •