1

I need to clear a specific cubemap layer within a cubemap array. I think this may be achievable with glClearTexSubImage but I'm not having any luck with it.

enter image description here

To give context, I'm shadow mapping. A cubemap array is encompassing 8 cubemap layers, with each containing scene/depth information for one of 8 light sources.

First, the entire cubemap array is cleared with

GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); 

Next, the scene is rendered into the 8 cubemaps from the viewpoint of the 8 light sources.

for (int j = 0; j < lights.Count; j++)
{
    // Create the light's view matrices
    List<Matrix4> shadowTransforms = new List<Matrix4>();
    shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(1, 0, 0), new Vector3(0, -1, 0)));
    shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(-1, 0, 0), new Vector3(0, -1, 0)));
    shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 1, 0), new Vector3(0, 0, 1)));
    shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, -1, 0), new Vector3(0, 0, -1)));
    shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, 1), new Vector3(0, -1, 0)));
    shadowTransforms.Add(Matrix4.LookAt(lights[j].position, lights[j].position + new Vector3(0, 0, -1), new Vector3(0, -1, 0)));

    // Send uniforms to the shader
    for (int i = 0; i < 6; i++)
    {
        Matrix4 shadowTransform = shadowTransforms[i];
        GL.UniformMatrix4(shader.getUniformID("shadowTransforms[" + i + "]"), false, ref shadowTransform);
    }
    GL.Uniform1(shader.getUniformID("lightID"), j);

    // Draw Scene
    DrawSceneInstanced(shader);
}

This all works fine, updating every shadow map each frame. However in favour of optimisation I wish to update only a single shadow map each frame, meaning I need to clear individual cubemap layers separately.

How is this done?

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);

    // Attach cubemap texture as the FBO's color buffer
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, FBO_handle);
    GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, cubeMapTextureHandle, 0);
    GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, cubeMapDepthHandle, 0);

    // Error check
    var errorcheck = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
    Console.WriteLine("CUBEMAP ARRAY: " + errorcheck);

    // Bind default framebuffer
    GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}
livin_amuk
  • 1,285
  • 12
  • 26
  • The color and depth buffers are part of the frame buffer, not part of textures, cubemaps, etc. – code_dredd Aug 27 '17 at 22:22
  • You should check [this related post](https://stackoverflow.com/questions/8004829/framebuffer-color-buffer) – code_dredd Aug 27 '17 at 22:23
  • All I learned from that is Canada and Ontario are real. – livin_amuk Aug 27 '17 at 23:22
  • I understand the difference between FBOs, colour buffers, and textures. Guess I misunderstood the parameters and purpose of `glClearTexSubImage `. – livin_amuk Aug 27 '17 at 23:34
  • `"All I learned from that is Canada and Ontario are real"` I'm not sure being sarcastic/cynical/etc will get you a lot of help... but the link I posted included [this link](http://oss.sgi.com/projects/ogl-sample/registry/EXT/framebuffer_object.txt) re FBOs. Your question explicitly said you wanted to `"clear color and depth buffers of a ... cubemap array"`, but I'm only aware of the color/depth buffers in relation to FBO attachment points or the default framebuffer on which `glClear(GL_COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT)` are used. – code_dredd Aug 28 '17 at 00:14
  • @ray: You can either clear the framebuffer using `glClear` or one of the textures using `glClearImage/glClearSubImage`. I don't see how FBOs are relevant here. – BDL Aug 28 '17 at 08:17
  • To the question: A format of `GL_RED` doesn't look right when clearing a depth texture. Don't you mean `GL_DEPTH_COMPONENT`? – BDL Aug 28 '17 at 08:19
  • @BDL Well, I'm not clear on what OP means by saying that they want to `"clear the color and depth buffers of a ... cubemap"` texture. I simply said that as far as color/depth *buffers* are concerned, I was only aware of them in the context I mentioned. Did OP mean a depth *texture* and not *buffer*? – code_dredd Aug 28 '17 at 10:30
  • @BDL I reworded the question, hopefully clearer, and added the greater context of my problem. – livin_amuk Aug 28 '17 at 13:35

1 Answers1

2

Attach a specific layer of the texture array to the FBO using glFramebufferTextureLayer then use glClear() to clear that attachment.

Solution Attempt:

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);
livin_amuk
  • 1,285
  • 12
  • 26
Michael IV
  • 11,016
  • 12
  • 92
  • 223
  • This seems to be the right track. But it's still clearing the whole array for me... – livin_amuk Aug 29 '17 at 06:37
  • It's highly unlikely that it clears the whole array. Can you show the code where you manage your FBO attachment? – Michael IV Aug 29 '17 at 07:01
  • I can change the skybox to one of the different shadow maps with the number keys and it's definitely clearing the lot. I've added the FBO attachment code to your answer temporarily. – livin_amuk Aug 29 '17 at 08:48
  • Well,you were supposed to add your solution attempt to your question,not to my answer :) – Michael IV Aug 29 '17 at 16:01
  • Yeh I know it's not conventional, figured it's going to be the real solution very soon and it would be most valuable to others in conjunction with your answer. In any case the FBO code is in my question now... – livin_amuk Aug 29 '17 at 23:09
  • do you think you could have another look at this for me? – livin_amuk Aug 30 '17 at 23:20
  • I am afraid you must bind a single cube map face as FBO render target. And if you wish to clear all 6 faces at once you should use layered rendering approach where it involves also geometry shaders. I render to cube maps in my apps. Never did to cubemap texture array. But it doesn't matter, same rules apply. Either you bind a single face to a single render target, or use layered rendering. – Michael IV Aug 31 '17 at 08:38
  • I'm using layered rendering with a geometry shader already, renders to a cubemap array one cubemap at a time and works fine. I don't think I understand your comment though, what are you saying my problem is now? – livin_amuk Sep 01 '17 at 03:28