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

4

我正在研究使用无绑定纹理来快速显示一系列图像。我参考的是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统一属性?另外,我应该使用什么来更新顶点属性“texindex”——实际上是一个纹理句柄数组中的索引还是纹理句柄本身?

1个回答

10

这是“无需绑定”纹理。您不需要将此类纹理绑定到任何东西上。

无需绑定的纹理中,sampler的数据值是一个数字,具体而言就是glGetTextureHandleARB返回的数字。纹理句柄是64位无符号整数。

在着色器中,sampler类型的值在缓冲区支持的接口块(UBO和SSBO)中是64位无符号整数。因此,一组sampler与一组64位无符号整数的结构等效。

因此,在C++中,与您的ALL_TEXTURES块相当的结构体如下:

struct AllTextures
{
    GLuint64 textures[200];
};
假设您正确使用了 std140 布局,那当然没问题。否则,您需要查询结构的布局。
此时,您将缓冲区视为与任何其他 UBO 用法没有区别。通过将 AllTextures 放入缓冲对象中来构建着色器数据,然后将该缓冲绑定为 UBO 绑定 0。您只需要在其中填充实际纹理句柄数组即可。
“另外,我应该使用什么来更新顶点属性'texindex' - 实际上是对纹理句柄数组的索引还是纹理句柄本身?”
好吧,你写的两种方法都不行。
请注意,ARB_bindless_texture 不允许您从任何着色器调用以任何方式访问任何想要的纹理。除非您使用 NV_gpu_shader5,用于纹理访问的代码必须基于动态均匀表达式
因此,除非渲染命令中的每个顶点获得相同的索引或句柄......否则您无法使用它们来选择要使用的纹理。即使是实例化也无法拯救您,因为动态均匀表达式不关心实例化。
如果您想渲染一堆四边形而无需在它们之间更改 uniform(并且无需依赖 NVIDIA 扩展),则有几种选择。支持绑定纹理的大多数硬件也支持ARB_shader_draw_parameters。这使您可以访问 gl_DrawID,它表示渲染命令在类似于glMultiDraw样式的命令中的当前索引。该扩展明确声明gl_DrawID是动态均匀的。
因此,您可以使用它来选择要呈现的纹理。您只需要发出一个多次绘制命令,在每种情况下,您都会重复呈现相同的网格数据,但其中的gl_DrawID索引不同即可。

1
谢谢,这非常有帮助!OpenGL 很难! - vincent
我已经成功运行了我发布的代码。我只需要像你提到的那样使用UBO来附加到ALL_TEXTURES。我仍然使用整数i_texindex来索引fs_textures。如果我遍历fs_textures,无论我加载多少纹理,只有前一半的纹理有效(50个纹理中只有25个显示出来)。另一半似乎被Linux Graphics Debugger称为“Front Left Color”或“Back Left Color”的可绘制对象所覆盖。我已确认完整的纹理数组已正确加载。我对此感到困惑!你以前见过这种情况吗? - vincent
搞定了!再次感谢你的帮助! - vincent
当你谈论无绑定统一表达式时,我有点困惑。你说我不能选择每个四边形将使用哪个纹理 - 这意味着每个四边形都必须使用相同的纹理。如果是这样,那么拥有“ALL_TEXTURES”的意义是什么? - CygnusX1
@CygnusX1:这是为了在不绑定纹理的情况下进行渲染。因此有了“无绑定”的术语。它并不意味着“永远没有状态变化”或“一次性绘制所有内容”。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接