creating GL_TEXTURE_CUBE_MAP_ARRAY and binding to a layer?

How do you create a GL_TEXTURE_CUBE_MAP_ARRAY with 4 layers?

Heres my current code;

// Configure depth map FBO
    const int maxLights = 4;
    const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
    GLuint depthMapFBO;
    glGenFramebuffers(1, &depthMapFBO);
    // Create depth cubemap texture
    GLuint depthCubemap;
    glGenTextures(1, &depthCubemap);
    glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);
    for (GLuint i = 0; i < 6; ++i)
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    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);
    // Attach cubemap as depth map FBO's color buffer
    glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "Framebuffer not complete!" << std::endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

Then how do you bind to a specific layer?

glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
renderScene();

Thanks.

I’ve searched google, bing and here for an example but nothing of any use.
Is this rare or something?

Anyone help me out?

You might read up on these, in the man pages and the GL spec:

Thanks.

Ive got this so far but don’t know what to put for depth? It’s for a shadow map.
Also, is GL_RGBA8 correct for a shadowmap? Or should I use GL_R8 since I’m only dealing with depth?

glGenTextures(1, &depthCubemap);
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubemap);
	glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, maxLights, GL_RGBA8, SHADOW_WIDTH, SHADOW_HEIGHT, ?);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    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);
    // Attach cubemap as depth map FBO's color buffer
    glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);

As for glFramebufferTextureLayer, i dont know how to fill the rest in?
Lets say I want layer 6.

glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, ?, ?, 6)

Do I still bind to buffer or is that now glFramebufferTextureLayer?
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);

I’ve searched goggle and bing for +“GL_TEXTURE_CUBE_MAP_ARRAY”, google came up with nothing relevant, and bing went from page 8 to page 6, there’s a bug in their code because of the limited amount of results orr lack of searches.

Neither. A depth texture should use one of the GL_DEPTH_COMPONENT formats (probably GL_DEPTH_COMPONENT24; support for 32-bit depth is optional).

This is incorrect; you’re passing the number of lights (which is presumably the number of layers) as the levels parameter, which is the number of mipmap levels. Which should probably be 1, given that you’re using GL_NEAREST.

For a cube map array, the depth parameter should be the number of layer-faces, i.e. the number of layers (cube maps) multiplied by six (a GL_INVALID_VALUE error will be generated if depth isn’t a multiple of six). For functions such as glTexSubImage3D() which take a layer parameter, a particular face of a particular layer is specified using layer*6+face.

The texture parameter should be the name of the texture (depthCubemap), level is the mipmap level, and should be zero unless you’re using mipmaps.

Thanks for the help, appreciated!
I have OpenGL 4.0 if that makes any difference?

So I have this but it’s throwing Framebuffer not complete! error:


    // Configure depth map FBO
    const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
    GLuint depthMapFBO;
    glGenFramebuffers(1, &depthMapFBO);
    // Create depth cubemap texture
    GLuint depthCubemap;
    glGenTextures(1, &depthCubemap);
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubemap);
	glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 1, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, maxLights * 6);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    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);
    // Attach cubemap as depth map FBO's color buffer
    glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "Framebuffer not complete!" << std::endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

i think you are calling the wrong function, if you want to attach a certain cubemap face to a framebuffer, you have to call:

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, color_tex, 0);

GL_TEXTURE_CUBE_MAP_POSITIVE_Y specifies the face you want to attach to the FBO

take a look at the example in the wiki:
https://www.khronos.org/opengl/wiki/Framebuffer_Object_Extension_Examples#Quick_example.2C_render_to_texture_.28Cubemap.29

Report the return value from glCheckFramebufferStatus(), as that indicates why it is incomplete.

If maxLights is large, you may be exceeding the maximum number of framebuffer layers; in that case, you’d need to bind individual faces with glFramebufferTextureLayer(). There’s no way to bind a subset of a texture’s layers; it’s either a single layer or all of them.

[QUOTE=GClements;1285298]Report the return value from glCheckFramebufferStatus(), as that indicates why it is incomplete.

If maxLights is large, you may be exceeding the maximum number of framebuffer layers; in that case, you’d need to bind individual faces with glFramebufferTextureLayer(). There’s no way to bind a subset of a texture’s layers; it’s either a single layer or all of them.[/QUOTE]

Return value: 36055

maxLights = 4.

#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7

your FBO doesnt have any valid attachments, try using glFramebufferTextureLayer instead of glFramebufferTexture

Is this correct?

glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 1, 0);

I’m receiving error code 36054

[QUOTE=paul_g_griffiths;1285301]Is this correct?

glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 1, 0);

[/QUOTE]
That binds mipmap level 1, which doesn’t appear to exist.

Which is GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.

I’d suggest also calling glGetError() to check that none of the commands prior to that point failed. If an error condition exists, you need to determine which command caused it.

But with only four lights, you should be able to use glFramebufferTexture() to attach the entire array as a layered framebuffer if that’s what you want.

