OpenVDB  11.0.0
NanoToOpenVDB.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /*!
5  \file NanoToOpenVDB.h
6 
7  \author Ken Museth
8 
9  \date May 6, 2020
10 
11  \brief This class will deserialize an NanoVDB grid into an OpenVDB grid.
12 
13  \todo Add support for PointIndexGrid and PointDataGrid
14 */
15 
16 #include <nanovdb/NanoVDB.h> // manages and streams the raw memory buffer of a NanoVDB grid.
18 #include "ForEach.h"
19 
20 #include <openvdb/openvdb.h>
21 
22 #ifndef NANOVDB_NANOTOOPENVDB_H_HAS_BEEN_INCLUDED
23 #define NANOVDB_NANOTOOPENVDB_H_HAS_BEEN_INCLUDED
24 
25 template<typename T>
26 struct ConvertTrait {using Type = T;};
27 
28 template<typename T>
29 struct ConvertTrait<nanovdb::Vec3<T>> {using Type = openvdb::math::Vec3<T>;};
30 
31 template<typename T>
32 struct ConvertTrait<nanovdb::Vec4<T>> {using Type = openvdb::math::Vec4<T>;};
33 
34 template<>
35 struct ConvertTrait<nanovdb::Fp4> {using Type = float;};
36 
37 template<>
38 struct ConvertTrait<nanovdb::Fp8> {using Type = float;};
39 
40 template<>
41 struct ConvertTrait<nanovdb::Fp16> {using Type = float;};
42 
43 template<>
44 struct ConvertTrait<nanovdb::FpN> {using Type = float;};
45 
46 template<>
47 struct ConvertTrait<nanovdb::ValueMask> {using Type = openvdb::ValueMask;};
48 
49 namespace nanovdb {
50 
51 /// @brief Forward declaration of free-standing function that de-serializes a typed NanoVDB grid into an OpenVDB Grid
52 template<typename NanoBuildT>
54 nanoToOpenVDB(const NanoGrid<NanoBuildT>& grid, int verbose = 0);
55 
56 /// @brief Forward declaration of free-standing function that de-serializes a NanoVDB GridHandle into an OpenVDB GridBase
57 template<typename BufferT>
59 nanoToOpenVDB(const GridHandle<BufferT>& handle, int verbose = 0, uint32_t n = 0);
60 
61 /// @brief This class will serialize an OpenVDB grid into a NanoVDB grid managed by a GridHandle.
62 template<typename NanoBuildT>
64 {
65  using NanoNode0 = LeafNode<NanoBuildT, openvdb::Coord, openvdb::util::NodeMask>; // note that it's using openvdb coord nd mask types!
69  using NanoTreeT = Tree<NanoRootT>;
70  using NanoGridT = Grid<NanoTreeT>;
71  using NanoValueT = typename NanoGridT::ValueType;
72 
73  using OpenBuildT = typename ConvertTrait<NanoBuildT>::Type; // e.g. float -> float but nanovdb::Vec3<float> -> openvdb::Vec3<float>
74  using OpenNode0 = openvdb::tree::LeafNode<OpenBuildT, NanoNode0::LOG2DIM>; // leaf
75  using OpenNode1 = openvdb::tree::InternalNode<OpenNode0, NanoNode1::LOG2DIM>; // lower
76  using OpenNode2 = openvdb::tree::InternalNode<OpenNode1, NanoNode2::LOG2DIM>; // upper
77  using OpenRootT = openvdb::tree::RootNode<OpenNode2>;
78  using OpenTreeT = openvdb::tree::Tree<OpenRootT>;
80  using OpenValueT = typename OpenGridT::ValueType;
81 
82 public:
83  /// @brief Construction from an existing const OpenVDB Grid.
85 
86  /// @brief Return a shared pointer to a NanoVDB grid constructed from the specified OpenVDB grid
87  typename OpenGridT::Ptr operator()(const NanoGrid<NanoBuildT>& grid, int verbose = 0);
88 
89 private:
90 
91  template<typename NanoNodeT, typename OpenNodeT>
92  OpenNodeT* processNode(const NanoNodeT*);
93 
94  OpenNode2* process(const NanoNode2* node) {return this->template processNode<NanoNode2, OpenNode2>(node);}
95  OpenNode1* process(const NanoNode1* node) {return this->template processNode<NanoNode1, OpenNode1>(node);}
96 
97  template <typename NanoLeafT>
98  typename std::enable_if<!std::is_same<bool, typename NanoLeafT::BuildType>::value &&
99  !std::is_same<ValueMask, typename NanoLeafT::BuildType>::value &&
100  !std::is_same<Fp4, typename NanoLeafT::BuildType>::value &&
101  !std::is_same<Fp8, typename NanoLeafT::BuildType>::value &&
102  !std::is_same<Fp16,typename NanoLeafT::BuildType>::value &&
103  !std::is_same<FpN, typename NanoLeafT::BuildType>::value,
104  OpenNode0*>::type
105  process(const NanoLeafT* node);
106 
107  template <typename NanoLeafT>
108  typename std::enable_if<std::is_same<Fp4, typename NanoLeafT::BuildType>::value ||
109  std::is_same<Fp8, typename NanoLeafT::BuildType>::value ||
110  std::is_same<Fp16,typename NanoLeafT::BuildType>::value ||
111  std::is_same<FpN, typename NanoLeafT::BuildType>::value,
112  OpenNode0*>::type
113  process(const NanoLeafT* node);
114 
115  template <typename NanoLeafT>
116  typename std::enable_if<std::is_same<ValueMask, typename NanoLeafT::BuildType>::value,
117  OpenNode0*>::type
118  process(const NanoLeafT* node);
119 
120  template <typename NanoLeafT>
121  typename std::enable_if<std::is_same<bool, typename NanoLeafT::BuildType>::value,
122  OpenNode0*>::type
123  process(const NanoLeafT* node);
124 
125  /// converts nanovdb value types to openvdb value types, e.g. nanovdb::Vec3f& -> openvdb::Vec3f&
126  static const OpenValueT& Convert(const NanoValueT &v) {return reinterpret_cast<const OpenValueT&>(v);}
127  static const OpenValueT* Convert(const NanoValueT *v) {return reinterpret_cast<const OpenValueT*>(v);}
128 
129 }; // NanoToOpenVDB class
130 
131 template<typename NanoBuildT>
134 {
135  // since the input nanovdb grid might use nanovdb types (Coord, Mask, Vec3) we cast to use openvdb types
136  const NanoGridT *srcGrid = reinterpret_cast<const NanoGridT*>(&grid);
137 
138  auto dstGrid = openvdb::createGrid<OpenGridT>(Convert(srcGrid->tree().background()));
139  dstGrid->setName(srcGrid->gridName()); // set grid name
140  switch (srcGrid->gridClass()) { // set grid class
142  dstGrid->setGridClass(openvdb::GRID_LEVEL_SET);
143  break;
145  dstGrid->setGridClass(openvdb::GRID_FOG_VOLUME);
146  break;
148  dstGrid->setGridClass(openvdb::GRID_STAGGERED);
149  break;
151  throw std::runtime_error("NanoToOpenVDB does not yet support PointIndexGrids");
153  throw std::runtime_error("NanoToOpenVDB does not yet support PointDataGrids");
154  default:
155  dstGrid->setGridClass(openvdb::GRID_UNKNOWN);
156  }
157  // set transform
158  const nanovdb::Map& nanoMap = reinterpret_cast<const GridData*>(srcGrid)->mMap;
159  auto mat = openvdb::math::Mat4<double>::identity();
160  mat.setMat3(openvdb::math::Mat3<double>(nanoMap.mMatD));
161  mat.transpose(); // the 3x3 in nanovdb is transposed relative to openvdb's 3x3
162  mat.setTranslation(openvdb::math::Vec3<double>(nanoMap.mVecD));
163  dstGrid->setTransform(openvdb::math::Transform::createLinearTransform(mat)); // calls simplify!
164 
165  // process root node
166  auto &root = dstGrid->tree().root();
167  auto *data = srcGrid->tree().root().data();
168  for (uint32_t i=0; i<data->mTableSize; ++i) {
169  auto *tile = data->tile(i);
170  if (tile->isChild()) {
171  root.addChild( this->process( data->getChild(tile)) );
172  } else {
173  root.addTile(tile->origin(), Convert(tile->value), tile->state);
174  }
175  }
176 
177  return dstGrid;
178 }
179 
180 template<typename T>
181 template<typename SrcNodeT, typename DstNodeT>
182 DstNodeT*
183 NanoToOpenVDB<T>::processNode(const SrcNodeT *srcNode)
184 {
185  DstNodeT *dstNode = new DstNodeT(); // un-initialized for fast construction
186  dstNode->setOrigin(srcNode->origin());
187  const auto& childMask = srcNode->childMask();
188  const_cast<typename DstNodeT::NodeMaskType&>(dstNode->getValueMask()) = srcNode->valueMask();
189  const_cast<typename DstNodeT::NodeMaskType&>(dstNode->getChildMask()) = childMask;
190  auto* dstTable = const_cast<typename DstNodeT::UnionType*>(dstNode->getTable());
191  auto* srcData = srcNode->data();
192  std::vector<std::pair<uint32_t, const typename SrcNodeT::ChildNodeType*>> childNodes;
193  const auto childCount = childMask.countOn();
194  childNodes.reserve(childCount);
195  for (uint32_t n = 0; n < DstNodeT::NUM_VALUES; ++n) {
196  if (childMask.isOn(n)) {
197  childNodes.emplace_back(n, srcData->getChild(n));
198  } else {
199  dstTable[n].setValue(Convert(srcData->mTable[n].value));
200  }
201  }
202  auto kernel = [&](const auto& r) {
203  for (auto i = r.begin(); i != r.end(); ++i) {
204  auto &p = childNodes[i];
205  dstTable[p.first].setChild( this->process(p.second) );
206  }
207  };
208 
209 #if 0
210  kernel(Range1D(0, childCount));
211 #else
212  forEach(0, childCount, 1, kernel);
213 #endif
214  return dstNode;
215 } // processNode
216 
217 template<typename T>
218 template <typename NanoLeafT>
219 inline typename std::enable_if<!std::is_same<bool, typename NanoLeafT::BuildType>::value &&
220  !std::is_same<ValueMask, typename NanoLeafT::BuildType>::value &&
221  !std::is_same<Fp4, typename NanoLeafT::BuildType>::value &&
222  !std::is_same<Fp8, typename NanoLeafT::BuildType>::value &&
223  !std::is_same<Fp16,typename NanoLeafT::BuildType>::value &&
224  !std::is_same<FpN, typename NanoLeafT::BuildType>::value,
225  typename NanoToOpenVDB<T>::OpenNode0*>::type
226 NanoToOpenVDB<T>::process(const NanoLeafT *srcNode)
227 {
228  static_assert(std::is_same<NanoLeafT, NanoNode0>::value, "NanoToOpenVDB<FpN>::process assert failed");
229  OpenNode0* dstNode = new OpenNode0(); // un-initialized for fast construction
230  dstNode->setOrigin(srcNode->origin());
231  dstNode->setValueMask(srcNode->valueMask());
232 
233  const auto* src = Convert(srcNode->data()->mValues);// doesn't work for compressed data, bool or ValueMask
234  for (auto *dst = dstNode->buffer().data(), *end = dst + OpenNode0::SIZE; dst != end; dst += 4, src += 4) {
235  dst[0] = src[0];
236  dst[1] = src[1];
237  dst[2] = src[2];
238  dst[3] = src[3];
239  }
240 
241  return dstNode;
242 } // process(NanoNode0)
243 
244 template<typename T>
245 template <typename NanoLeafT>
246 inline typename std::enable_if<std::is_same<Fp4, typename NanoLeafT::BuildType>::value ||
247  std::is_same<Fp8, typename NanoLeafT::BuildType>::value ||
248  std::is_same<Fp16,typename NanoLeafT::BuildType>::value ||
249  std::is_same<FpN, typename NanoLeafT::BuildType>::value,
250  typename NanoToOpenVDB<T>::OpenNode0*>::type
251 NanoToOpenVDB<T>::process(const NanoLeafT *srcNode)
252 {
253  static_assert(std::is_same<NanoLeafT, NanoNode0>::value, "NanoToOpenVDB<T>::process assert failed");
254  OpenNode0* dstNode = new OpenNode0(); // un-initialized for fast construction
255  dstNode->setOrigin(srcNode->origin());
256  dstNode->setValueMask(srcNode->valueMask());
257  float *dst = dstNode->buffer().data();
258  for (int i=0; i!=512; i+=4) {
259  *dst++ = srcNode->getValue(i);
260  *dst++ = srcNode->getValue(i+1);
261  *dst++ = srcNode->getValue(i+2);
262  *dst++ = srcNode->getValue(i+3);
263  }
264 
265  return dstNode;
266 } // process(NanoNode0)
267 
268 template<typename T>
269 template <typename NanoLeafT>
270 inline typename std::enable_if<std::is_same<ValueMask, typename NanoLeafT::BuildType>::value,
271  typename NanoToOpenVDB<T>::OpenNode0*>::type
272 NanoToOpenVDB<T>::process(const NanoLeafT *srcNode)
273 {
274  static_assert(std::is_same<NanoLeafT, NanoNode0>::value, "NanoToOpenVDB<ValueMask>::process assert failed");
275  OpenNode0* dstNode = new OpenNode0(); // un-initialized for fast construction
276  dstNode->setOrigin(srcNode->origin());
277  dstNode->setValueMask(srcNode->valueMask());
278 
279  return dstNode;
280 } // process(NanoNode0)
281 
282 template<typename T>
283 template <typename NanoLeafT>
284 inline typename std::enable_if<std::is_same<bool, typename NanoLeafT::BuildType>::value,
285  typename NanoToOpenVDB<T>::OpenNode0*>::type
286 NanoToOpenVDB<T>::process(const NanoLeafT *srcNode)
287 {
288  static_assert(std::is_same<NanoLeafT, NanoNode0>::value, "NanoToOpenVDB<ValueMask>::process assert failed");
289  OpenNode0* dstNode = new OpenNode0(); // un-initialized for fast construction
290  dstNode->setOrigin(srcNode->origin());
291  dstNode->setValueMask(srcNode->valueMask());
292  reinterpret_cast<openvdb::util::NodeMask<3>&>(dstNode->buffer()) = srcNode->data()->mValues;
293 
294  return dstNode;
295 } // process(NanoNode0)
296 
297 template<typename NanoBuildT>
299 nanoToOpenVDB(const NanoGrid<NanoBuildT>& grid, int verbose)
300 {
302  return tmp(grid, verbose);
303 }
304 
305 template<typename BufferT>
307 nanoToOpenVDB(const GridHandle<BufferT>& handle, int verbose, uint32_t n)
308 {
309  if (auto grid = handle.template grid<float>(n)) {
310  return nanovdb::nanoToOpenVDB(*grid, verbose);
311  } else if (auto grid = handle.template grid<double>(n)) {
312  return nanovdb::nanoToOpenVDB(*grid, verbose);
313  } else if (auto grid = handle.template grid<int32_t>(n)) {
314  return nanovdb::nanoToOpenVDB(*grid, verbose);
315  } else if (auto grid = handle.template grid<int64_t>(n)) {
316  return nanovdb::nanoToOpenVDB(*grid, verbose);
317  } else if (auto grid = handle.template grid<bool>(n)) {
318  return nanovdb::nanoToOpenVDB(*grid, verbose);
319  } else if (auto grid = handle.template grid<nanovdb::Fp4>(n)) {
320  return nanovdb::nanoToOpenVDB(*grid, verbose);
321  } else if (auto grid = handle.template grid<nanovdb::Fp8>(n)) {
322  return nanovdb::nanoToOpenVDB(*grid, verbose);
323  } else if (auto grid = handle.template grid<nanovdb::Fp16>(n)) {
324  return nanovdb::nanoToOpenVDB(*grid, verbose);
325  } else if (auto grid = handle.template grid<nanovdb::FpN>(n)) {
326  return nanovdb::nanoToOpenVDB(*grid, verbose);
327  } else if (auto grid = handle.template grid<nanovdb::ValueMask>(n)) {
328  return nanovdb::nanoToOpenVDB(*grid, verbose);
329  } else if (auto grid = handle.template grid<nanovdb::Vec3f>(n)) {
330  return nanovdb::nanoToOpenVDB(*grid, verbose);
331  } else if (auto grid = handle.template grid<nanovdb::Vec3d>(n)) {
332  return nanovdb::nanoToOpenVDB(*grid, verbose);
333  } else if (auto grid = handle.template grid<nanovdb::Vec4f>(n)) {
334  return nanovdb::nanoToOpenVDB(*grid, verbose);
335  } else if (auto grid = handle.template grid<nanovdb::Vec4d>(n)) {
336  return nanovdb::nanoToOpenVDB(*grid, verbose);
337  } else {
338  OPENVDB_THROW(openvdb::RuntimeError, "Unsupported NanoVDB grid type!");
339  }
340 }
341 
342 } // namespace nanovdb
343 
344 #endif // NANOVDB_NANOTOOPENVDB_H_HAS_BEEN_INCLUDED
T Type
Definition: NanoToOpenVDB.h:26
openvdb::math::Vec4< T > Type
Definition: NanoToOpenVDB.h:32
VDB Tree, which is a thin wrapper around a RootNode.
Definition: NanoVDB.h:3989
Highest level of the data structure. Contains a tree and a world->index transform (that currently onl...
Definition: NanoVDB.h:3698
typename _TreeType::ValueType ValueType
Definition: Grid.h:579
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:74
double mVecD[3]
Definition: NanoVDB.h:3165
A unified wrapper for tbb::parallel_for and a naive std::thread fallback.
Definition: NanoToOpenVDB.h:26
Defines GridHandle, which manages a host, and possibly a device, memory buffer containing one or more...
Definition: Types.h:111
const TreeT & tree() const
Return a const reference to the tree.
Definition: NanoVDB.h:3753
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
This class serves to manage a buffer containing one or more NanoVDB Grids.
Definition: GridHandle.h:37
Implements a light-weight self-contained VDB data-structure in a single file! In other words...
float Type
Definition: NanoToOpenVDB.h:38
Definition: NanoVDB.h:247
float Type
Definition: NanoToOpenVDB.h:44
openvdb::Grid< typename openvdb::tree::Tree4< typename ConvertTrait< NanoBuildT >::Type >::Type >::Ptr nanoToOpenVDB(const NanoGrid< NanoBuildT > &grid, int verbose=0)
Forward declaration of free-standing function that de-serializes a typed NanoVDB grid into an OpenVDB...
Definition: NanoToOpenVDB.h:299
Top-most node of the VDB tree structure.
Definition: NanoVDB.h:4329
float Type
Definition: NanoToOpenVDB.h:35
double mMatD[9]
Definition: NanoVDB.h:3163
openvdb::math::Vec3< T > Type
Definition: NanoToOpenVDB.h:29
Definition: Types.h:455
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
NanoToOpenVDB()
Construction from an existing const OpenVDB Grid.
Definition: NanoToOpenVDB.h:84
typename TreeT::ValueType ValueType
Definition: NanoVDB.h:3708
This class will serialize an OpenVDB grid into a NanoVDB grid managed by a GridHandle.
Definition: NanoToOpenVDB.h:63
Range< 1, size_t > Range1D
Definition: Range.h:30
SharedPtr< Grid > Ptr
Definition: Grid.h:573
Definition: Types.h:456
const char * gridName() const
Return a c-string with the name of this grid.
Definition: NanoVDB.h:3858
Defines an affine transform and its inverse represented as a 3x3 matrix and a vec3 translation...
Definition: NanoVDB.h:3157
const GridClass & gridClass() const
Definition: NanoVDB.h:3828
Internal nodes of a VDB treedim(),.
Definition: NanoVDB.h:4968
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
Struct with all the member data of the Grid (useful during serialization of an openvdb grid) ...
Definition: NanoVDB.h:3511
Definition: Types.h:457
openvdb::GridBase::Ptr nanoToOpenVDB(const GridHandle< BufferT > &handle, int verbose=0, uint32_t n=0)
Forward declaration of free-standing function that de-serializes a NanoVDB GridHandle into an OpenVDB...
Definition: NanoToOpenVDB.h:307
Definition: Types.h:454
Leaf nodes of the VDB tree. (defaults to 8x8x8 = 512 voxels)
Definition: NanoVDB.h:6026
Definition: Exceptions.h:63
float Type
Definition: NanoToOpenVDB.h:41