Hey Guys,
Does anyone know how linear sampler works behind the scene? especially when sampling a Texture3D object. Is it fetching 8 texels and interpolate the result? MSDN only says D3D12_FILTER_TYPE_LINEAR will return "the weighter average of a 2x2 area of texels surrounding the desired pixel" which is not super clear to me.
I tried to render a surface by raycasting through a TSDF volume (Texture3D), point sampler and my own linear 'sampler' (point sample 8 nearest voxels then interpolate) gives expected result without artifacts, while LinearSampler and AnisotropicSampler runs faster but generate artifacts(see attachments PointSampler, ManualSampler(trilinear interpolation), LinearSampler).
[attachment=33607:PointSample.PNG][attachment=33608:ManualLinearSample.PNG][attachment=33609:LinearSample.PNG]
also here is the most obvious one:
[attachment=33610:artifactPattern.PNG]
It looks clearly that this artifact related to raycast step size, but why point sampler and manual interpolation don't have this artifact? In fact I double checked, even if I make my ray cast step 10x smaller, the artifact still exist (even worse).
Also another MSDN page at the bottom part states:
During texture sampling, one or more texels are read and combined (this is calling filtering) to produce a single value. Point sampling reads a single texel while linear sampling reads two texels (endpoints) and linearly interpolates a third value between the endpoints.
So it seems samplers will never do 8 texels fetches for correct trilinear interpolation on Texture3D? (anyone?)
in case there are any problems in my manual interpolation I pasted it here:
// f3Idx range (0,0,0) - (resolution.x, resolution.y, resolution.z)
float readVolume(float3 f3Idx)
{
int3 i3Idx000;
float3 f3d = modf(f3Idx, i3Idx000) - 0.5f;
#if FILTER_READ == 1
float fV000 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000)];
float fV001 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(0, 0, 1))];
float fV010 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(0, 1, 0))];
float fV011 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(0, 1, 1))];
float fV100 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(1, 0, 0))];
float fV101 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(1, 0, 1))];
float fV110 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(1, 1, 0))];
float fV111 = tex_srvTSDFVol[BUFFER_INDEX(i3Idx000 + uint3(1, 1, 1))];
return fV000 * (1.f - f3d.x) * (1.f - f3d.y) * (1.f - f3d.z) +
fV100 * f3d.x * (1.f - f3d.y) * (1.f - f3d.z) +
fV010 * (1.f - f3d.x) * f3d.y * (1.f - f3d.z) +
fV001 * (1.f - f3d.x) * (1.f - f3d.y) * f3d.z +
fV101 * f3d.x * (1.f - f3d.y) * f3d.z +
fV011 * (1.f - f3d.x) * f3d.y * f3d.z +
fV110 * f3d.x * f3d.y * (1.f - f3d.z) +
fV111 * f3d.x * f3d.y * f3d.z;
#elif TEX3D_UAV && FILTER_READ == 2
return tex_srvTSDFVol.SampleLevel(
samp_Linear, f3Idx / vParam.u3VoxelReso, 0);
#elif TEX3D_UAV && FILTER_READ == 3
return tex_srvTSDFVol.SampleLevel(
samp_Aniso, f3Idx / vParam.u3VoxelReso, 0);
#else
return tex_srvTSDFVol[BUFFER_INDEX(i3Idx000)];
#endif // !FILTER_READ
}
So I think I probably need more information to dig into it. Also if anyone knows there exist better ways to do Volume interpolated read, please yell at me.
Thanks