Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions devices/rtx/device/gpu/shadingState.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ struct NvdbRegularSamplerState
const GridType *grid;
AccessorType accessor;
SamplerType sampler;
nanovdb::Vec3f offset;
nanovdb::Vec3f offsetDown;
nanovdb::Vec3f offsetUp;
nanovdb::Vec3f scale;
nanovdb::Vec3f indexMin;
nanovdb::Vec3f indexMax;
Expand All @@ -178,8 +179,10 @@ struct NvdbRectilinearSamplerState
const GridType *grid;
AccessorType accessor;
SamplerType sampler;
nanovdb::Vec3f offset;
nanovdb::Vec3f scale;
nanovdb::Vec3f offsetDown;
nanovdb::Vec3f offsetUp;
nanovdb::Vec3f scaleDown;
nanovdb::Vec3f scaleUp;
nanovdb::Vec3f indexMin;
nanovdb::Vec3f indexMax;
cudaTextureObject_t axisLUT[3];
Expand Down
65 changes: 29 additions & 36 deletions devices/rtx/device/spatial_field/NvdbRectilinearSampler_ptx.cu
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <driver_types.h>
#include <nanovdb/math/Math.h>
#include "gpu/gpu_decl.h"
#include "gpu/gpu_objects.h"
#include "gpu/shadingState.h"
Expand Down Expand Up @@ -61,19 +63,25 @@ VISRTX_DEVICE void initNvdbRectilinearSampler(
typename NvdbRectilinearSamplerState<ValueType>::SamplerType(
nanovdb::math::createSampler<1>(state.accessor));

const bool cellCentered = field->data.nvdbRectilinear.cellCentered;
const nanovdb::CoordBBox indexBBox = grid->indexBBox();
const nanovdb::Vec3f dims = nanovdb::Vec3f(indexBBox.dim());
state.indexMin = indexBBox.min().asVec3d();
state.indexMax = indexBBox.max().asVec3d();

if (cellCentered) {
state.offset = nanovdb::Vec3f(-0.5f);
state.scale = nanovdb::Vec3f(1.0f);
// NanoVDB samplers get exact values at 0, 1, ... N, which works for
// node centered data. For cell centered data, we need to offset by -0.5
// and clamp to artificially create the full voxel, extrapolating the
// outermost voxel values.
// ScaleDown moves from index space to normalized space [0, 1]
// ScaleUp moves from normalized space [0, 1] to index space - 1
state.scaleDown = 1.0f / dims;
state.scaleUp = dims - nanovdb::Vec3f(1.0f);
state.offsetDown = -nanovdb::Vec3f(indexBBox.min());
if (field->data.nvdbRectilinear.cellCentered) {
state.offsetUp = nanovdb::Vec3f(-0.5f) - state.offsetDown;
} else {
state.offset = nanovdb::Vec3f(0.0f);
state.scale = (dims - nanovdb::Vec3f(1.0f)) / dims;
state.offsetUp = -state.offsetDown;
}
state.indexMin = nanovdb::Vec3f(indexBBox.min());
state.indexMax = nanovdb::Vec3f(indexBBox.max());

state.axisLUT[0] = field->data.nvdbRectilinear.axisLUT[0];
state.axisLUT[1] = field->data.nvdbRectilinear.axisLUT[1];
Expand All @@ -84,37 +92,22 @@ template <typename ValueType>
VISRTX_DEVICE float sampleNvdbRectilinear(
const NvdbRectilinearSamplerState<ValueType> &state, const vec3 *location)
{
nanovdb::Vec3f samplePos(location->x, location->y, location->z);

// Apply rectilinear mapping to samplePosition
if (state.axisLUT[0]) {
samplePos[0] -= state.indexMin[0];
samplePos[0] /= (state.indexMax[0] - state.indexMin[0]);
samplePos[0] = tex1D<float>(state.axisLUT[0], samplePos[0]);
samplePos[0] *= (state.indexMax[0] - state.indexMin[0]);
samplePos[0] += state.indexMin[0];
}
if (state.axisLUT[1]) {
samplePos[1] -= state.indexMin[1];
samplePos[1] /= (state.indexMax[1] - state.indexMin[1]);
samplePos[1] = tex1D<float>(state.axisLUT[1], samplePos[1]);
samplePos[1] *= (state.indexMax[1] - state.indexMin[1]);
samplePos[1] += state.indexMin[1];
}
if (state.axisLUT[2]) {
samplePos[2] -= state.indexMin[2];
samplePos[2] /= (state.indexMax[2] - state.indexMin[2]);
samplePos[2] = tex1D<float>(state.axisLUT[2], samplePos[2]);
samplePos[2] *= (state.indexMax[2] - state.indexMin[2]);
samplePos[2] += state.indexMin[2];
}
const auto indexPos0 = state.grid->worldToIndexF(
nanovdb::Vec3f(location->x, location->y, location->z));

// Recenter and normalize
const auto normalizedPos = (indexPos0 - state.offsetDown) * state.scaleDown;

auto indexPos = state.grid->worldToIndexF(samplePos);
// Apply rectilinear mapping
const auto normalizedPosRect =
nanovdb::Vec3f(tex1D<float>(state.axisLUT[0], normalizedPos[0]),
tex1D<float>(state.axisLUT[1], normalizedPos[1]),
tex1D<float>(state.axisLUT[2], normalizedPos[2]));

indexPos = indexPos * state.scale + state.offset;
indexPos = clamp(indexPos, state.indexMin, state.indexMax);
// Back to index space
const auto indexPos = normalizedPosRect * state.scaleUp + state.offsetUp;

return state.sampler(indexPos);
return state.sampler(clamp(indexPos, state.indexMin, state.indexMax));
}

// Fp4 rectilinear sampler
Expand Down
37 changes: 21 additions & 16 deletions devices/rtx/device/spatial_field/NvdbRegularSampler_ptx.cu
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@
using namespace visrtx;

VISRTX_DEVICE nanovdb::Vec3f clamp(const nanovdb::Vec3f &v,
const nanovdb::Vec3f &min,
const nanovdb::Vec3f &max)
const nanovdb::Vec3f &min,
const nanovdb::Vec3f &max)
{
return nanovdb::Vec3f(nanovdb::math::Clamp(v[0], min[0], max[0]),
nanovdb::math::Clamp(v[1], min[1], max[1]),
nanovdb::math::Clamp(v[2], min[2], max[2]));
nanovdb::math::Clamp(v[1], min[1], max[1]),
nanovdb::math::Clamp(v[2], min[2], max[2]));
}

