如何正确地将对象的整数 ID 渲染到整数纹理缓冲区?
假设我有一个内部格式为 GL_LUMINANCE16 的 texture2D,我将它作为颜色附件附加到我的 FBO。
渲染对象时,我将整数 ID 传递给着色器,并希望将此 ID 渲染到我的整数纹理中。
但是,fragmentsshader 输出的类型是 vec4。如何正确地将我的 ID 转换为四分量浮点数并避免转换不准确,以便最终我的整数纹理目标中的整数值对应于我想要渲染的整数 ID?
我仍然认为这里没有明确的答案。所以这是我如何通过 2D 纹理使它工作的:
// First, create a frame buffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Then generate your texture and define an unsigned int array:
glGenTextures(1, &textureid);
glBindTexture(GL_TEXTURE_2D, textureid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, w, h, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Attach it to the frame buffer object:
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, textureid, 0);
// Before rendering
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLuint buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; // this assumes that there is another texture that is for the render buffer. Color attachment1 is preserved for the element ids.
glDrawBuffers(2, buffers);
// Clear and render here
glFlush(); // Flush after just in case
glBindFramebuffer(GL_FRAMEBUFFER, 0);
在 GLSL 方面,片段着色器应具有(此处为 4.3 核心配置文件代码):
layout(location = 0) out vec4 colorOut; // The first element in 'buffers' so location 0
layout(location = 1) out uvec4 elementID; // The second element in 'buffers' so location 1. unsigned int vector as color
// ...
void main()
{
//...
elementID = uvec4( elementid, 0, 0, 0 ); // Write the element id as integer to the red channel.
}
您可以读取主机端的值:
unsigned int* ids = new unsigned int[ w*h ];
glBindTexture(GL_TEXTURE_2D, textureid);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, ids);
你的问题有几个问题。
首先,不是GL_LUMINANCE16
“整数纹理”。它是一个包含标准化无符号整数值的纹理。它使用整数来表示 [0, 1] 范围内的浮点数。如果要存储实际整数,则必须使用实际整数图像格式。
其次,您不能渲染到亮度纹理;它们不是可呈现颜色的格式。如果你真的想渲染到单通道纹理,你必须创建单通道图像格式。GL_LUMINANCE16
因此,您可以使用GL_R16UI
16 位单通道无符号整数图像格式来代替。
现在您已经正确设置了此设置,这非常简单。定义一个uint
片段着色器输出并让您的片段着色器将您的uint
值写入它。这uint
可能来自顶点着色器或制服;但是你想这样做。
显然,您还需要将纹理或渲染缓冲区附加到 FBO,但我很确定您知道这一点。
最后一件事:不要使用短语“纹理缓冲区”,除非您指的是其中之一。否则,它会变得混乱。
我想你的整数 ID 是一组原语的标识符;实际上它可以被定义为一个着色器制服:
uniform int vertedObjectId;
渲染后,您希望将片段处理存储到整数纹理中。请注意,整数纹理应使用整数采样器(isampler2D
)进行采样,它返回整数向量(即ivec3
)。
此纹理可以附加到帧缓冲区对象(注意帧缓冲区完整性)。帧缓冲区附件可以绑定到整数输出变量:
out int fragmentObjectId;
void main() {
fragmentObjectId = vertedObjectId;
}
您需要一些扩展支持,或高级 OpenGL 版本(3.2?)。