OpenGL - TBO (Texture Buffer Object) - 缓存纹理 - Instancing Using TBO 前置篇

tech2022-09-26  105


准备尝试一下 TBO 的方式来实现 Instancing 渲染,所以提前了解一下 TBO 是什么,怎么用,是很有必要的

TBO 就是:Texture Buffer Object 的缩写,意思是:缓存纹理对象

简单的使用,可以参考如下内容

如下内容引用:OpenGL 红宝书 第9版 第6章 - 缓存纹理


缓存纹理

缓存纹理是一种特殊形式的纹理,它允许从着色器中直接访问缓存对象的内容,将它当作一个巨大的以为纹理使用。缓存纹理与一般的以为纹理相比有一些限制和不同,但是在代码中所体现出的形态是非常类似的。我们可以把它当作一般的纹理对象创建,绑定到纹理单元,并使用 glTextureParameteri() 控制它们的参数1。但是,纹理数据的存储实际上是由一个缓存对象(它必须是有名称的)来管理和控制的。此外,缓存纹理也没有内置的采样器,并且采样器对象也不会对缓存纹理产生效果。缓存纹理与一般的一维纹理相比有如下不同之处:

一维纹理的尺寸受限于 GL_MAX_TEXTURE_SIZE 对应的最大值,但是缓存纹理的尺寸受限于 GL_MAX_TEXTURE_BUFFER_SIZE 的值,通常能达到 2GB 甚至更多。一维纹理支持滤波、mipmap、纹理坐标的截取,以及其他的一些采样器参数,但是缓存纹理不行一维纹理的纹理坐标是归一化的浮点数值,但是缓存纹理使用的是没有归一化的整数纹理坐标。

我们需要根据自己的实际需求,在应用程序中选中使用缓存纹理或者一维纹理。如果要创建纹理,需要调用 glCreateTexture() 来创建纹理对象,并将 GL_TEXTURE_BUFFER 作为输入的目标参数,然后使用 glTextureBuffer() 函数将纹理与一个缓存对象关联起来。

void glTextureBuffer(GLuint texture, GLenum internalformat, GLuint buffer);

将缓存对象 buffer 的存储空间与缓存纹理 texture 进行关联。buffer 的存储数据将被视为一组数据格式为 internalformat 的元素进行解析,注意数据格式必须是有尺寸后缀的。如果 buffer 为0,那么缓存纹理 texture 中当前已经存在的关联信息将被断开,缓存数据将无法再读取。

例 6.23 是上述缓存创建、初始化数据存储,然后与一个缓存纹理进行关联的全过程示例。

例 6.23 创建和初始化缓存纹理

// 作为数据存储的缓存对象 GLuint buffer; // 作为缓存纹理使用的纹理对象 GLuint tex; // 数据应当被保存到程序内存中了 extern const GLvoid* data; // 生成、绑定和初始化缓存对象,设置绑定点为 GL_TEXTURE_BUFFER。假设这里用到的数据量是 1MB glGenBuffers(1, &buf); glBindBuffer(GL_TEXTURE_BUFFER, buf); glBufferData(GL_TEXTURE_BUFFER, 1024 * 1024, data, GL_STATIC_DRAW); // 现在创建缓存纹理对象并将它与缓存对象关联 glCreateTexture(1, GL_TEXTURE_BUFFER, &tex); glTextureBuffer(tex, GL_R32F, buf);

如果只需要关联缓存对象的一部分到缓存纹理中,需要使用 glTextureBufferRange() 函数,它的原型如下所示:

void glTextureBufferRange(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);

将缓存对象 buffer 中从 offset 开始,总共 size 字节的一部分存储区域,关联给缓存纹理 texture。buffer 的存储数据将被视为一组数据格式为 internalformat 的元素进行解析,注意数据格式必须是有尺寸后缀的。如果 buffer 为 0,那么缓存纹理 texture 中当前已经存在的关联信息将被断开,缓存数据将无法再读取。offset 必须是一个整数值,并且是系统平台所定义的常量 GL_TEXTURE_BUFFER_OFFSET_ALGINMENT 的倍数。

为了在着色器中访问缓存纹理,还需要创建一个 uniform 变量 samplerBuffer(对于有符号或者无符号整型的变量,还可以使用 isamplerBuffer 和 usamplerBuffer),然后用 texelFetch 函数2来读取单独的纹理采样数据并使用。用于缓存纹理的 texelFetch 函数的定义如下:

vec4 texelFetch(samplerBuffer s, int coord); ivec4 texelFetch(isamplerBuffer s, int coord); uvec4 texelFetch(usamplerBuffer s, int coord);

对一个单独的纹素执行查找,纹理当前绑定到 s,而纹理坐标设置为 coord。

有关声明缓存采样器并使用 texelFetch 来读取数据的过程,可以参见例 6.24。

例 6.24 从缓存纹理中查找纹素

#version 450 core layout (binding = 0) uniform samplerBuffer buf; in int buf_tex_coord; layout (location = 0) out vec4 color; void main(void) { color = texelFetch(buf, tex_coord); }

References

OpenGL 红宝书 第9版 第6章 - 缓存纹理

并不是所有的纹理参数都适用于缓存纹理,并且缓存纹理也没有采样器,因此会忽略所有的采样器参数。 ↩︎

texelFetch 函数除了用于缓存纹理,也可以用于一般的纹理。如果我们用它来采样一个非缓存纹理,那么纹理的采样器参数将被忽略,并且纹理坐标在这里会被视为一个没有经过归一化的整数数值(这一点与缓存纹理的用法相同)。我们选择在这里单独介绍这个函数,是因为它是使用缓存纹理时最常用到的。 ↩︎

最新回复(0)