template <typename ValueType>
Expand All @@ -61,32 +61,37 @@ VISRTX_DEVICE void initNvdbSampler(
new (&state.sampler) typename NvdbRegularSamplerState<ValueType>::SamplerType(
nanovdb::math::createSampler<1>(state.accessor));

const bool cellCentered = field->data.nvdbRegular.cellCentered;
const nanovdb::CoordBBox indexBBox = grid->indexBBox();
const nanovdb::Vec3f dims = nanovdb::Vec3f(indexBBox.dim());
state.indexMin = indexBBox.min().asVec3d();
state.indexMax = indexBBox.max().asVec3d();

if (cellCentered) {
state.offset = nanovdb::Vec3f(-0.5f);
// NanoVDB samplers get exact values at 0, 1, ... N, which works for
// node centered data. For cell centered data, we need to offset by -0.5
// and clamp to artificially create the full voxel, extrapolating the
// outermost voxel values.
// Scale moves from index space to index space - 1
state.offsetDown = -nanovdb::Vec3f(indexBBox.min());
if (field->data.nvdbRectilinear.cellCentered) {
state.offsetUp = nanovdb::Vec3f(-0.5f) - state.offsetDown;
state.scale = nanovdb::Vec3f(1.0f);
} else {
state.offset = nanovdb::Vec3f(0.0f);
state.scale = (dims - nanovdb::Vec3f(1.0f)) / dims;
state.offsetUp = -state.offsetDown;
state.scale = (dims) / (dims + nanovdb::Vec3f(1.0f));
}

state.indexMin = nanovdb::Vec3f(indexBBox.min());
state.indexMax = nanovdb::Vec3f(indexBBox.max());
}

template <typename ValueType>
VISRTX_DEVICE float sampleNvdb(
const NvdbRegularSamplerState<ValueType> &state, const vec3 *location)
{
auto indexPos = state.grid->worldToIndexF(
const auto indexPos0 = state.grid->worldToIndexF(
nanovdb::Vec3f(location->x, location->y, location->z));

indexPos = indexPos * state.scale + state.offset;
indexPos = clamp(indexPos, state.indexMin, state.indexMax);
const auto indexPos =
(indexPos0 - state.offsetDown) * state.scale + state.offsetUp;

return state.sampler(indexPos);
return state.sampler(clamp(indexPos, state.indexMin, state.indexMax));
}

// Fp4 sampler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,9 @@ VISRTX_CALLABLE float __direct_callable__sampleStructuredRectilinear(
vec3 normalizedPos = (*location - state.axisBoundsMin)
/ (state.axisBoundsMax - state.axisBoundsMin);

normalizedPos =
vec3(state.axisLUT[0] ? tex1D<float>(state.axisLUT[0], normalizedPos.x)
: normalizedPos.x,
state.axisLUT[1] ? tex1D<float>(state.axisLUT[1], normalizedPos.y)
: normalizedPos.y,
state.axisLUT[2] ? tex1D<float>(state.axisLUT[2], normalizedPos.z)
: normalizedPos.z);
normalizedPos = vec3(tex1D<float>(state.axisLUT[0], normalizedPos.x),
tex1D<float>(state.axisLUT[1], normalizedPos.y),
tex1D<float>(state.axisLUT[2], normalizedPos.z));

// Sample texture with transformed coordinates
auto sampleCoord = normalizedPos * state.dims + state.offset;
Expand Down
24 changes: 19 additions & 5 deletions tsd/apps/tools/tsdVolumeToNanoVDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string_view>
#include <tsd/core/Logging.hpp>
#include <tsd/core/scene/Scene.hpp>
#include <tsd/core/scene/objects/SpatialField.hpp>
#include <tsd/io/importers.hpp>
#include <tsd/io/serialization.hpp>

Expand Down Expand Up @@ -65,14 +66,16 @@ int main(int argc, const char *argv[])

if (arg == "--undefined" || arg == "-u") {
if (i + 1 >= argc) {
tsd::core::logError("Option %s requires a value", std::string(arg).c_str());
tsd::core::logError(
"Option %s requires a value", std::string(arg).c_str());
printUsage(argv[0]);
return 1;
}
try {
undefinedValue = std::stof(std::string(argv[++i]));
} catch (const std::exception &e) {
tsd::core::logError("Invalid undefined value: %s", std::string(argv[i] ).c_str());
tsd::core::logError(
"Invalid undefined value: %s", std::string(argv[i]).c_str());
printUsage(argv[0]);
return 1;
}
Expand All @@ -96,7 +99,8 @@ int main(int argc, const char *argv[])
} else if (precStr == "float32") {
precision = tsd::io::VDBPrecision::Float32;
} else {
tsd::core::logError("Unknown precision type: %s", std::string(precStr).c_str());
tsd::core::logError(
"Unknown precision type: %s", std::string(precStr).c_str());
printUsage(argv[0]);
return 1;
}
Expand All @@ -108,7 +112,8 @@ int main(int argc, const char *argv[])
} else if (!outputFile) {
outputFile = std::string(arg);
} else {
tsd::core::logError("Unexpected positional argument: %s", std::string(arg).c_str());
tsd::core::logError(
"Unexpected positional argument: %s", std::string(arg).c_str());
printUsage(argv[0]);
return 1;
}
Expand Down Expand Up @@ -143,7 +148,16 @@ int main(int argc, const char *argv[])
return 1;
}

