PDA

View Full Version : Clear a single cubemap in a cubemap Array



livin_amuk
09-11-2017, 08:15 AM
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);
}

Alfonse Reinheart
09-11-2017, 10:02 AM
Is there some reason why you can't just use `glClearTexSubImage` (https://www.khronos.org/opengl/wiki/Texture_Storage#Texture_clear)?

livin_amuk
09-11-2017, 12:02 PM
No, there is not some reason why I can't use glClearTexSubImage (https://www.khronos.org/opengl/wiki/Texture_Storage#Texture_clear). I'll give it another try. I mentioned it on StackOverflow but nobody acknowledged it, instead referring me to glFramebufferTextureLayer (https://www.khronos.org/opengl/wiki/GLAPI/glFramebufferTextureLayer), people even upvoted the answer. Still cleared the whole cubemap array for me.

livin_amuk
09-11-2017, 12:17 PM
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);

john_connor
09-12-2017, 02:42 AM
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)

Silence
09-12-2017, 03:19 AM
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)

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.

livin_amuk
09-12-2017, 03:46 AM
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);

Silence
09-12-2017, 04:10 AM
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

livin_amuk
09-12-2017, 04:22 AM
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.

mhagain
09-12-2017, 05:56 AM
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.

GClements
09-12-2017, 06:26 AM
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?

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 (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearTexSubImage.xhtml) 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 n, 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 level and halving size at each step (cube map faces must be square, i.e. the width and height will always be equal).

livin_amuk
09-12-2017, 06:44 AM
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?

GClements
09-12-2017, 06:57 AM
glClear() should clear whichever buffers are indicated by the mask 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.

livin_amuk
09-12-2017, 07:35 AM
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?

Alfonse Reinheart
09-12-2017, 09:58 AM
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?

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`.

livin_amuk
09-12-2017, 10:24 AM
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?

mhagain
09-12-2017, 11:18 AM
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) (https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glClear.xml), having ensured that depth-writing is enabled and that your glClearDepth (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearDepth.xhtml) 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 (https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearBuffer.xhtml), 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.

GClements
09-12-2017, 12:42 PM
1. Use any method possible to clear a single cubemap from the array

You can either


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


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().

livin_amuk
09-13-2017, 12:51 AM
This is confusing us because your original question stated nothing about clearing a depth buffer.

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.



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

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.

john_connor
09-13-2017, 02:15 AM
Is this something that has to be done during the creation of the FBO or can it be done during the render pass?

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



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.

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

livin_amuk
09-13-2017, 08:25 AM
you can modify your FBO (framebuffer object) whenever you want. usually it's a good choice to modify it once at initialization.

The only relevant consideration in real time rendering is speed right, so you're saying this is a good approach?


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

I am rendering depth cubemaps for 8 point light sources, and storing each within a cubemap array. From those depth maps I'm calculating shadows for the 8 light sources. This is all updated dynamically every frame and this is working fine, but I want to speed it up by only rendering one shadow map per frame, the effect will be unnoticeable and the performance gain will be huge. The thing is I need to be clear only a subset of the cubemap array per update loop and that is exactly my question, what is the most efficient way to do this?