GLSL:寻址通过 TEXTURE_BUFFER 加载的 2D 纹理的像素
GLSL : Adressing pixel of a 2D texture loaded via TEXTURE_BUFFER
我正在做一些测试以通过 GL_TEXTURE_BUFFER 加载图像。我坚持正确地从 texelFetch 寻址像素。目标是只显示 R8 纹理。
下面是我创建缓冲区的方法:
sz = width*height*sizeof(uint8)
glGenBuffers( 1, &pbo );
glBindBuffer( GL_TEXTURE_BUFFER, pbo );
glBufferStorage( GL_TEXTURE_BUFFER, sz, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT |GL_MAP_COHERENT_BIT );
我是通过memcpy上传的,数据是uint8
最后我 link 它到 GL_TEXTURE_BUFFER 纹理
glBindTexture( GL_TEXTURE_BUFFER, texture );
glTexBuffer( GL_TEXTURE_BUFFER, GL_R8, pbo );
在这一步,我只是画了一个简单的矩形,并将 uv 坐标传递给片段着色器
绘制函数是:
尺寸显然是640*480
uniform samplerBuffer texture;
in vec2 uv;
...
float f;
f = 640. * 480. * (uv.y) + 640. * (uv.x);
index = int(f);
color.r = texelFetch( texture, index )[0];
我试图规范化 color.r ( / 255.f ) 但没有任何效果。奇怪的行为是,如果我修改 window 的几何形状,着色器输出会不断变化,并且在某些特定维度上我可以看到纹理。我不明白,因为我的 uv 坐标没有改变(常规 0,1 1,1 ... 对于简单的四边形)。
我的索引计算不正确,这就是为什么我想知道是否有人可以指出问题所在。
(我已经用常规 GL_TEXTURE_2D a GL_PIXEL_UNPACK_BUFFER、sampler2D 测试了着色器,没有问题)
编辑 1:
我试过将图像尺寸作为 uv 坐标传递。
uv_min = {0,0}
uv_max = {640,480}
并将片段中的索引计算为:
int index = int( 640.*uv.y + 640.*uv.x)
失败。
您的 2D 到 1D 索引计算已关闭:
float f;
f = 640. * 480. * (uv.y) + 640. * (uv.x);
index = int(f);
假设一个 640x480 像素的图像,并且在 [0,1]
中归一化纹理坐标,正确的方法需要是
int index = 640 * int(480 * uv.y) + int(640 * uv.x);
The strang behaviour is that if i modyfy the geometry of the window, the shader output change constantly and at some specific dimension i can see the texture.
你的 640. * 480. * (uv.y)
将结束在行之间的任意像素上,而不是在行的开头,除非 uv.y
恰好落在 1/480
的整数倍,这取决于您在采样期间应用的重新缩放因子。
此外,根据您的评论:
Correct me if i am wrong but as far i know on GL, when i use a PIXEL_UNPACK_BUFFER
, and update the texture, the buffer is copied to the real texture memory block, i want to skip this copy by using a texture buffer.
从技术上讲,这是正确的,但它缺少大局。 PBO 是异步更新纹理/纹理流的好方法。
改为使用 TBO,您确实绕过了该副本,但从 GPU 采样时也绕过了 GPU 上的 TMU 硬件单元,这意味着您完全松开了所有纹理过滤器和环绕模式等。
此外,2D 纹理不会像在 TexImage
(以及此处的 TBO)的输入缓冲区中那样以线性方式存储,而是以平铺和混合格式存储以优化缓存采样时命中。通过完全绕过纹理功能,您实际采样数据的成本实际上会更高,并且您的性能不一定会更高。
TBO 并非真正用于纹理数据,它们用于访问任意缓冲区数据不 适合纹理(并且比 UBO 允许的更大),基本上,它们是在现代 GL 中完全被 SSBO 取代。
我正在做一些测试以通过 GL_TEXTURE_BUFFER 加载图像。我坚持正确地从 texelFetch 寻址像素。目标是只显示 R8 纹理。
下面是我创建缓冲区的方法:
sz = width*height*sizeof(uint8)
glGenBuffers( 1, &pbo );
glBindBuffer( GL_TEXTURE_BUFFER, pbo );
glBufferStorage( GL_TEXTURE_BUFFER, sz, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT |GL_MAP_COHERENT_BIT );
我是通过memcpy上传的,数据是uint8
最后我 link 它到 GL_TEXTURE_BUFFER 纹理
glBindTexture( GL_TEXTURE_BUFFER, texture );
glTexBuffer( GL_TEXTURE_BUFFER, GL_R8, pbo );
在这一步,我只是画了一个简单的矩形,并将 uv 坐标传递给片段着色器 绘制函数是:
尺寸显然是640*480
uniform samplerBuffer texture;
in vec2 uv;
...
float f;
f = 640. * 480. * (uv.y) + 640. * (uv.x);
index = int(f);
color.r = texelFetch( texture, index )[0];
我试图规范化 color.r ( / 255.f ) 但没有任何效果。奇怪的行为是,如果我修改 window 的几何形状,着色器输出会不断变化,并且在某些特定维度上我可以看到纹理。我不明白,因为我的 uv 坐标没有改变(常规 0,1 1,1 ... 对于简单的四边形)。
我的索引计算不正确,这就是为什么我想知道是否有人可以指出问题所在。
(我已经用常规 GL_TEXTURE_2D a GL_PIXEL_UNPACK_BUFFER、sampler2D 测试了着色器,没有问题)
编辑 1:
我试过将图像尺寸作为 uv 坐标传递。
uv_min = {0,0}
uv_max = {640,480}
并将片段中的索引计算为:
int index = int( 640.*uv.y + 640.*uv.x)
失败。
您的 2D 到 1D 索引计算已关闭:
float f; f = 640. * 480. * (uv.y) + 640. * (uv.x); index = int(f);
假设一个 640x480 像素的图像,并且在 [0,1]
中归一化纹理坐标,正确的方法需要是
int index = 640 * int(480 * uv.y) + int(640 * uv.x);
The strang behaviour is that if i modyfy the geometry of the window, the shader output change constantly and at some specific dimension i can see the texture.
你的 640. * 480. * (uv.y)
将结束在行之间的任意像素上,而不是在行的开头,除非 uv.y
恰好落在 1/480
的整数倍,这取决于您在采样期间应用的重新缩放因子。
此外,根据您的评论:
Correct me if i am wrong but as far i know on GL, when i use a
PIXEL_UNPACK_BUFFER
, and update the texture, the buffer is copied to the real texture memory block, i want to skip this copy by using a texture buffer.
从技术上讲,这是正确的,但它缺少大局。 PBO 是异步更新纹理/纹理流的好方法。
改为使用 TBO,您确实绕过了该副本,但从 GPU 采样时也绕过了 GPU 上的 TMU 硬件单元,这意味着您完全松开了所有纹理过滤器和环绕模式等。
此外,2D 纹理不会像在 TexImage
(以及此处的 TBO)的输入缓冲区中那样以线性方式存储,而是以平铺和混合格式存储以优化缓存采样时命中。通过完全绕过纹理功能,您实际采样数据的成本实际上会更高,并且您的性能不一定会更高。
TBO 并非真正用于纹理数据,它们用于访问任意缓冲区数据不 适合纹理(并且比 UBO 允许的更大),基本上,它们是在现代 GL 中完全被 SSBO 取代。