[QUOTE=GClements;1285305]That binds mipmap level 1, which doesn’t appear to exist.

Which is GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT.

I’d suggest also calling glGetError() to check that none of the commands prior to that point failed. If an error condition exists, you need to determine which command caused it.

But with only four lights, you should be able to use glFramebufferTexture() to attach the entire array as a layered framebuffer if that’s what you want.[/QUOTE]

glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubemap); is throwing error 1280.

I’ve only got 4 lights to test this code, am hoping for a lot more?

you can use google.com to search how to translate a “decimal” value into a “hexadecimal” value:
1280 == 0x0500

and you can look up the meaning of those “error” codes here:
https://www.khronos.org/opengl/wiki/OpenGL_Error#Meaning_of_errors

0x0500 == GL_INVALID_ENUM:

[QUOTE=john_connor;1285309]you can use google.com to search how to translate a “decimal” value into a “hexadecimal” value:
1280 == 0x0500[/QUOTE]

Even better, just translate the error code to a string, and print it and the hex value directly:


void CheckGLErrors()
{
  for( GLenum err; (err = glGetError()) != GL_NO_ERROR; )
  {
    fprintf( stderr, "GL ERROR: %s (0x%x)
", gluErrorString(err), err );
  }
}

I’m receiving error " invalid enumerant" at glTexStorage3D.
But not with GL_DEPTH_COMPONENT24, glCheckFramebufferStatus repcorts no error.

    const GLuint maxLights = 4;
    // Configure depth map FBO
    const GLuint SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
    GLuint depthMapFBO;
	CHECK_GL_ERROR();
    glGenFramebuffers(1, &depthMapFBO);
    // Create depth cubemap texture
    GLuint depthCubemap;
    glGenTextures(1, &depthCubemap);
	CHECK_GL_ERROR();
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubemap);
	CHECK_GL_ERROR();
	glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 1, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, maxLights * 6);
	CHECK_GL_ERROR(); // invalid enumerant
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    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);
	CHECK_GL_ERROR();
    // Attach cubemap as depth map FBO's color buffer
    glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
	CHECK_GL_ERROR();
    //glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);
	glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0, 0);
	CHECK_GL_ERROR();
    glDrawBuffer(GL_NONE);
	CHECK_GL_ERROR();
    glReadBuffer(GL_NONE);
	CHECK_GL_ERROR();
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "Framebuffer not complete!" << std::endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

It’s not casting any shadows, is this correct for the array 0?

glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0, 0);

In my shader code I modified ;

texture(depthMap, fragToLight).r

to become:

texture(depthMap, fragToLight, 0).r

I take it that’s correct for array 0?

Also:

glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubemap);

Anything else I should be doing?

[QUOTE=paul_g_griffiths;1285311]I’m receiving error " invalid enumerant" at glTexStorage3D.
But not with GL_DEPTH_COMPONENT24, glCheckFramebufferStatus repcorts no error.
[/QUOTE]
If you’re planning on using a texture as a framebuffer attachment, always use a sized format. For depth textures, note that GL_DEPTH_COMPONENT32 isn’t required to be usable as a render target (only 16, 24 and 32F are). Unsized formats are never required to be usable as render targets. For colour attachments, 3-component (RGB) formats other than RGB565 and R11F_G11F_B10F aren’t usable, nor are any signed normalised formats.

Thanks.

Am currently receiving invalid operation error for;


glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);

Anyone see anything wrong? This is my glTexStorage3D;

glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 1, GL_DEPTH_COMPONENT24, SHADOW_WIDTH, SHADOW_HEIGHT, maxLights * 6);

The only situations in which that should occur are if zero is bound to the GL_FRAMEBUFFER target or of the texture parameter refers to a buffer texture. So assuming that depthFBO is non-zero and the glBindFramebuffer() call succeeded, I’d suspect a driver bug.

Also, looking over the most recent versions of the specifications, it appears that someone overlooked cube map arrays with regard to glFramebufferTexture() until 4.5. Earlier versions (4.2 through 4.4) say

If texture is the name of a three-dimensional texture, cube map texture, one-or two-dimensional array texture, or two-dimensional multisample array texture, the texture level attached to the framebuffer attachment point is an array of images, and the framebuffer attachment is considered layered.

while 4.5 says

If texture is the name of a three-dimensional texture, cube map array texture cube map texture, one- or two-dimensional array texture, or two-dimensional multisample array texture, the texture level attached to the framebuffer attachment point is an array of images, and the framebuffer attachment is considered layered.

(emphasis mine, missing comma in the original).

Taken literally, that would imply that using a cube map array results in an non-layered framebuffer, which wouldn’t make much sense. Note that the section on layered framebuffers does describe how layer-faces are numbered for cube map arrays bound to a layered framebuffer, so it’s not the case that rendering to cube map arrays wasn’t supposed to work in earlier versions.

Given that the authors of the specification overlooked this detail, it’s quite possible that the driver developers did so.