5
\$\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\$

1 Answer 1

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\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .