使用 GL_TEXTURE_2D_ARRAY 作为绘制目标

Rom*_*man 1 c++ opengl

我创建了一个 2D 纹理数组并使用glTexImage3D对其进行了初始化。然后我使用glFramebufferTextureLayer将单独的纹理附加到颜色附件,帧缓冲区创建不会引发错误,并且在绘制调用发生之前一切似乎都很好。

当着色器尝试访问颜色附件时,会出现以下消息:

OpenGL Debug Output message : Source : API; Type : ERROR; Severity : HIGH;
GL_INVALID_OPERATION error generated. <location> is invalid.
Run Code Online (Sandbox Code Playgroud)

着色器使用位置限定符访问数组的层:

layout (location = 0) out vec3 WorldPosOut; 
layout (location = 1) out vec3 DiffuseOut; 
layout (location = 2) out vec3 NormalOut; 
layout (location = 3) out vec3 TexCoordOut; 
Run Code Online (Sandbox Code Playgroud)

文档说glFramebufferTextureLayer就像glFramebufferTexture2D一样工作,除了 layer 参数,所以我可以使用带有纹理数组的位置限定符,还是存在其他一些方式?

Rom*_*man 5

我终于设法将纹理数组绑定为颜色缓冲区。很难找到有关该主题的有用信息,因此这里有一个说明:

?1. 您需要创建一个纹理数组并正确初始化它:

glGenTextures(1, &arrayBuffer);
glBindTexture(GL_TEXTURE_2D_ARRAY, arrayBuffer);

// we should initialize layers for each mipmap level
    for (int mip = 0; mip < mipLevelCount; ++mip) {

glTexImage3D(GL_TEXTURE_2D_ARRAY, mip, internalFormat, ImageWidth, ImageHeight,
 layerCount, 0, GL_RGB, GL_UNSIGNED_INT, 0);
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, textureFilter);
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, textureFilter);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, mipLevelCount - 1);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

}
Run Code Online (Sandbox Code Playgroud)

请记住,设置 MIN/MAG 过滤器和 BASE/MAX mipmap 级别等纹理参数很重要。OpenGL 将最大 mipmap 级别设置为 1000,如果您没有提供一整千个 mipmap,您将获得不完整的纹理,除了黑屏之外,您什么也得不到。

?2. 在将图层附加到颜色缓冲区之前,不要忘记将arrayBuffer绑定到 GL_TEXTURE_2D_ARRAY 目标:

glBindTexture(GL_TEXTURE_2D_ARRAY, arrayBuffer);

for (unsigned int i = 0; i < NUMBER_OF_TEXTURES; i++) {

glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, arrayBuffer, 0, i);

}
Run Code Online (Sandbox Code Playgroud)

不要忘记使用glBindTexture将 GL_TEXTURE_2D_ARRAY 目标设置为 0,否则它可以在初始化代码之外进行修改。

?3. 由于数组中每个图像internalFormat必须保持不变,我建议为深度/模板缓冲区创建一个单独的纹理:

glGenTextures(1, &m_depthTexture);

...

glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, WindowWidth,
WindowHeight, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);

glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, m_depthTexture, 0);
Run Code Online (Sandbox Code Playgroud)

不要忘记为每个颜色缓冲区设置索引:

for (int i = 0; i < GBUFFER_NUM_TEXTURES; ++i)
        DrawBuffers[i] = GL_COLOR_ATTACHMENT0 + i; //Sets appropriate indices for each color buffer

glDrawBuffers(ARRAY_SIZE_IN_ELEMENTS(DrawBuffers), DrawBuffers);
Run Code Online (Sandbox Code Playgroud)

在着色器中,您可以使用layout(location = n)限定符来指定颜色缓冲区。

OpenGL 3 Note (NVIDIA): glFramebufferTextureLayer从 OpenGL 3.2(核心配置文件)开始可用,但在 NVIDIA GPU 上,驱动程序会将 OpenGL 版本强制为 4.5,因此如果您关心兼容性,应该指定 OpenGL 的确切版本。我在我的应用程序中使用 SDL2,所以我使用以下调用来设置 OpenGL 版本:

SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
Run Code Online (Sandbox Code Playgroud)

延迟着色的结果: 最终渲染 辅助 FBO 的颜色缓冲区