OpenGL 无绑定纹理:绑定到统一的 sampler2D 数组

OpenGL Bindless Textures: Bind to uniform sampler2D array

我正在研究使用无绑定纹理来快速显示一系列图像。我的参考资料是 OpenGL 4.5 红皮书。这本书说我可以使用这个片段着色器在着色器中采样无绑定纹理:

#version 450 core
#extension GL_ARB_bindless_texture : require

in FS_INPUTS {
   vec2 i_texcoord;
   flat int i_texindex;
};

layout (binding = 0) uniform ALL_TEXTURES {
   sampler2D fs_textures[200];
};

out vec4 color;

void main(void) {
   color = texture(fs_textures[i_texindex], i_texcoord);
};

我创建了一个如下所示的顶点着色器:

#version 450 core

in vec2 vert;
in vec2 texcoord;
uniform int texindex;

out FS_INPUTS {
   vec2 i_texcoord;
   flat int i_texindex;
} tex_data;

void main(void) {
   tex_data.i_texcoord = texcoord;
   tex_data.i_texindex = texindex;
   gl_Position = vec4(vert.x, vert.y, 0.0, 1.0);
};

你可能注意到了,我对正在发生的事情的把握有点弱。

在我的 OpenGL 代码中,我创建了一堆纹理,获取它们的句柄,并使它们常驻。我用来获取纹理句柄的函数是 'glGetTextureHandleARB'。还有另一个可以使用的函数,'glGetTextureSamplerHandleARB' 我可以在其中传递采样器位置。这是我所做的:

Texture* textures = new Texture[load_limit];
GLuint64* tex_handles = new GLuint64[load_limit];

for (int i=0; i<load_limit; ++i)
{
    textures[i].bind();
    textures[i].data(new CvImageFile(image_names[i]));
    tex_handles[i] = glGetTextureHandleARB(textures[i].id());
    glMakeTextureHandleResidentARB(tex_handles[i]);
    textures[i].unbind();
}

我的问题是如何将纹理句柄绑定到片段着色器的 ALL_TEXTURES uniform 属性?另外,我应该使用什么来更新顶点属性 'texindex' - 我的纹理句柄数组或纹理句柄的实际索引?

它是无束缚纹理。你不要"bind"这样的纹理。

bindless texturing中,采样器的数据值为一个数字。具体来说,就是 glGetTextureHandleARB 返回的数字。纹理句柄是 64 位无符号整数。

在着色器中,buffer-backed interface blocks(UBO 和 SSBO)中 sampler 类型的值是 64 位无符号整数。因此,采样器数组在结构上等同于 64 位无符号整数数组。

所以在 C++ 中,与 ALL_TEXTURES 块等效的结构将是:

struct AllTextures
{
    GLuint64 textures[200];
};

当然,前提是您正确使用 std140 布局。否则,您必须查询结构的布局。

此时,您将缓冲区视为与任何其他 UBO 用法没有区别。通过将 AllTextures 粘贴到缓冲区对象中来为着色器构建数据,然后将该缓冲区作为 UBO 绑定到绑定 0。您只需要用实际的纹理句柄填充数组。

Also, what should I use to update the vertex attribute 'texindex' - an actual index into my texture handle array or a texture handle?

好吧,两者都行不通。不是你写的那样。

见,ARB_bindless_texture does not allow you to access any texture you want in any way at any time from any shader invocation. Unless you are using NV_gpu_shader5, the code leading to the texture access must be based on dynamically uniform expressions

所以除非渲染命令中的每个顶点都获得相同的索引或句柄...您不能使用它们来选择要使用的纹理。即使实例化也救不了你,因为动态统一表达式不关心实例化。

如果您想渲染一堆四边形而不必更改它们之间的制服(并且不必依赖 NVIDIA 扩展),那么您有几个选择。大多数支持无绑定纹理的硬件也支持 ARB_shader_draw_parameters. This gives you access to gl_DrawID, which represents the current index of a rendering command within a glMultiDraw-style command。该扩展明确声明 gl_DrawID 是动态统一的。

因此您可以使用它来 select 要渲染的纹理。您只需要发出一个多次绘制命令,在其中一遍又一遍地渲染相同的网格数据,但在每种情况下它都会获得不同的 gl_DrawID 索引。