从 texture() 切换到 texelFetch()
Switching from texture() to texelFetch()
目前我使用函数 texture(...)
读取 3D 纹理,如下所示:
vec3 value = texture(texture_3D, coord).rgb
我现在要做的是:
vec3 value = 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)
}
有什么想法吗?如果您需要更多信息,请询问,我会提供。
在 worldToVolume
之后,您的坐标似乎在 [0, 1] 范围内。由于 texelFetch
需要整数纹素坐标而不是归一化纹理坐标,因此必须乘以纹理大小:
vec3 coord = worldToVolume(world_pos, min_box, max_box);
ivec3 texel_fetch_coord = ivec3(coord * vec3(256, 256, 256));
请注意,您可以使用 textureSize
方法查询着色器内部纹理的大小(以防纹理的大小不总是相同)。
这两个函数根据完全不同的参数执行完全不同的任务。
texture
期望在 [0,1] 中 归一化浮点纹理坐标(即 0 为 left/bottom,1 为 right/top)并根据您设置的任何采样模式执行适当的包装(因此坐标不一定必须在 [0,1] 中)和过滤(因此您不一定获得确切的纹素颜色)。
另一方面,texelFetch
期望 [0,width-1] 中的 整数纹素索引(y 和 z 分别为 height/depth)和不执行任何类型的过滤或包装,在指定的 mipmap 级别访问指定索引处的确切纹素值。
所以 texelFetch(texture_3D, ivec3(coord * vec3(256.0), 0)
应该等同于 texture(texture_3D, coord)
with 过滤模式 GL_NEAREST
和环绕模式 GL_CLAMP_TO_EDGE
。但是,还要记住可能存在的舍入问题,以防坐标正好是 1.0
或在纹素边界上,也许 texelFetch(texture_3D, ivec3(coord * vec3(255.0) + vec3(0.5), 0)
在这方面更安全是可取的。
但是,与仅使用 GL_NEAREST
过滤器保持当前纹理访问相比,仅以这种方式更改它似乎是一种相当无用的方法。如果您已经有整数纹素坐标并且已经知道纹理大小,它会更有用。仅以这种方式模拟最近的过滤不会真正给您带来任何好处。它基本上是两种概念上不同的方法,一种使用与大小无关的浮点坐标过滤纹理,另一种使用整数索引访问 3D 数组。这取决于您周围的代码,哪种方法更适合您的用例。
目前我使用函数 texture(...)
读取 3D 纹理,如下所示:
vec3 value = texture(texture_3D, coord).rgb
我现在要做的是:
vec3 value = 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)
}
有什么想法吗?如果您需要更多信息,请询问,我会提供。
在 worldToVolume
之后,您的坐标似乎在 [0, 1] 范围内。由于 texelFetch
需要整数纹素坐标而不是归一化纹理坐标,因此必须乘以纹理大小:
vec3 coord = worldToVolume(world_pos, min_box, max_box);
ivec3 texel_fetch_coord = ivec3(coord * vec3(256, 256, 256));
请注意,您可以使用 textureSize
方法查询着色器内部纹理的大小(以防纹理的大小不总是相同)。
这两个函数根据完全不同的参数执行完全不同的任务。
texture
期望在 [0,1] 中 归一化浮点纹理坐标(即 0 为 left/bottom,1 为 right/top)并根据您设置的任何采样模式执行适当的包装(因此坐标不一定必须在 [0,1] 中)和过滤(因此您不一定获得确切的纹素颜色)。
texelFetch
期望 [0,width-1] 中的 整数纹素索引(y 和 z 分别为 height/depth)和不执行任何类型的过滤或包装,在指定的 mipmap 级别访问指定索引处的确切纹素值。
所以 texelFetch(texture_3D, ivec3(coord * vec3(256.0), 0)
应该等同于 texture(texture_3D, coord)
with 过滤模式 GL_NEAREST
和环绕模式 GL_CLAMP_TO_EDGE
。但是,还要记住可能存在的舍入问题,以防坐标正好是 1.0
或在纹素边界上,也许 texelFetch(texture_3D, ivec3(coord * vec3(255.0) + vec3(0.5), 0)
在这方面更安全是可取的。
但是,与仅使用 GL_NEAREST
过滤器保持当前纹理访问相比,仅以这种方式更改它似乎是一种相当无用的方法。如果您已经有整数纹素坐标并且已经知道纹理大小,它会更有用。仅以这种方式模拟最近的过滤不会真正给您带来任何好处。它基本上是两种概念上不同的方法,一种使用与大小无关的浮点坐标过滤纹理,另一种使用整数索引访问 3D 数组。这取决于您周围的代码,哪种方法更适合您的用例。