Clear a single cubemap in a cubemap Array

I need to clear a specific cubemap layer within a cubemap array. I think this may be achievable with glFramebufferTextureLayer, and below is my attempt, but it is still clearing the entire cubemap array.

GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);

FramebufferTarget target = FramebufferTarget.Framebuffer;
FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0;
int level = 0;
int layer = currentShadowMap;
int texture = shadowMapArray.FBO_handle;

GL.FramebufferTextureLayer(target, attachment, texture, level, layer);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

FBO/Cubemap Array creation and attachment:

public CubeMapArray()
{
    // Create the FBO
    GL.GenFramebuffers(1, out FBO_handle);

    // Create and bind the CubeMap array
    GL.GenTextures(1, out cubeMapTextureHandle);
    GL.BindTexture(TextureTarget.TextureCubeMapArray, cubeMapTextureHandle);

    // Allocate storage space
    GL.TexImage3D(TextureTarget.TextureCubeMapArray, 0, PixelInternalFormat.Rg16, size, size, layers * 6, 0, PixelFormat.Red, PixelType.Float, IntPtr.Zero);

    // Set the suitable texture parameters
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapR, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureBaseLevel, 0);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMaxLevel, 0);

    // Create and bind the CubeMap depth array
    GL.GenTextures(1, out cubeMapDepthHandle);
    GL.BindTexture(TextureTarget.TextureCubeMapArray, cubeMapDepthHandle);

    // Allocate storage space
    GL.TexImage3D(TextureTarget.TextureCubeMapArray, 0, PixelInternalFormat.DepthComponent, size, size, layers * 6, 0, PixelFormat.DepthComponent, PixelType.UnsignedByte, IntPtr.Zero);

    // Set the suitable texture parameters
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureWrapR, (int)TextureWrapMode.ClampToEdge);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureBaseLevel, 0);
    GL.TexParameter(TextureTarget.TextureCubeMapArray, TextureParameterName.TextureMaxLevel, 0);
}

Is there some reason why you can’t just use glClearTexSubImage?

1 Like

No, there is not some reason why I can’t use glClearTexSubImage. I’ll give it another try. I mentioned it on StackOverflow but nobody acknowledged it, instead referring me to glFramebufferTextureLayer, people even upvoted the answer. Still cleared the whole cubemap array for me.

The cubemap array contains 8 cubemaps, I’m trying to clear only the one at index 2, except it’s wiping the lot.

int layer = currentShadowMap;
int texture = shadowMapArray.FBO_handle;
int level = 2; // Attempting to clear cubemap at index 2
int xoffset = 0;
int yoffset = 0;
int zoffset = 0;
int width = shadowMapArray.size;
int height = shadowMapArray.size;
int depth = 6;
PixelFormat format = PixelFormat.Red;
PixelType type = PixelType.Float;
IntPtr data = IntPtr.Zero;

GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);
GL.ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);

int level = 2; // Attempting to clear cubemap at index 2

GL.ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);

level means the “mipmap level” to clear, i guess that ought to be 0. and you dont have to bind a framebuffer to clear a (sub-) texture (attached to it)

[QUOTE=john_connor;1288479]


int level = 2; // Attempting to clear cubemap at index 2

GL.ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);

level means the “mipmap level” to clear, i guess that ought to be 0. and you dont have to bind a framebuffer to clear a (sub-) texture (attached to it)[/QUOTE]

Yes as far as I understand it, it looks like the OP is mixing levels and layers.

To the OP, also try to select the face you want first by calling glFramebufferTextureFace. You need ARB_geometry_shader4 to use it however.

Ah right that clears it up, level is “mipmap level”.

I couldn’t find any documentation for glFramebufferTextureFace. Despite returning an InvalidOperation error, this is actually working and clears the first cubemap. How would I for example clear the second in the array?


FramebufferTarget target = FramebufferTarget.Framebuffer;
FramebufferAttachment attachemnt = FramebufferAttachment.ColorAttachment0;
int texture = shadowMapArray.cubeMapTextureHandle;
int level = 0;
TextureTarget face = TextureTarget.TextureCubeMap;

