使用 GL_TEXTURE_2D_ARRAY 作为绘制目标
Posted
技术标签:
【中文标题】使用 GL_TEXTURE_2D_ARRAY 作为绘制目标【英文标题】:Using GL_TEXTURE_2D_ARRAY as a draw target 【发布时间】:2015-08-03 17:40:53 【问题描述】:我创建了一个二维纹理数组并使用 glTexImage3D 对其进行了初始化。然后我使用 glFramebufferTextureLayer 将单独的纹理附加到颜色附件,创建帧缓冲区不会引发错误,并且在绘制调用发生之前一切看起来都很好。
当着色器尝试访问颜色附件时,会出现以下消息:
OpenGL Debug Output message : Source : API; Type : ERROR; Severity : HIGH;
GL_INVALID_OPERATION error generated. <location> is invalid.
着色器正在使用 location 限定符访问数组的层:
layout (location = 0) out vec3 WorldPosOut;
layout (location = 1) out vec3 DiffuseOut;
layout (location = 2) out vec3 NormalOut;
layout (location = 3) out vec3 TexCoordOut;
文档说 glFramebufferTextureLayer 的工作方式与 glFramebufferTexture2D 一样,除了 layer 参数,所以我可以将 location 限定符与纹理数组一起使用,或者一些其他方式存在吗?
【问题讨论】:
【参考方案1】:我终于设法将纹理数组绑定为颜色缓冲区。很难找到有关该主题的有用信息,因此这里有一个说明:
№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);
请记住,设置纹理参数(例如 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);
不要忘记使用 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);
不要忘记为每个颜色缓冲区设置索引:
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);
在着色器中,您可以使用 layout(location = n) 限定符来指定颜色缓冲区。
OpenGL 3 注意 (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);
延迟着色的结果:
【讨论】:
以上是关于使用 GL_TEXTURE_2D_ARRAY 作为绘制目标的主要内容,如果未能解决你的问题,请参考以下文章