Fix Cycles volume render differences with NanoVDB when using linear sampling
The NanoVDB sampling implementation behaves different from dense texture sampling, so this adds a small offset to the voxel indices to correct for that. Also removes the need to modify the sampling coordinates by moving all the necessary transformations into the image transform. See also T81454.
This commit is contained in:
parent
43ceb0f047
commit
fd9124ed6b
Notes:
blender-bot
2023-02-14 10:37:49 +01:00
Referenced by issue #81454, Cycles: enable NanoVDB by default
|
@ -490,21 +490,17 @@ template<typename T> struct NanoVDBInterpolator {
|
|||
static ccl_always_inline float4
|
||||
interp_3d(const TextureInfo &info, float x, float y, float z, InterpolationType interp)
|
||||
{
|
||||
const nanovdb::Vec3f xyz(x, y, z);
|
||||
nanovdb::NanoGrid<T> *const grid = (nanovdb::NanoGrid<T> *)info.data;
|
||||
const nanovdb::NanoRoot<T> &root = grid->tree().root();
|
||||
|
||||
const nanovdb::Coord off(root.bbox().min());
|
||||
const nanovdb::Coord dim(root.bbox().dim());
|
||||
const nanovdb::Vec3f xyz(off[0] + x * dim[0], off[1] + y * dim[1], off[2] + z * dim[2]);
|
||||
|
||||
typedef nanovdb::ReadAccessor<nanovdb::NanoRoot<T>> ReadAccessorT;
|
||||
switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
|
||||
default:
|
||||
case INTERPOLATION_LINEAR:
|
||||
return read(nanovdb::SampleFromVoxels<ReadAccessorT, 1, false>(root)(xyz));
|
||||
case INTERPOLATION_CLOSEST:
|
||||
return read(nanovdb::SampleFromVoxels<ReadAccessorT, 0, false>(root)(xyz));
|
||||
case INTERPOLATION_CUBIC:
|
||||
case INTERPOLATION_LINEAR:
|
||||
return read(nanovdb::SampleFromVoxels<ReadAccessorT, 1, false>(root)(xyz));
|
||||
default:
|
||||
return read(nanovdb::SampleFromVoxels<ReadAccessorT, 3, false>(root)(xyz));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,21 +130,17 @@ template<typename T>
|
|||
ccl_device_inline T kernel_tex_image_interp_nanovdb(
|
||||
const TextureInfo &info, float x, float y, float z, uint interpolation)
|
||||
{
|
||||
const nanovdb::Vec3f xyz(x, y, z);
|
||||
nanovdb::NanoGrid<T> *const grid = (nanovdb::NanoGrid<T> *)info.data;
|
||||
const nanovdb::NanoRoot<T> &root = grid->tree().root();
|
||||
|
||||
const nanovdb::Coord off(root.bbox().min());
|
||||
const nanovdb::Coord dim(root.bbox().dim());
|
||||
const nanovdb::Vec3f xyz(off[0] + x * dim[0], off[1] + y * dim[1], off[2] + z * dim[2]);
|
||||
|
||||
typedef nanovdb::ReadAccessor<nanovdb::NanoRoot<T>> ReadAccessorT;
|
||||
switch (interpolation) {
|
||||
default:
|
||||
case INTERPOLATION_LINEAR:
|
||||
return nanovdb::SampleFromVoxels<ReadAccessorT, 1, false>(root)(xyz);
|
||||
case INTERPOLATION_CLOSEST:
|
||||
return nanovdb::SampleFromVoxels<ReadAccessorT, 0, false>(root)(xyz);
|
||||
case INTERPOLATION_CUBIC:
|
||||
case INTERPOLATION_LINEAR:
|
||||
return nanovdb::SampleFromVoxels<ReadAccessorT, 1, false>(root)(xyz);
|
||||
default:
|
||||
return nanovdb::SampleFromVoxels<ReadAccessorT, 3, false>(root)(xyz);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,32 +229,29 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float3 P
|
|||
uint interpolation = (interp == INTERPOLATION_NONE) ? info->interpolation : interp;
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
cnanovdb_Vec3F xyz;
|
||||
xyz.mVec[0] = x;
|
||||
xyz.mVec[1] = y;
|
||||
xyz.mVec[2] = z;
|
||||
|
||||
if (info->data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) {
|
||||
ccl_global cnanovdb_griddata *grid =
|
||||
(ccl_global cnanovdb_griddata *)(kg->buffers[info->cl_buffer] + info->data);
|
||||
const ccl_global cnanovdb_rootdataF *root = cnanovdb_treedata_rootF(
|
||||
cnanovdb_griddata_tree(grid));
|
||||
|
||||
cnanovdb_Vec3F xyz;
|
||||
xyz.mVec[0] = root->mBBox_min.mVec[0] +
|
||||
x * (root->mBBox_max.mVec[0] - root->mBBox_min.mVec[0]);
|
||||
xyz.mVec[1] = root->mBBox_min.mVec[1] +
|
||||
y * (root->mBBox_max.mVec[1] - root->mBBox_min.mVec[1]);
|
||||
xyz.mVec[2] = root->mBBox_min.mVec[2] +
|
||||
z * (root->mBBox_max.mVec[2] - root->mBBox_min.mVec[2]);
|
||||
|
||||
cnanovdb_readaccessor acc;
|
||||
cnanovdb_readaccessor_init(&acc, root);
|
||||
|
||||
float value;
|
||||
switch (interpolation) {
|
||||
case INTERPOLATION_CLOSEST:
|
||||
value = cnanovdb_sampleF_nearest(&acc, &xyz);
|
||||
break;
|
||||
default:
|
||||
case INTERPOLATION_LINEAR:
|
||||
value = cnanovdb_sampleF_trilinear(&acc, &xyz);
|
||||
break;
|
||||
case INTERPOLATION_CLOSEST:
|
||||
value = cnanovdb_sampleF_nearest(&acc, &xyz);
|
||||
break;
|
||||
}
|
||||
return make_float4(value, value, value, 1.0f);
|
||||
}
|
||||
|
@ -264,14 +261,6 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float3 P
|
|||
const ccl_global cnanovdb_rootdataF3 *root = cnanovdb_treedata_rootF3(
|
||||
cnanovdb_griddata_tree(grid));
|
||||
|
||||
cnanovdb_Vec3F xyz;
|
||||
xyz.mVec[0] = root->mBBox_min.mVec[0] +
|
||||
x * (root->mBBox_max.mVec[0] - root->mBBox_min.mVec[0]);
|
||||
xyz.mVec[1] = root->mBBox_min.mVec[1] +
|
||||
y * (root->mBBox_max.mVec[1] - root->mBBox_min.mVec[1]);
|
||||
xyz.mVec[2] = root->mBBox_min.mVec[2] +
|
||||
z * (root->mBBox_max.mVec[2] - root->mBBox_min.mVec[2]);
|
||||
|
||||
cnanovdb_readaccessor acc;
|
||||
cnanovdb_readaccessor_init(&acc, root);
|
||||
|
||||
|
|
|
@ -144,8 +144,13 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
|
|||
}
|
||||
}
|
||||
|
||||
# ifdef WITH_NANOVDB
|
||||
/* Add small offset for correct sampling between voxels. */
|
||||
Transform texture_to_index = transform_translate(0.5f, 0.5f, 0.5f);
|
||||
# else
|
||||
Transform texture_to_index = transform_translate(min.x(), min.y(), min.z()) *
|
||||
transform_scale(dim.x(), dim.y(), dim.z());
|
||||
# endif
|
||||
|
||||
metadata.transform_3d = transform_inverse(index_to_object * texture_to_index);
|
||||
metadata.use_transform_3d = true;
|
||||
|
@ -159,10 +164,10 @@ bool VDBImageLoader::load_metadata(ImageMetaData &metadata)
|
|||
|
||||
bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size_t, const bool)
|
||||
{
|
||||
#if defined(WITH_NANOVDB)
|
||||
#ifdef WITH_OPENVDB
|
||||
# ifdef WITH_NANOVDB
|
||||
memcpy(pixels, nanogrid.data(), nanogrid.size());
|
||||
return true;
|
||||
#elif defined(WITH_OPENVDB)
|
||||
# else
|
||||
if (grid->isType<openvdb::FloatGrid>()) {
|
||||
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
|
||||
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid), dense);
|
||||
|
@ -202,7 +207,7 @@ bool VDBImageLoader::load_pixels(const ImageMetaData &, void *pixels, const size
|
|||
openvdb::tools::Dense<float, openvdb::tools::LayoutXYZ> dense(bbox, (float *)pixels);
|
||||
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<openvdb::MaskGrid>(grid), dense);
|
||||
}
|
||||
|
||||
# endif
|
||||
return true;
|
||||
#else
|
||||
(void)pixels;
|
||||
|
|
|
@ -324,8 +324,13 @@ float Object::compute_volume_step_size() const
|
|||
|
||||
if (voxel_step_size == 0.0f) {
|
||||
/* Auto detect step size. */
|
||||
float3 size = make_float3(
|
||||
1.0f / metadata.width, 1.0f / metadata.height, 1.0f / metadata.depth);
|
||||
float3 size = make_float3(1.0f, 1.0f, 1.0f);
|
||||
#ifdef WITH_NANOVDB
|
||||
/* Dimensions were not applied to image transform with NanOVDB (see image_vdb.cpp) */
|
||||
if (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
|
||||
metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3)
|
||||
#endif
|
||||
size /= make_float3(metadata.width, metadata.height, metadata.depth);
|
||||
|
||||
/* Step size is transformed from voxel to world space. */
|
||||
Transform voxel_tfm = tfm;
|
||||
|
|
Loading…
Reference in New Issue