PDA

View Full Version : creating GL_TEXTURE_CUBE_MAP_ARRAY and binding to a layer?



paul_g_griffiths
01-04-2017, 08:42 AM
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.

paul_g_griffiths
01-04-2017, 11:21 AM
I've searched google, bing and here for an example but nothing of any use.
Is this rare or something?

Anyone help me out?

Dark Photon
01-04-2017, 01:36 PM
You might read up on these, in the man pages and the GL spec:

* glTexStorage3D (https://www.opengl.org/sdk/docs/man/html/glTexStorage3D.xhtml)
* glFramebufferTextureLayer (https://www.opengl.org/sdk/docs/man/html/glFramebufferTextureLayer.xhtml)

paul_g_griffiths
01-04-2017, 02:07 PM
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.

GClements
01-04-2017, 06:39 PM
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?

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




glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY, maxLights, GL_RGBA8, SHADOW_WIDTH, SHADOW_HEIGHT, ?);


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.



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)

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.

paul_g_griffiths
01-05-2017, 12:12 AM
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);

GClements
01-05-2017, 03:00 AM
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.

paul_g_griffiths
01-05-2017, 03:32 AM
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.

Return value: 36055

maxLights = 4.

john_connor
01-05-2017, 04:20 AM
Return value: 36055

#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7

your FBO doesnt have any valid attachments, try using glFramebufferTextureLayer (https://www.opengl.org/sdk/docs/man/html/glFramebufferTextureLayer.xhtml) instead of glFramebufferTexture

paul_g_griffiths
01-05-2017, 04:26 AM
Is this correct?


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

I'm receiving error code 36054

GClements
01-05-2017, 08:47 AM
Is this correct?


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

That binds mipmap level 1, which doesn't appear to exist.

I'm receiving error code 36054

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.

paul_g_griffiths
01-05-2017, 11:53 AM
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.

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?

john_connor
01-05-2017, 02:25 PM
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubemap); is throwing error 1280.

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:

GL_INVALID_ENUM, 0x0500
Given when an enumeration parameter is not a legal enumeration for that function. This is given only for local problems; if the spec allows the enumeration in certain circumstances, where other parameters or state dictate those circumstances, then GL_INVALID_OPERATION is the result instead.

Dark Photon
01-05-2017, 02:50 PM
you can use google.com to search how to translate a "decimal" value into a "hexadecimal" value:
1280 == 0x0500

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)\n", gluErrorString(err), err );
}
}

paul_g_griffiths
01-05-2017, 03:06 PM
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);

paul_g_griffiths
01-05-2017, 03:40 PM
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?

GClements
01-05-2017, 05:55 PM
I'm receiving error " invalid enumerant" at glTexStorage3D.
But not with GL_DEPTH_COMPONENT24, glCheckFramebufferStatus repcorts no error.

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.

paul_g_griffiths
01-05-2017, 06:29 PM
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);

GClements
01-06-2017, 11:11 AM
Am currently receiving invalid operation error for;


glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);

Anyone see anything wrong?

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.

paul_g_griffiths
01-06-2017, 01:16 PM
Thanks for the info.
I've binned my laptop due to pins on the power socket coming off and gone back to my desktop which is OpenGL 4.4. I can use code from a book OpenGL insights, it's got a code example for multiple lights and shadows.

Thanks all.