int xoffset = 0;
int yoffset = 0;
int zoffset = 0;
int width = shadowMapArray.size;
int height = shadowMapArray.size;
int depth = 6;
PixelFormat format = PixelFormat.Red;
PixelType type = PixelType.Float;
IntPtr data = IntPtr.Zero;

GL.Arb.FramebufferTextureFace(target, attachemnt, texture, level, face);
GL.ClearTexSubImage(texture, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);

shadowMapArray.cubeMapTextureHandle is the actual texture handle, is this correct?

// Create the FBO
GL.GenFramebuffers(1, out FBO_handle);

// Create and bind the CubeMap array
GL.GenTextures(1, out cubeMapTextureHandle);
GL.BindTexture(TextureTarget.TextureCubeMapArray, cubeMapTextureHandle);

Well, I don’t know if what I told above can be useful for you.

In case it might, here are some links that might help further:

https://www.khronos.org/opengl/wiki/Cubemap_Texture#Layered_Rendering
https://www.khronos.org/opengl/wiki/Cubemap_Texture#Cubemap_array_textures

I was slow at editing my reply above and didn’t see this, I read through that documentation but couldn’t see what I’m after however.

The updated code above actually works, but only clears the first cubemap in the array, do you know where I make the change to indicate subsequent a cubemap? By changing depth from 6 to 7 it clears all the entire first cubemap and one face of the second cubemap, as expected. What I need to do obivously is specify the starting offset. Any value other than 0 for xoffset, yoffset, or zoffset and nothing is cleared at all, I guess they refer to regions within the individual cubemap faces.

Documentation: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_clear_texture.txt

Cube map textures are treated as an array of six slices in the z-dimension, where the value of <zoffset> is interpreted as specifying the cube map face for the corresponding <layer> in table 9.3 (Layer numbers for cube map texture faces) and <depth> is the number of faces to clear. For cube map array textures, <zoffset> is the first layer-face to clear, and <depth> is the number of layer-faces to clear. Each layer-face is translated into an array layer and a cube map face as described for layer-face numbers in section 8.5.3.

[QUOTE=livin_amuk;1288481]Ah right that clears it up, level is “mipmap level”.

I couldn’t find any documentation for glFramebufferTextureFace. Despite returning an InvalidOperation error, this is actually working and clears the first cubemap. How would I for example clear the second in the array?
[/QUOTE]
Cube map array textures are often treated as an array of 6*N 2D textures (“layer-faces”), where N is the size of the array. I.e. each face of each layer is a separate 2D texture. This is certainly the case when binding a specific face as a non-layered framebuffer attachment, and appears to be the case for clearing. The glClearTexSubImage reference page says:

For cube map array textures, zoffset is the first layer-face to clear, and depth is the number of layer-faces to clear.

So to clear a given mipmap level for all six faces of the cube map corresponding to layer [var]n[/var], you’d use:


glClearTexSubImage(texture, level, 0, 0, 6*n, size, size, 6, format, type, data);

To clear all mipmap levels, you’d need to call it in a loop, incrementing [var]level[/var] and halving [var]size[/var] at each step (cube map faces must be square, i.e. the width and height will always be equal).

1 Like

Thank you mhagain, that is working. It’s clearing the color attachment, it seems I have to manually clear the attached depth buffer? Is this correct?

glClear() should clear whichever buffers are indicated by the [var]mask[/var] parameter, but note that write masks set by e.g. glColorMask() or glDepthMask() apply to glClear(). Obviously, the relevant textures need to be attached to the currently-bound FBO at the time of the call.

glClearTexSubImage() only affects the specified texture.

Unless I’m misunderstanding you, glClear() is useless for me here because it wipes the entire FBO, thus the entire cubemap array.

glClearTexSubImage() is working for me, in other words it’s clearing specific individual cubemap layers, but only the color texture and not the associated depth texture. Do I need a second glClearTexSubImage() call with different parameters to clear the depth?

[QUOTE=livin_amuk;1288493]Unless I’m misunderstanding you, glClear() is useless for me here because it wipes the entire FBO, thus the entire cubemap array.