tsd::io::export_StructuredRegularVolumeToNanoVDB(spatialField,
const auto subtype = spatialField->subtype();
const bool isRectilinear =
subtype == tsd::core::tokens::spatial_field::structuredRectilinear;

if (isRectilinear) {
tsd::core::logStatus(
"Detected rectilinear grid; writing NanoVDB sidecar with axis coordinates.");
}

tsd::io::export_StructuredVolumeToNanoVDB(spatialField,
outputFile->c_str(),
undefinedValue.has_value(),
undefinedValue.value_or(0.0f),
Expand Down
34 changes: 32 additions & 2 deletions tsd/src/tsd/core/scene/objects/SpatialField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ SpatialField::SpatialField(Token stype) : Object(ANARI_SPATIAL_FIELD, stype)
.setValue({ANARI_ARRAY1D, INVALID_INDEX})
.setDescription("array of floats containing the scalar voxel data");
} else if (stype == tokens::spatial_field::nanovdb) {
addParameter("gridData")
addParameter("data")
.setValue({ANARI_ARRAY1D, INVALID_INDEX})
.setDescription("array containing serialzed NanoVDB grid");
addParameter("filter").setValue("linear").setStringValues(
Expand All @@ -108,6 +108,34 @@ SpatialField::SpatialField(Token stype) : Object(ANARI_SPATIAL_FIELD, stype)
.setValue(tsd::math::box3(
tsd::math::float3(-math::inf, -math::inf, -math::inf),
tsd::math::float3(math::inf, math::inf, math::inf)));
} else if (stype == tokens::spatial_field::nanovdbRectilinear) {
addParameter("data")
.setValue({ANARI_ARRAY1D, INVALID_INDEX})
.setDescription("array containing serialzed NanoVDB grid");
addParameter("filter")
.setValue("linear")
.setStringValues({"linear", "nearest"})
.setStringSelection(0);
addParameter("dataCentering")
.setValue("cell")
.setStringValues({"node", "cell"})
.setStringSelection(1)
.setDescription(
"whether data values are node-centered or cell-centered");
addParameter("roi")
.setDescription("ROI box in object space")
.setValue(tsd::math::box3(
tsd::math::float3(-math::inf, -math::inf, -math::inf),
tsd::math::float3(math::inf, math::inf, math::inf)));
addParameter("coordsX")
.setValue({ANARI_ARRAY1D, INVALID_INDEX})
.setDescription("X-axis coordinates");
addParameter("coordsY")
.setValue({ANARI_ARRAY1D, INVALID_INDEX})
.setDescription("Y-axis coordinates");
addParameter("coordsZ")
.setValue({ANARI_ARRAY1D, INVALID_INDEX})
.setDescription("Z-axis coordinates");
}
}

Expand Down Expand Up @@ -150,7 +178,8 @@ tsd::math::float2 SpatialField::computeValueRange()
retval = *r;
else if (auto r = getDataRangeFromParameter(parameter("cell.data")); r)
retval = *r;
} else if (subtype() == tokens::spatial_field::nanovdb) {
} else if (subtype() == tokens::spatial_field::nanovdb
|| subtype() == tokens::spatial_field::nanovdbRectilinear) {
if (auto *range = parameter("range"); range)
retval = range->value().get<tsd::math::float2>();
} else if (subtype() == tokens::spatial_field::amr) {
Expand All @@ -175,6 +204,7 @@ const Token structuredRectilinear = "structuredRectilinear";
const Token unstructured = "unstructured";
const Token amr = "amr";
const Token nanovdb = "nanovdb";
const Token nanovdbRectilinear = "nanovdbRectilinear";

} // namespace tokens::spatial_field

