Switching from texture() to texelFetch()
Asked Answered
W

2

6

Currently I read a 3D texture with the function texture(...) like this:

vec3 value = texture(texture_3D, coord).rgb

What I want to do now is:

vec3 value = texelFetch(texture_3D, coord, 0).xyz

However, I do not know how to convert my coordinate so that it works with texelFetch. My texture is of size 256x256x256

And my current coordinate calculation is as follows:

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)
}

Any ideas? If you need more information please ask and I will provide it.

Whydah answered 10/8, 2017 at 12:7 Comment(0)
G
12

Those two functions perform quite different tasks on quite different arguments.

texture expects normalized floating point texture coordinates in [0,1] (i.e. 0 being left/bottom and 1 being right/top) and performs proper wrapping (so the coordinates don't necessarily have to be in [0,1]) and filtering (so you don't necessarily get the exact texel color) according to whatever sampling modes you set.

texelFetch on the other hand expects integer texel indices in [0,width-1] (and respectively height/depth for y and z) and doesn't perform any kind of filtering or wrapping, accessing the exact texel value at the specified index in a specified mipmap level.

So texelFetch(texture_3D, ivec3(coord * vec3(256.0), 0) should be equivalent to texture(texture_3D, coord) with filter modes GL_NEAREST and wrapping modes GL_CLAMP_TO_EDGE. However, also keep in mind possible rounding problems in case coord is exactly 1.0 or on texel boundaries, maybe texelFetch(texture_3D, ivec3(coord * vec3(255.0) + vec3(0.5), 0) might be advisable to be more secure in that regard.

However, just changing it this way seems a rather useless aproach compared to simply keeping your current texture access with a GL_NEAREST filter. It is more useful if you already have integer texel coordinates and already know the texture size. Just emulating nearest filtering this way won't really buy you anything. It's basically two conceptually different approaches, one filters a texture with size-independent floating point coordinates and the other one accesses a 3D-array with integer indices. It depends on your surrounding code which approach is more appropriate for your use case.

Gregoire answered 10/8, 2017 at 12:29 Comment(2)
What is the big difference, if I just the texelFetch option rather than texture(). When using texelFetch I do not have to care whether I use GL_NEAREST or GL_LINEAR?Whydah
Well, there isn't much of a difference, as said. It depends entirely on what you want to do and what information you got. That's all. If your coordinates are already integers and in the proper range anyway, then texelFetch is a good idea. If you have normalized foating point texture coordinates and would have to know the texture size (or query it with textureSize) explicitly, then it seems like a bad approach. One way you don't have to care about filtering, he other way you don't have to care about the texture size. Whatever's more convenient to you.Gregoire
G
4

After worldToVolume your coordinates seem to be in the [0, 1] range. Since texelFetch requires integer texel coordinates instead of normalized texture coordinates, one has to multiply with the texture size:

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

Note, that you can query the size of a texture inside the shader (in case the texture is not always of the same size) by using the textureSize method.

Gomel answered 10/8, 2017 at 12:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.