Rendering to cube map
Asked Answered
G

1

12

According to ARB_geometry_shader4 it is possible to render a scene onto the 6 faces of a cube map with a geometry shader and the cube map attached to a framebuffer object. I want to create a shadow map using this way. However there seems to be a conflict that I can't resolve:

  1. I can only attach a texture with GL_DEPTH_COMPONENT as internal type to the GL_DEPTH_ATTACHMENT_EXT.
  2. A depth texture can only be 1D or 2D.
  3. If I want to attach a cube map, all other attached textures must be cube maps as well.

So it looks like I can't use any depth testing when I want to render to a cube map. Or what exactly am I missing here?

EDIT: It looks like newer Nvidia drivers (180.48) support depth cube maps.

Gymnosperm answered 20/1, 2009 at 19:26 Comment(4)
I'm not sure exactly what the rendering to cube map has got to do with the geometry shader, it feels completely independent, nevertheless, I have no answer.Perseverance
The geometry shader can create 6 output triangles for every input triangle and redirect it to each of the cube map faces (see "Layered rendering"). Without a shader I have to attach each face and render the geometry 6 times.Gymnosperm
I'm wondering, could you paste the code which creates the frame buffer with the cube texture? I'm interested about this myself.Bethea
Why not just use 6 separate frame buffers for each of the sides of the cube? How are you binding the different sides of the cube map from inside the shader?Bethea
G
13

Ok, to answer some other questions here:

Of course it is possible to use 6 FBOs, one for each face. Or to use one FBO and attach each face before you draw to it. In both cases the cube map face will be treated like any other 2D texture and you can use it together with normal 2D textures or Renderbuffers. And there's probably not much of a difference in all the possible ways (if the hardware supports them).

However, it's also possible to draw everything in one step and as I was curious as to how this is done I did some research.

To create a FBO with all faces of a cube map attached to a single attachment point I used this code (written in D):

// depth cube map
glGenTextures(1, &tDepthCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, tDepthCubeMap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_DEPTH_COMPONENT24,
        width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, null);
}

// color cube map
glGenTextures(1, &tColorCubeMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, tColorCubeMap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
for (uint face = 0; face < 6; face++) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA,
        width, height, 0, GL_RGBA, GL_FLOAT, null);
}

// framebuffer object
glGenFramebuffersEXT(1, &fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, tDepthCubeMap, 0);
glFramebufferTextureARB(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, tColorCubeMap, 0);

glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

if (!isValidFBO()) {
    glDeleteFramebuffersEXT(1, &fbo);
    fbo = 0;
}
  • If you want to have only a depth map you have to change glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); to glDrawBuffer(GL_NONE); before validating it (and before drawing to it)
  • MIN and MAG filters must be set to something valid (default would be GL_NEAREST_MIPMAP_LINEAR)
  • width and height of all textures must be the same

To render to the faces of a cube map you need a geometry shader. The following shader misses some rotations but it should be clear what it does. gl_Layer is used to direct the primitive to the correct face (0 = +X, 1 = -X, ...).

#version 120
#extension GL_EXT_geometry_shader4 : enable

void main(void) {
    int i, layer;
    for (layer = 0; layer < 6; layer++) {
        gl_Layer = layer;
        for (i = 0; i < 3; i++) {
            gl_Position = gl_PositionIn[i];
            EmitVertex();
        }
        EndPrimitive();
    }
}
Gymnosperm answered 30/1, 2009 at 15:34 Comment(4)
Do you know what extension makes it possible to call glTexImage2D with a GL_TEXTURE_CUBE_MAP_POSITIVE_X and GL_DEPTH_COMPONENT24? GL_EXT_depth_texture explicitly disallows that. I need to know what GL extension I can check for to know if I can use this feature. I didn't see one in the standard extension registry. Thanks.Tibbs
That was my original problem. There doesn't seem to be any place that specifically mentions that it's allowed (that could have changed though, I haven't checked again). You can probably check for ARB_geometry_shader4 and then see if setting up the FBO doesn't generate errors.Gymnosperm
I tried getting this to work with core opengl 3.3, but failed. All I get when reading from the cube map is noise. It would be very nice if you could provide a working example.Periwinkle
I am using this in my engine and it seems to be working for GTX 970 and up, but when attempting to use it on a GTX 880 I get a black result, and when trying to use it on Intel it just crashes.Physics

© 2022 - 2024 — McMap. All rights reserved.