Expand Down
1 change: 1 addition & 0 deletions tsd/src/tsd/core/scene/objects/SpatialField.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ extern const Token structuredRectilinear;
extern const Token unstructured;
extern const Token amr;
extern const Token nanovdb;
extern const Token nanovdbRectilinear;

} // namespace tokens::spatial_field

Expand Down
1 change: 1 addition & 0 deletions tsd/src/tsd/core/scene/objects/Volume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ anari::Object Volume::makeANARIObject(anari::Device d) const
namespace tokens::volume {

const Token structuredRegular = "structuredRegular";
const Token structuredRectilinear = "structuredRectilinear";
const Token transferFunction1D = "transferFunction1D";

} // namespace tokens::volume
Expand Down
1 change: 1 addition & 0 deletions tsd/src/tsd/core/scene/objects/Volume.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ using VolumeRef = ObjectPoolRef<Volume>;
namespace tokens::volume {

extern const Token structuredRegular;
extern const Token structuredRectilinear;
extern const Token transferFunction1D;

} // namespace tokens::volume
Expand Down
3 changes: 2 additions & 1 deletion tsd/src/tsd/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ PRIVATE
procedural/generate_randomSpheres.cpp
procedural/generate_rtow.cpp
procedural/generate_sphereSetVolume.cpp
serialization/export_RegularVolumeToNanoVDB.cpp
serialization/export_StructuredVolumeToNanoVDB.cpp
serialization/NanoVdbSidecar.cpp
serialization/export_SceneToUSD.cpp
serialization/serialization_datatree.cpp
)
Expand Down
Loading