4
\$\begingroup\$

I'm trying to make shadow cube maps in an array. I want to draw each shadow map with a single pass using a geometry shader, which I read about here: https://stackoverflow.com/questions/462721/rendering-to-cube-map. But in that example, the cube map is not in an array, and I can't find any code examples of how to get a cube map from an array attached to a frame buffer.

Just to make sure my array is legit, here's how I made it:

glGenTextures(1, &shadowMapArray);
glActiveTexture(GL_TEXTURE0 + TEXTURE_UNIT_SHADOW_MAPS_POINT);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, shadowMapArray);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_DEPTH_COMPONENT, POINT_LIGHT_SOURCE_SHADOW_MAP_RESOLUTION, POINT_LIGHT_SOURCE_SHADOW_MAP_RESOLUTION, (POINT_LIGHT_SOURCE_MAX_SHADOW_MAPS * 6), 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);

And this is how I tried to make the frame buffer:

    //Create the shadowMapFrameBuffer
    glGenFramebuffers(1, &shadowMapFrameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFrameBuffer);
    glDrawBuffer(GL_NONE);

    //Attach the shadow map to the shadowMapFrameBuffer
    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowMapArray, 0, shadowMapIndex);

    GraphicsResources::checkGLFramebufferStatus();
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

But it looks like glFramebufferTextureLayer is only going for a layer-face, not a layer (a whole cube map), so only the first face (positive X) of the first shadow map is working, (and, for some unknown reason, only half of that face).

I also tried this:

    glFramebufferTexture3D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, shadowMapArray, 0, ((shadowMapIndex * 6) + 0));
    glFramebufferTexture3D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, shadowMapArray, 0, ((shadowMapIndex * 6) + 1));
    glFramebufferTexture3D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, shadowMapArray, 0, ((shadowMapIndex * 6) + 2));
    glFramebufferTexture3D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, shadowMapArray, 0, ((shadowMapIndex * 6) + 3));
    glFramebufferTexture3D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, shadowMapArray, 0, ((shadowMapIndex * 6) + 4));
    glFramebufferTexture3D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, shadowMapArray, 0, ((shadowMapIndex * 6) + 5));

But I don't know if a frame buffer is meant to be set up with multiple calls like that, and anyway, this produces 'GL_INVALID_ENUM'.

Anyone know the proper way to do this?

\$\endgroup\$
2
\$\begingroup\$

I hate seeing workarounds instead of real answers, but I've come to the conclusion that the current OpenGL spec doesn't provide the functionality that would answer this question, and I have found a workaround:

Rather than making a small frame buffer for each cube map, I made a big one for all of them with a simple call to glFramebufferTexture:

glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowMapArray, 0);

Then to access a specific cube map for rendering, I passed the index of its first face to a uniform in the geometry shader, and assigned it to gl_Layer and rendered to that and the next 5 layers.

This created a problem with clearing the shadow map I wanted to update - the single frame buffer can only clear all of them at once, wiping the ones that aren't getting updated. My solution for this was to make 6 single face frame buffers for each cube map using glFramebufferTextureLayer, and clearing those instead. It seems a little awkward and redundant, but it works.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.