Refactor: Cycles: Add some OpenVDB and NanoVDB functions to util
OpenVDB to NanoVDB was moved, a new NanoVDB to OpenVDB mask grid was added for future use. Some redundant CMake code was simplified. Pull Request: https://projects.blender.org/blender/blender/pulls/132908
This commit is contained in:
@@ -103,13 +103,9 @@ if(WITH_TBB)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENVDB)
|
||||
add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
|
||||
list(APPEND INC
|
||||
../../openvdb
|
||||
)
|
||||
list(APPEND INC_SYS
|
||||
${OPENVDB_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND LIB
|
||||
${OPENVDB_LIBRARIES}
|
||||
)
|
||||
|
||||
@@ -68,13 +68,6 @@ set(SRC_HD_CYCLES
|
||||
volume.cpp
|
||||
)
|
||||
|
||||
if(WITH_OPENVDB)
|
||||
add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
|
||||
list(APPEND INC_SYS
|
||||
${OPENVDB_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
|
||||
# Blender libraries do not include hgiGL, so build without display driver then.
|
||||
if(EXISTS ${USD_INCLUDE_DIR}/pxr/imaging/hgiGL)
|
||||
add_definitions(-DWITH_HYDRA_DISPLAY_DRIVER)
|
||||
|
||||
@@ -128,18 +128,9 @@ if(WITH_OPENCOLORIO)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENVDB)
|
||||
add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS})
|
||||
list(APPEND INC_SYS
|
||||
${OPENVDB_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND LIB
|
||||
${OPENVDB_LIBRARIES}
|
||||
)
|
||||
|
||||
# This works around the issue described in #120317 and https://github.com/AcademySoftwareFoundation/openvdb/pull/1786
|
||||
if(MSVC_CLANG)
|
||||
set_source_files_properties(image_vdb.cpp PROPERTIES COMPILE_FLAGS -fno-delayed-template-parsing)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
|
||||
@@ -5,129 +5,30 @@
|
||||
#include "scene/image_vdb.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/nanovdb.h"
|
||||
#include "util/openvdb.h"
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <openvdb/tools/Dense.h>
|
||||
#endif
|
||||
#ifdef WITH_NANOVDB
|
||||
# define NANOVDB_USE_OPENVDB
|
||||
# include <nanovdb/NanoVDB.h>
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7)
|
||||
# include <nanovdb/tools/CreateNanoGrid.h>
|
||||
# else
|
||||
# include <nanovdb/util/OpenToNanoVDB.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
struct NumChannelsOp {
|
||||
int num_channels = 0;
|
||||
|
||||
template<typename GridType, typename FloatGridType, typename FloatDataType, const int channels>
|
||||
bool operator()(const openvdb::GridBase::ConstPtr & /*unused*/)
|
||||
{
|
||||
num_channels = channels;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ToDenseOp {
|
||||
openvdb::CoordBBox bbox;
|
||||
void *pixels;
|
||||
|
||||
template<typename GridType, typename FloatGridType, typename FloatDataType, const int channels>
|
||||
bool operator()(const openvdb::GridBase::ConstPtr &grid)
|
||||
template<typename GridType, typename FloatDataType, const int channels>
|
||||
bool operator()(const typename GridType::ConstPtr &grid)
|
||||
{
|
||||
openvdb::tools::Dense<FloatDataType, openvdb::tools::LayoutXYZ> dense(bbox,
|
||||
(FloatDataType *)pixels);
|
||||
openvdb::tools::copyToDense(*openvdb::gridConstPtrCast<GridType>(grid), dense);
|
||||
openvdb::tools::copyToDense(*grid, dense);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
# ifdef WITH_NANOVDB
|
||||
struct ToNanoOp {
|
||||
nanovdb::GridHandle<> nanogrid;
|
||||
int precision;
|
||||
|
||||
template<typename GridType, typename FloatGridType, typename FloatDataType, const int channels>
|
||||
bool operator()(const openvdb::GridBase::ConstPtr &grid)
|
||||
{
|
||||
if constexpr (!std::is_same_v<GridType, openvdb::MaskGrid>) {
|
||||
try {
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 6)
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7)
|
||||
/* OpenVDB 12. */
|
||||
using nanovdb::tools::createNanoGrid;
|
||||
using nanovdb::tools::StatsMode;
|
||||
# else
|
||||
/* OpenVDB 11. */
|
||||
using nanovdb::createNanoGrid;
|
||||
using nanovdb::StatsMode;
|
||||
# endif
|
||||
|
||||
if constexpr (std::is_same_v<FloatGridType, openvdb::FloatGrid>) {
|
||||
const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
|
||||
if (precision == 0) {
|
||||
nanogrid = createNanoGrid<openvdb::FloatGrid, nanovdb::FpN>(floatgrid);
|
||||
}
|
||||
else if (precision == 16) {
|
||||
nanogrid = createNanoGrid<openvdb::FloatGrid, nanovdb::Fp16>(floatgrid);
|
||||
}
|
||||
else {
|
||||
nanogrid = createNanoGrid<openvdb::FloatGrid, float>(floatgrid);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FloatGridType, openvdb::Vec3fGrid>) {
|
||||
const openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
|
||||
nanogrid = createNanoGrid<openvdb::Vec3fGrid, nanovdb::Vec3f>(floatgrid,
|
||||
StatsMode::Disable);
|
||||
}
|
||||
# else
|
||||
/* OpenVDB 10. */
|
||||
if constexpr (std::is_same_v<FloatGridType, openvdb::FloatGrid>) {
|
||||
openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
|
||||
if (precision == 0) {
|
||||
nanogrid =
|
||||
nanovdb::openToNanoVDB<nanovdb::HostBuffer, openvdb::FloatTree, nanovdb::FpN>(
|
||||
floatgrid);
|
||||
}
|
||||
else if (precision == 16) {
|
||||
nanogrid =
|
||||
nanovdb::openToNanoVDB<nanovdb::HostBuffer, openvdb::FloatTree, nanovdb::Fp16>(
|
||||
floatgrid);
|
||||
}
|
||||
else {
|
||||
nanogrid = nanovdb::openToNanoVDB(floatgrid);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FloatGridType, openvdb::Vec3fGrid>) {
|
||||
openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
|
||||
nanogrid = nanovdb::openToNanoVDB(floatgrid);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
|
||||
}
|
||||
catch (...) {
|
||||
LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: Unknown error";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
# endif
|
||||
|
||||
VDBImageLoader::VDBImageLoader(openvdb::GridBase::ConstPtr grid_, const string &grid_name)
|
||||
: grid_name(grid_name), grid(grid_)
|
||||
{
|
||||
@@ -145,29 +46,23 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get number of channels from type. */
|
||||
NumChannelsOp op;
|
||||
if (!openvdb::grid_type_operation(grid, op)) {
|
||||
/* Convert to the few float types that we know. */
|
||||
grid = openvdb_convert_to_known_type(grid);
|
||||
if (!grid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
metadata.channels = op.num_channels;
|
||||
/* Get number of channels from type. */
|
||||
metadata.channels = openvdb_num_channels(grid);
|
||||
|
||||
/* Set data type. */
|
||||
# ifdef WITH_NANOVDB
|
||||
if (features.has_nanovdb) {
|
||||
/* NanoVDB expects no inactive leaf nodes. */
|
||||
# if 0
|
||||
openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
|
||||
openvdb::tools::pruneInactive(pruned_grid.tree());
|
||||
nanogrid = nanovdb::openToNanoVDB(pruned_grid);
|
||||
# endif
|
||||
ToNanoOp op;
|
||||
op.precision = precision;
|
||||
if (!openvdb::grid_type_operation(grid, op)) {
|
||||
/* Convert OpenVDB to NanoVDB grid. */
|
||||
nanogrid = openvdb_to_nanovdb(grid, precision, 0.0f);
|
||||
if (!nanogrid) {
|
||||
return false;
|
||||
}
|
||||
nanogrid = std::move(op.nanogrid);
|
||||
}
|
||||
# endif
|
||||
|
||||
@@ -263,7 +158,7 @@ bool VDBImageLoader::load_pixels(const ImageMetaData & /*metadata*/,
|
||||
ToDenseOp op;
|
||||
op.pixels = pixels;
|
||||
op.bbox = bbox;
|
||||
openvdb::grid_type_operation(grid, op);
|
||||
openvdb_grid_type_operation(grid, op);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
|
||||
@@ -18,6 +18,8 @@ set(SRC
|
||||
math_cdf.cpp
|
||||
md5.cpp
|
||||
murmurhash.cpp
|
||||
nanovdb.cpp
|
||||
openvdb.cpp
|
||||
path.cpp
|
||||
profiling.cpp
|
||||
string.cpp
|
||||
@@ -75,6 +77,7 @@ set(SRC_HEADERS
|
||||
math_int8.h
|
||||
md5.h
|
||||
murmurhash.h
|
||||
nanovdb.h
|
||||
openimagedenoise.h
|
||||
openvdb.h
|
||||
optimization.h
|
||||
@@ -133,4 +136,15 @@ endif()
|
||||
include_directories(${INC})
|
||||
include_directories(SYSTEM ${INC_SYS})
|
||||
|
||||
if(WITH_OPENVDB)
|
||||
list(APPEND LIB
|
||||
${OPENVDB_LIBRARIES}
|
||||
)
|
||||
|
||||
# This works around the issue described in #120317 and https://github.com/AcademySoftwareFoundation/openvdb/pull/1786
|
||||
if(MSVC_CLANG)
|
||||
set_source_files_properties(openvdb.cpp PROPERTIES COMPILE_FLAGS -fno-delayed-template-parsing)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
cycles_add_library(cycles_util "${LIB}" ${SRC} ${SRC_HEADERS})
|
||||
|
||||
310
intern/cycles/util/nanovdb.cpp
Normal file
310
intern/cycles/util/nanovdb.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
/* SPDX-FileCopyrightText: Contributors to the OpenVDB Project
|
||||
* SPDX-FileCopyrightText: 2025 Blender Foundation
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
|
||||
# include "util/nanovdb.h"
|
||||
# include "util/log.h"
|
||||
# include "util/openvdb.h"
|
||||
|
||||
# include <openvdb/tools/Activate.h>
|
||||
|
||||
# include <nanovdb/util/ForEach.h>
|
||||
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7)
|
||||
# include <nanovdb/tools/CreateNanoGrid.h>
|
||||
# else
|
||||
# include <nanovdb/util/OpenToNanoVDB.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Convert NanoVDB to OpenVDB mask grid.
|
||||
*
|
||||
* Implementation adapted from nanoToOpenVDB in nanovdb, this will create
|
||||
* a MaskGrid from any type of grid using the active voxels. */
|
||||
|
||||
template<typename NanoBuildT> class NanoToOpenVDBMask {
|
||||
using NanoNode0 = nanovdb::LeafNode<NanoBuildT, openvdb::Coord, openvdb::util::NodeMask>;
|
||||
using NanoNode1 = nanovdb::InternalNode<NanoNode0>;
|
||||
using NanoNode2 = nanovdb::InternalNode<NanoNode1>;
|
||||
using NanoRootT = nanovdb::RootNode<NanoNode2>;
|
||||
using NanoTreeT = nanovdb::Tree<NanoRootT>;
|
||||
using NanoGridT = nanovdb::Grid<NanoTreeT>;
|
||||
using NanoValueT = typename NanoGridT::ValueType;
|
||||
|
||||
using OpenBuildT = openvdb::ValueMask;
|
||||
using OpenNode0 = openvdb::tree::LeafNode<OpenBuildT, NanoNode0::LOG2DIM>;
|
||||
using OpenNode1 = openvdb::tree::InternalNode<OpenNode0, NanoNode1::LOG2DIM>;
|
||||
using OpenNode2 = openvdb::tree::InternalNode<OpenNode1, NanoNode2::LOG2DIM>;
|
||||
using OpenRootT = openvdb::tree::RootNode<OpenNode2>;
|
||||
using OpenTreeT = openvdb::tree::Tree<OpenRootT>;
|
||||
using OpenGridT = openvdb::Grid<OpenTreeT>;
|
||||
using OpenValueT = typename OpenGridT::ValueType;
|
||||
|
||||
public:
|
||||
NanoToOpenVDBMask() = default;
|
||||
typename OpenGridT::Ptr operator()(const nanovdb::NanoGrid<NanoBuildT> &grid = 0);
|
||||
|
||||
private:
|
||||
template<typename NanoNodeT, typename OpenNodeT>
|
||||
OpenNodeT *processNode(const NanoNodeT * /*node*/);
|
||||
|
||||
OpenNode2 *process(const NanoNode2 *node)
|
||||
{
|
||||
return this->template processNode<NanoNode2, OpenNode2>(node);
|
||||
}
|
||||
OpenNode1 *process(const NanoNode1 *node)
|
||||
{
|
||||
return this->template processNode<NanoNode1, OpenNode1>(node);
|
||||
}
|
||||
|
||||
template<typename NanoLeafT> OpenNode0 *process(const NanoLeafT *node);
|
||||
};
|
||||
|
||||
template<typename NanoBuildT>
|
||||
typename NanoToOpenVDBMask<NanoBuildT>::OpenGridT::Ptr NanoToOpenVDBMask<NanoBuildT>::operator()(
|
||||
const nanovdb::NanoGrid<NanoBuildT> &grid)
|
||||
{
|
||||
/* Since the input nanovdb grid might use nanovdb types (Coord, Mask, Vec3)
|
||||
* we cast to use openvdb types. */
|
||||
const NanoGridT *srcGrid = reinterpret_cast<const NanoGridT *>(&grid);
|
||||
auto dstGrid = openvdb::createGrid<OpenGridT>(OpenValueT());
|
||||
|
||||
/* Set transform. */
|
||||
const nanovdb::Map &nanoMap = reinterpret_cast<const nanovdb::GridData *>(srcGrid)->mMap;
|
||||
auto mat = openvdb::math::Mat4<double>::identity();
|
||||
mat.setMat3(openvdb::math::Mat3<double>(nanoMap.mMatD));
|
||||
mat.transpose(); /* The 3x3 in nanovdb is transposed relative to openvdb's 3x3. */
|
||||
mat.setTranslation(openvdb::math::Vec3<double>(nanoMap.mVecD));
|
||||
dstGrid->setTransform(openvdb::math::Transform::createLinearTransform(mat));
|
||||
|
||||
/* Process root node. */
|
||||
auto &root = dstGrid->tree().root();
|
||||
auto *data = srcGrid->tree().root().data();
|
||||
for (uint32_t i = 0; i < data->mTableSize; ++i) {
|
||||
auto *tile = data->tile(i);
|
||||
if (tile->isChild()) {
|
||||
root.addChild(this->process(data->getChild(tile)));
|
||||
}
|
||||
else {
|
||||
root.addTile(tile->origin(), OpenValueT(), tile->state);
|
||||
}
|
||||
}
|
||||
|
||||
return dstGrid;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename SrcNodeT, typename DstNodeT>
|
||||
DstNodeT *NanoToOpenVDBMask<T>::processNode(const SrcNodeT *srcNode)
|
||||
{
|
||||
DstNodeT *dstNode = new DstNodeT(); /* Un-initialized for fast construction. */
|
||||
dstNode->setOrigin(srcNode->origin());
|
||||
const auto &childMask = srcNode->childMask();
|
||||
const_cast<typename DstNodeT::NodeMaskType &>(dstNode->getValueMask()) = srcNode->valueMask();
|
||||
const_cast<typename DstNodeT::NodeMaskType &>(dstNode->getChildMask()) = childMask;
|
||||
auto *dstTable = const_cast<typename DstNodeT::UnionType *>(dstNode->getTable());
|
||||
auto *srcData = srcNode->data();
|
||||
std::vector<std::pair<uint32_t, const typename SrcNodeT::ChildNodeType *>> childNodes;
|
||||
const auto childCount = childMask.countOn();
|
||||
childNodes.reserve(childCount);
|
||||
for (uint32_t n = 0; n < DstNodeT::NUM_VALUES; ++n) {
|
||||
if (childMask.isOn(n)) {
|
||||
childNodes.emplace_back(n, srcData->getChild(n));
|
||||
}
|
||||
}
|
||||
auto kernel = [&](const auto &r) {
|
||||
for (auto i = r.begin(); i != r.end(); ++i) {
|
||||
auto &p = childNodes[i];
|
||||
dstTable[p.first].setChild(this->process(p.second));
|
||||
}
|
||||
};
|
||||
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7)
|
||||
nanovdb::util::forEach(0, childCount, 1, kernel);
|
||||
# else
|
||||
nanovdb::forEach(0, childCount, 1, kernel);
|
||||
# endif
|
||||
|
||||
return dstNode;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename NanoLeafT>
|
||||
inline typename NanoToOpenVDBMask<T>::OpenNode0 *NanoToOpenVDBMask<T>::process(
|
||||
const NanoLeafT *srcNode)
|
||||
{
|
||||
static_assert(std::is_same_v<NanoLeafT, NanoNode0>, "NanoToOpenVDBMask wrong leaf type");
|
||||
OpenNode0 *dstNode = new OpenNode0(); /* Un-initialized for fast construction. */
|
||||
dstNode->setOrigin(srcNode->origin());
|
||||
dstNode->setValueMask(srcNode->valueMask());
|
||||
|
||||
return dstNode;
|
||||
}
|
||||
|
||||
struct NanoToOpenVDBMaskOp {
|
||||
openvdb::MaskGrid::Ptr mask_grid;
|
||||
|
||||
template<typename NanoBuildT> bool operator()(const nanovdb::NanoGrid<NanoBuildT> &grid)
|
||||
{
|
||||
NanoToOpenVDBMask<NanoBuildT> tmp;
|
||||
mask_grid = tmp(grid);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename OpType>
|
||||
bool nanovdb_grid_type_operation(const nanovdb::GridHandle<> &handle, OpType &&op)
|
||||
{
|
||||
const int n = 0;
|
||||
|
||||
if (const auto *grid = handle.template grid<float>(n)) {
|
||||
return op(*grid);
|
||||
}
|
||||
if (const auto *grid = handle.template grid<nanovdb::Fp16>(n)) {
|
||||
return op(*grid);
|
||||
}
|
||||
if (const auto *grid = handle.template grid<nanovdb::FpN>(n)) {
|
||||
return op(*grid);
|
||||
}
|
||||
if (const auto *grid = handle.template grid<nanovdb::Vec3f>(n)) {
|
||||
return op(*grid);
|
||||
}
|
||||
if (const auto *grid = handle.template grid<nanovdb::Vec4f>(n)) {
|
||||
return op(*grid);
|
||||
}
|
||||
|
||||
assert(!"Unknown NanoVDB grid type");
|
||||
return true;
|
||||
}
|
||||
|
||||
openvdb::MaskGrid::Ptr nanovdb_to_openvdb_mask(const nanovdb::GridHandle<> &handle)
|
||||
{
|
||||
NanoToOpenVDBMaskOp op;
|
||||
nanovdb_grid_type_operation(handle, op);
|
||||
return op.mask_grid;
|
||||
}
|
||||
|
||||
/* Convert OpenVDB to NanoVDB grid. */
|
||||
|
||||
struct ToNanoOp {
|
||||
nanovdb::GridHandle<> nanogrid;
|
||||
int precision = 16;
|
||||
float clipping = 0.0f;
|
||||
|
||||
template<typename GridType, typename FloatDataType, const int channels>
|
||||
bool operator()(const typename GridType::ConstPtr &grid)
|
||||
{
|
||||
if constexpr (std::is_same_v<GridType, openvdb::MaskGrid>) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 6)
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7)
|
||||
/* OpenVDB 12. */
|
||||
using nanovdb::tools::createNanoGrid;
|
||||
using nanovdb::tools::StatsMode;
|
||||
# else
|
||||
/* OpenVDB 11. */
|
||||
using nanovdb::createNanoGrid;
|
||||
using nanovdb::StatsMode;
|
||||
# endif
|
||||
|
||||
if constexpr (std::is_same_v<GridType, openvdb::FloatGrid>) {
|
||||
typename GridType::ConstPtr floatgrid = apply_clipping<GridType>(grid);
|
||||
if (precision == 0) {
|
||||
nanogrid = createNanoGrid<openvdb::FloatGrid, nanovdb::FpN>(*floatgrid,
|
||||
StatsMode::Disable);
|
||||
}
|
||||
else if (precision == 16) {
|
||||
nanogrid = createNanoGrid<openvdb::FloatGrid, nanovdb::Fp16>(*floatgrid,
|
||||
StatsMode::Disable);
|
||||
}
|
||||
else {
|
||||
nanogrid = createNanoGrid<openvdb::FloatGrid, float>(*floatgrid, StatsMode::Disable);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<GridType, openvdb::Vec3fGrid>) {
|
||||
/* Enable stats for velocity grid. Weak, but there seems to be no simple iterator over all
|
||||
* values in the grid? */
|
||||
typename GridType::ConstPtr floatgrid = apply_clipping<GridType>(grid);
|
||||
nanogrid = createNanoGrid<openvdb::Vec3fGrid, nanovdb::Vec3f>(*floatgrid,
|
||||
StatsMode::MinMax);
|
||||
}
|
||||
else if constexpr (std::is_same_v<GridType, openvdb::Vec4fGrid>) {
|
||||
typename GridType::ConstPtr floatgrid = apply_clipping<GridType>(grid);
|
||||
nanogrid = createNanoGrid<openvdb::Vec4fGrid, nanovdb::Vec4f>(*floatgrid,
|
||||
StatsMode::Disable);
|
||||
}
|
||||
# else
|
||||
/* OpenVDB 10. */
|
||||
if constexpr (std::is_same_v<GridType, openvdb::FloatGrid>) {
|
||||
typename GridType::ConstPtr floatgrid = apply_clipping<GridType>(grid);
|
||||
if (precision == 0) {
|
||||
nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer, openvdb::FloatTree, nanovdb::FpN>(
|
||||
*floatgrid);
|
||||
}
|
||||
else if (precision == 16) {
|
||||
nanogrid =
|
||||
nanovdb::openToNanoVDB<nanovdb::HostBuffer, openvdb::FloatTree, nanovdb::Fp16>(
|
||||
*floatgrid);
|
||||
}
|
||||
else {
|
||||
nanogrid = nanovdb::openToNanoVDB(*floatgrid);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<FloatGridType, openvdb::Vec3fGrid>) {
|
||||
typename GridType::ConstPtr floatgrid = apply_clipping<GridType>(grid);
|
||||
nanogrid = nanovdb::openToNanoVDB(*floatgrid);
|
||||
}
|
||||
else if constexpr (std::is_same_v<FloatGridType, openvdb::Vec4fGrid>) {
|
||||
typename GridType::ConstPtr floatgrid = apply_clipping<GridType>(grid);
|
||||
nanogrid = nanovdb::openToNanoVDB(*floatgrid);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
|
||||
}
|
||||
catch (...) {
|
||||
LOG(WARNING) << "Error converting OpenVDB to NanoVDB grid: Unknown error";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename GridT>
|
||||
typename GridT::ConstPtr apply_clipping(const typename GridT::ConstPtr &grid) const
|
||||
{
|
||||
if (clipping == 0.0f) {
|
||||
return grid;
|
||||
}
|
||||
|
||||
/* TODO: Ideally would apply clipping during createNanoGrid, this seems slow. */
|
||||
typename GridT::Ptr newgrid = grid->deepCopy();
|
||||
openvdb::tools::deactivate(
|
||||
*newgrid, typename GridT::ValueType(0.0f), typename GridT::ValueType(clipping));
|
||||
return newgrid;
|
||||
}
|
||||
};
|
||||
|
||||
nanovdb::GridHandle<> openvdb_to_nanovdb(const openvdb::GridBase::ConstPtr &grid,
|
||||
const int precision,
|
||||
const float clipping)
|
||||
{
|
||||
ToNanoOp op;
|
||||
op.precision = precision;
|
||||
op.clipping = clipping;
|
||||
openvdb_grid_type_operation(grid, op);
|
||||
return std::move(op.nanogrid);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
35
intern/cycles/util/nanovdb.h
Normal file
35
intern/cycles/util/nanovdb.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: Contributors to the OpenVDB Project
|
||||
* SPDX-FileCopyrightText: 2025 Blender Foundation
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef WITH_NANOVDB
|
||||
|
||||
# include <openvdb/openvdb.h>
|
||||
|
||||
# define NANOVDB_USE_OPENVDB
|
||||
# define NANOVDB_USE_TBB
|
||||
|
||||
# include <nanovdb/NanoVDB.h> // manages and streams the raw memory buffer of a NanoVDB grid.
|
||||
|
||||
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
|
||||
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 7)
|
||||
# include <nanovdb/GridHandle.h>
|
||||
# else
|
||||
# include <nanovdb/util/GridHandle.h>
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Convert NanoVDB to OpenVDB mask grid that represents just the topology. */
|
||||
openvdb::MaskGrid::Ptr nanovdb_to_openvdb_mask(const nanovdb::GridHandle<> &handle);
|
||||
|
||||
/* Convert OpenVDB to NanoVDB grid. */
|
||||
nanovdb::GridHandle<> openvdb_to_nanovdb(const openvdb::GridBase::ConstPtr &grid,
|
||||
const int precision,
|
||||
const float clipping);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
80
intern/cycles/util/openvdb.cpp
Normal file
80
intern/cycles/util/openvdb.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
|
||||
# include "util/openvdb.h"
|
||||
|
||||
# include <openvdb/tools/Activate.h>
|
||||
# include <openvdb/tools/Dense.h>
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Convert to the few data types we native can render. */
|
||||
openvdb::GridBase::ConstPtr openvdb_convert_to_known_type(const openvdb::GridBase::ConstPtr &grid)
|
||||
{
|
||||
if (grid->isType<openvdb::FloatGrid>()) {
|
||||
return grid;
|
||||
}
|
||||
if (grid->isType<openvdb::Vec3fGrid>()) {
|
||||
return grid;
|
||||
}
|
||||
if (grid->isType<openvdb::Vec4fGrid>()) {
|
||||
return grid;
|
||||
}
|
||||
if (grid->isType<openvdb::BoolGrid>()) {
|
||||
const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<openvdb::BoolGrid>(grid));
|
||||
return std::make_shared<openvdb::FloatGrid>(std::move(floatgrid));
|
||||
}
|
||||
if (grid->isType<openvdb::DoubleGrid>()) {
|
||||
const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<openvdb::DoubleGrid>(grid));
|
||||
return std::make_shared<openvdb::FloatGrid>(std::move(floatgrid));
|
||||
}
|
||||
if (grid->isType<openvdb::Int32Grid>()) {
|
||||
const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<openvdb::Int32Grid>(grid));
|
||||
return std::make_shared<openvdb::FloatGrid>(std::move(floatgrid));
|
||||
}
|
||||
if (grid->isType<openvdb::Int64Grid>()) {
|
||||
const openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<openvdb::Int64Grid>(grid));
|
||||
return std::make_shared<openvdb::FloatGrid>(std::move(floatgrid));
|
||||
}
|
||||
if (grid->isType<openvdb::Vec3IGrid>()) {
|
||||
const openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast<openvdb::Vec3IGrid>(grid));
|
||||
return std::make_shared<openvdb::Vec3fGrid>(std::move(floatgrid));
|
||||
}
|
||||
if (grid->isType<openvdb::Vec3dGrid>()) {
|
||||
const openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast<openvdb::Vec3dGrid>(grid));
|
||||
return std::make_shared<openvdb::Vec3fGrid>(std::move(floatgrid));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* Counter number of channels. */
|
||||
struct NumChannelsOp {
|
||||
int num_channels = 0;
|
||||
|
||||
template<typename GridType, typename FloatDataType, const int channels>
|
||||
bool operator()(const typename GridType::ConstPtr & /*unused*/)
|
||||
{
|
||||
num_channels = channels;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int openvdb_num_channels(const openvdb::GridBase::ConstPtr &grid)
|
||||
{
|
||||
NumChannelsOp op;
|
||||
if (!openvdb_grid_type_operation(grid, op)) {
|
||||
return 0;
|
||||
}
|
||||
return op.num_channels;
|
||||
}
|
||||
|
||||
/* Convert OpenVDB to NanoVDB. */
|
||||
# ifdef WITH_NANOVDB
|
||||
# endif
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
# include <memory>
|
||||
# include <openvdb/openvdb.h>
|
||||
|
||||
namespace openvdb {
|
||||
@@ -12,40 +13,36 @@ namespace openvdb {
|
||||
using Vec4fTree = tree::Tree4<Vec4f, 5, 4, 3>::Type;
|
||||
using Vec4fGrid = Grid<Vec4fTree>;
|
||||
|
||||
} // namespace openvdb
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
/* Convert to the few grid types we can render natively. */
|
||||
openvdb::GridBase::ConstPtr openvdb_convert_to_known_type(const openvdb::GridBase::ConstPtr &grid);
|
||||
|
||||
/* Apply operation to known grid types. */
|
||||
template<typename OpType>
|
||||
bool grid_type_operation(const openvdb::GridBase::ConstPtr &grid, OpType &&op)
|
||||
bool openvdb_grid_type_operation(const openvdb::GridBase::ConstPtr &grid, OpType &&op)
|
||||
{
|
||||
if (grid->isType<openvdb::FloatGrid>()) {
|
||||
return op.template operator()<openvdb::FloatGrid, openvdb::FloatGrid, float, 1>(grid);
|
||||
return op.template operator()<openvdb::FloatGrid, float, 1>(
|
||||
openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid));
|
||||
}
|
||||
if (grid->isType<openvdb::Vec3fGrid>()) {
|
||||
return op.template operator()<openvdb::Vec3fGrid, openvdb::Vec3fGrid, openvdb::Vec3f, 3>(grid);
|
||||
return op.template operator()<openvdb::Vec3fGrid, openvdb::Vec3f, 3>(
|
||||
openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid));
|
||||
}
|
||||
if (grid->isType<openvdb::BoolGrid>()) {
|
||||
return op.template operator()<openvdb::BoolGrid, openvdb::FloatGrid, float, 1>(grid);
|
||||
}
|
||||
if (grid->isType<openvdb::DoubleGrid>()) {
|
||||
return op.template operator()<openvdb::DoubleGrid, openvdb::FloatGrid, float, 1>(grid);
|
||||
}
|
||||
if (grid->isType<openvdb::Int32Grid>()) {
|
||||
return op.template operator()<openvdb::Int32Grid, openvdb::FloatGrid, float, 1>(grid);
|
||||
}
|
||||
if (grid->isType<openvdb::Int64Grid>()) {
|
||||
return op.template operator()<openvdb::Int64Grid, openvdb::FloatGrid, float, 1>(grid);
|
||||
}
|
||||
if (grid->isType<openvdb::Vec3IGrid>()) {
|
||||
return op.template operator()<openvdb::Vec3IGrid, openvdb::Vec3fGrid, openvdb::Vec3f, 3>(grid);
|
||||
}
|
||||
if (grid->isType<openvdb::Vec3dGrid>()) {
|
||||
return op.template operator()<openvdb::Vec3dGrid, openvdb::Vec3fGrid, openvdb::Vec3f, 3>(grid);
|
||||
}
|
||||
if (grid->isType<openvdb::MaskGrid>()) {
|
||||
return op.template operator()<openvdb::MaskGrid, openvdb::FloatGrid, float, 1>(grid);
|
||||
if (grid->isType<openvdb::Vec4fGrid>()) {
|
||||
return op.template operator()<openvdb::Vec4fGrid, openvdb::Vec4f, 4>(
|
||||
openvdb::gridConstPtrCast<openvdb::Vec4fGrid>(grid));
|
||||
}
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
}; // namespace openvdb
|
||||
/* Count number of channels in known types. */
|
||||
int openvdb_num_channels(const openvdb::GridBase::ConstPtr &grid);
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user