glClearTexSubImage() is working for me, in other words it’s clearing specific individual cubemap layers, but only the color texture and not the associated depth texture. Do I need a second glClearTexSubImage() call with different parameters to clear the depth?[/QUOTE]

It doesn’t clear the framebuffer. It clears the texture you pass in. The framebuffer is completely irrelevant.

If you have two textures you want to clear, then you need two calls to glClearTexSubImage.

1 Like

I think I need to back up a bit here…

Currently I am:

  1. Using glClear() to clear an entire cubemap array.
  2. Rendering a bunch of cubemaps into the array.

What I am trying to achieve is this:

  1. Use any method possible to clear a single cubemap from the array
  2. Render a single cubemap into the array.

It is step 1 that I am struggling with. I need to perform the equivalent of glClear, except only on a single cubemap, not the entire array. How would you go about this Alfonse?

This is confusing us because your original question stated nothing about clearing a depth buffer: you asked, and only asked, about clearing a single cubemap, then when you got that working you started asking about a depth buffer too. If you had given us the full requirement in your original question you might have got a full answer.

To clear a depth buffer the old-fashioned what you can use glClear (GL_DEPTH_BUFFER_BIT), having ensured that depth-writing is enabled and that your glClearDepth is set to the value you wish to clear to, and that will do the job for a good percentage of use cases. For more control use the modern way: glClearBuffer, making sure that you pay attention to the documentation because it describes the specific calls and parameters you need to use to successfully clear depth. Yes, this is an extra OpenGL call; you cannot clear both color and depth in a single call using this approach.

You can either

[ol]
[li] bind individual layer-faces to the FBO and clear each one with glClear(), or
[/li][li] clear a range of layer-faces with glClearTexSubImage()
[/li][/ol]

The first option can also clear any attached depth buffer. With the second option, you’ll need to clear the depth buffer separately; either with glClear(GL_DEPTH_BUFFER_BIT), or glClearBuffer(), or by using glClearTexSubImage() on the depth texture (assuming that it’s a texture and not a renderbuffer).

You can’t clear a subset of the layer-faces of a cube map array using a single glClear() call, as you can’t bind a subset of the layer-faces to a FBO. You can only bind either a single layer-face (with glFramebufferTextureLayer()) or the entire array (with glFramebufferTexture()). The same restrictions apply to glClearBuffer().

I figured it’d be a safe assumption, guess I’m still a novice. Not here to screw around though, I’ll be more explicit in the future.

[QUOTE=GClements;1288505]

  1. bind individual layer-faces to the FBO and clear each one with glClear()[/QUOTE]

Thank you. Is this something that has to be done during the creation of the FBO or can it be done during the render pass?

GL.BindFramebuffer(FramebufferTarget.Framebuffer, shadowMapArray.FBO_handle);

FramebufferTarget target = FramebufferTarget.Framebuffer;
FramebufferAttachment attachment = FramebufferAttachment.ColorAttachment0;
int level = 0;
int layer = 2; // Trying to delete cubemap at array index 2
int texture = shadowMapArray.cubeMapTextureHandle;

GL.FramebufferTextureLayer(target, attachment, texture, level, layer);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

Is glFramebufferTextureLayer the wrong choice here? Pretty sure, because there isn’t an option to specify which face. I guess ‘texture’ needs to point to a layerface texture? This is clearing the whole cubemap array btw.

you can modify your FBO (framebuffer object) whenever you want. usually it’s a good choice to modify it once at initialization.

depends on what you want to do (couldnt figured that out):

  1. render to texture (cubemap array):
    glFramebufferTexture(…)

  2. render to texture layer (1 face [2D surface] of a cubemap OR cubemap array):
    glFramebufferTextureLayer(…)

just read the description:
https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glFramebufferTextureLayer.xhtml

“layer” determines what cubemap index AND face
set “layer” to 15 means:
cubemap index = 15 / 6 = 2
face = 15 % 6 = 3

the same is true for “render to texture” (cubemap array): but layer is then the “gl_Layer” variable used in the geometry shader