从texture()切换到texelFetch()

6

目前我使用texture(...)函数读取3D纹理,代码如下:

vec3 value = texture(texture_3D, coord).rgb

现在我想改用texelFetch(texture_3D, coord, 0).xyz来读取纹理,但我不知道如何转换我的坐标以使其与texelFetch兼容。我的纹理大小为256x256x256

当前的坐标计算方法如下:

vec3 min_box = vec3(-0.5);
vec3 max_box = vec3(0.5);

vec3 coord = worldToVolume(world_pos, min_box, max_box)

vec3 worldToVolume(world_pos, min_box, max_box) {
     return (world_pos - min_box) / (max_box - min_box)
}

有什么想法吗?如果需要更多信息,请询问,我会提供的。
2个回答

12
这两个函数处理不同的参数并执行不同的任务。 texture 期望 [0,1] 范围内的标准化浮点纹理坐标 (例如,0 为左/下,1 为右/上),并根据设置的采样模式执行适当的包装(因此坐标不一定在 [0,1] 内)和过滤(因此您可能无法获得精确的纹素颜色)。
另一方面,texelFetch 期望 [0,width-1] 范围内的整数纹素索引(对于 y 和 z 分别是高度/深度),不执行任何过滤或包装,并访问指定 mipmap 级别中指定索引处的确切纹素值。
因此,texelFetch(texture_3D, ivec3(coord * vec3(256.0), 0) 应该等效于 texture(texture_3D, coord)使用GL_NEAREST的过滤模式和GL_CLAMP_TO_EDGE的包装模式。但是,请记住,在coord 正好为1.0 或处于纹素边界的情况下可能会出现四舍五入问题,因此也许更安全的做法是使用texelFetch(texture_3D, ivec3(coord * vec3(255.0) + vec3(0.5), 0)
但是,与其用这种方式改变它,不如保持当前纹理访问并使用GL_NEAREST过滤器。如果您已经具有整数纹素坐标并已经知道纹理大小,则更有用。以这种方式模拟最近的过滤不会带来任何好处。这基本上是两种概念上不同的方法,一种使用大小无关的浮点坐标过滤纹理,另一种使用整数索引访问3D数组。哪种方法更适合您的用例取决于周围的代码。

如果我使用texelFetch选项而不是texture(),有什么大的区别呢?当使用texelFetch时,我不必关心是否使用GL_NEARESTGL_LINEAR - user4911648
1
其实,就像所说的那样,两者并没有太大区别,完全取决于你想做什么以及你所拥有的信息。如果您的坐标已经是整数并且在适当的范围内,那么使用texelFetch是一个不错的选择。如果您具有归一化浮点纹理坐标,并且必须显式知道纹理大小(或使用textureSize进行查询),那么这似乎是一种糟糕的方法。一种方法是您不必关心过滤,而另一种方法是您不必关心纹理大小。哪种更方便就用哪个吧。 - Christian Rau

4

在使用了worldToVolume之后,您的坐标似乎在[0,1]的范围内。由于texelFetch需要整数纹素坐标而不是规范化的纹理坐标,因此必须乘以纹理大小:

vec3 coord = worldToVolume(world_pos, min_box, max_box);
ivec3 texel_fetch_coord = ivec3(coord * vec3(256, 256, 256));

请注意,在着色器中可以使用textureSize方法查询纹理的尺寸(如果纹理不总是相同大小)。


3
确切地说,“texelFetch”要求使用整数纹理坐标。 - Ripi2
@Ripi2:你说得完全正确,我已经更新了答案 :) - BDL

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