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

vin*_*ent 2 opengl textures glsl

我正在研究使用无绑定纹理来快速显示一系列图像.我的参考是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);
};
Run Code Online (Sandbox Code Playgroud)

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

#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);
};
Run Code Online (Sandbox Code Playgroud)

正如您可能注意到的那样,我对最新情况的了解有点微弱.

在我的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();
}
Run Code Online (Sandbox Code Playgroud)

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

Nic*_*las 8

这是无约束的纹理.你没有将这些纹理"绑定"到任何东西上.

在无绑定纹理中,采样器的数据值是一个数字.具体来说,返回的数字glGetTextureHandleARB.纹理句柄是64位无符号整数.

在着色器中,缓冲区支持的接口块(UBO和SSBO)中的sampler类型值是64位无符号整数.因此,采样器数组在结构上等同于64位无符号整数数组.

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

struct AllTextures
{
    GLuint64 textures[200];
};
Run Code Online (Sandbox Code Playgroud)

好吧,假设您正确使用std140布局,当然.否则,您必须查询结构的布局.

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

另外,我应该使用什么来更新顶点属性'texindex' - 我的纹理句柄数组或纹理句柄的实际索引?

好吧,两个人都不会工作.不是你写的方式.

请参阅,ARB_bindless_texture不允许您在任何着色器调用中随时以任何方式访问任何所需的纹理.除非您使用NV_gpu_shader5,否则导致纹理访问的代码必须基于动态统一表达式.

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

如果你想渲染一堆四边形而不必更改它们之间的制服(并且不必依赖NVIDIA扩展),那么你有几个选择.大多数支持无绑定纹理的硬件也支持ARB_shader_draw_parameters.这使您可以访问gl_DrawID,它代表了渲染指令的当前索引一个内glMultiDraw风格的命令.并且该扩展明确声明它gl_DrawID是动态统一的.

因此,您可以使用它来选择要渲染的纹理.您只需要发出一个多绘制命令,您可以反复渲染相同的网格数据,但gl_DrawID在每种情况下都会获得不同的索引.