OpenVDB  9.0.1
GEO_PrimVDB.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  * Copyright (c) Side Effects Software Inc.
6  *
7  * Produced by:
8  * Side Effects Software Inc
9  * 477 Richmond Street West
10  * Toronto, Ontario
11  * Canada M5V 3E7
12  * 416-504-9876
13  *
14  * NAME: GEO_PrimVDB.h ( GEO Library, C++)
15  *
16  * COMMENTS: Custom VDB primitive.
17  */
18 
19 
20 // Using the native OpenVDB Primitive shipped with Houdini is strongly recommended,
21 // as there is no guarantee that this code will be kept in sync with Houdini.
22 // However, for debugging it can be useful, so supply -DSESI_OPENVDB_PRIM to
23 // the compiler to build this custom primitive.
24 
25 #if !defined(SESI_OPENVDB) && !defined(SESI_OPENVDB_PRIM)
26 
27 #include <GEO/GEO_PrimVDB.h>
28 
29 namespace openvdb_houdini {
30 using ::GEO_VolumeOptions;
31 using ::GEO_PrimVDB;
32 }
33 
34 #else // SESI_OPENVDB || SESI_OPENVDB_PRIM
35 
36 #ifndef __HDK_GEO_PrimVDB__
37 #define __HDK_GEO_PrimVDB__
38 
39 #include <GEO/GEO_Primitive.h>
40 #include <GEO/GEO_VolumeOptions.h>
41 #include <GA/GA_Defines.h>
42 
43 #include <SYS/SYS_AtomicInt.h> // for SYS_AtomicCounter
44 
45 #include <UT/UT_BoundingBox.h>
46 #include "UT_VDBUtils.h"
47 
48 #include <openvdb/Platform.h>
49 #include <openvdb/openvdb.h>
50 
51 
52 class GEO_Detail;
53 class GEO_PrimVolume;
54 class GEO_PrimVolumeXform;
55 class UT_MemoryCounter;
56 
57 class CE_VDBGrid;
58 
59 class OPENVDB_HOUDINI_API GEO_PrimVDB : public GEO_Primitive
60 {
61 public:
62  typedef uint64 UniqueId;
63 
64 protected:
65  /// NOTE: The constructor should only be called from subclass
66  /// constructors.
67  GEO_PrimVDB(GEO_Detail *d, GA_Offset offset = GA_INVALID_OFFSET);
68 
69  ~GEO_PrimVDB() override;
70 public:
71  static GA_PrimitiveFamilyMask buildFamilyMask()
72  { return GA_FAMILY_NONE; }
73 
74  /// @{
75  /// Required interface methods
76  bool isDegenerate() const override;
77  int getBBox(UT_BoundingBox *bbox) const override;
78  void reverse() override;
79  UT_Vector3 computeNormal() const override;
80  void copyPrimitive(const GEO_Primitive *src) override;
81  void copySubclassData(const GA_Primitive *source) override;
82 
83  /// Acquire a CE grid and cache it on the GPU. If marked for
84  /// writing, the CPU version will be overwritten.
85  /// Note that the getVoxelHandle does *NOT* auto-flush these!
86  /// NOTE: If someone else fetches a non-read grid, and you fetch it
87  /// as a read grid, you will not get any copied data.
88  CE_VDBGrid *getCEGrid(bool read, bool write) const;
89 
90  /// Any modified CE cache on the GPU will be copied back to the
91  /// CPU. Will leave result on GPU.
92  void flushCEWriteCaches() override;
93 
94  /// Remove all CE caches from the GPU, possibly writing back
95  /// if necessary.
96  void flushCECaches() override;
97 
98  /// Steal the underlying CE buffer from the source.
99  void stealCEBuffers(const GA_Primitive *src) override;
100 
101  using GEO_Primitive::getVertexOffset;
102  using GEO_Primitive::getPointOffset;
103  using GEO_Primitive::setPointOffset;
104  using GEO_Primitive::getPos3;
105  using GEO_Primitive::setPos3;
106  SYS_FORCE_INLINE
107  GA_Offset getVertexOffset() const
108  { return getVertexOffset(0); }
109  SYS_FORCE_INLINE
110  GA_Offset getPointOffset() const
111  { return getPointOffset(0); }
112  SYS_FORCE_INLINE
113  void setPointOffset(GA_Offset pt)
114  { setPointOffset(0, pt); }
115  SYS_FORCE_INLINE
116  UT_Vector3 getPos3() const
117  { return getPos3(0); }
118  SYS_FORCE_INLINE
119  void setPos3(const UT_Vector3 &pos)
120  { setPos3(0, pos); }
121 
122  /// Convert an index in the voxel array into the corresponding worldspace
123  /// location
124  void indexToPos(int x, int y, int z, UT_Vector3 &pos) const;
125  void findexToPos(UT_Vector3 index, UT_Vector3 &pos) const;
126  void indexToPos(exint x, exint y, exint z, UT_Vector3D &pos) const;
127  void findexToPos(UT_Vector3D index, UT_Vector3D &pos) const;
128 
129  /// Convert a 3d position into the closest index value.
130  void posToIndex(UT_Vector3 pos, int &x, int &y, int &z) const;
131  void posToIndex(UT_Vector3 pos, UT_Vector3 &index) const;
132  void posToIndex(UT_Vector3D pos, exint &x, exint &y, exint &z) const;
133  void posToIndex(UT_Vector3D pos, UT_Vector3D &index) const;
134 
135  /// Evaluate the voxel value at the given world space position.
136  /// Note that depending on the underlying VDB type, this may not
137  /// be sensible, in which case a zero will silently be returned
138  fpreal getValueF(const UT_Vector3 &pos) const;
139  fpreal getValueAtIndexF(int ix, int iy, int iz) const;
140  UT_Vector3D getValueV3(const UT_Vector3 &pos) const;
141  UT_Vector3D getValueAtIndexV3(int ix, int iy, int iz) const;
142 
143  void getValues(float *f, int stride, const UT_Vector3 *pos, int num) const;
144  void getValues(int *f, int stride, const UT_Vector3 *pos, int num) const;
145  void getValuesAtIndices(float *f, int stride, const int *ix, const int *iy, const int *iz, int num) const;
146  void getValuesAtIndices(int *f, int stride, const int *ix, const int *iy, const int *iz, int num) const;
147 
148  /// Vector grid variants.
149  void getValues(UT_Vector3 *f, int stride, const UT_Vector3 *pos, int num) const;
150  void getValuesAtIndices(UT_Vector3 *f, int stride, const int *ix, const int *iy, const int *iz, int num) const;
151 
152  void getValues(double *f, int stride, const UT_Vector3D *pos, int num) const;
153  void getValues(exint *f, int stride, const UT_Vector3D *pos, int num) const;
154  void getValuesAtIndices(double *f, int stride, const exint *ix, const exint *iy, const exint *iz, int num) const;
155  void getValuesAtIndices(exint *f, int stride, const exint *ix, const exint *iy, const exint *iz, int num) const;
156 
157  /// Vector grid variants.
158  void getValues(UT_Vector3D *f, int stride, const UT_Vector3D *pos, int num) const;
159  void getValuesAtIndices(UT_Vector3D *f, int stride, const exint *ix, const exint *iy, const exint *iz, int num) const;
160 
161  // Worldspace gradient at the given position
162  UT_Vector3 getGradient(const UT_Vector3 &pos) const;
163 
164  /// Evaluate this grid's gradients at the given world space positions.
165  /// Does nothing and returns false if grid is non-scalar.
166  /// If normalize is true, then the gradients will be normalized to be unit
167  /// length.
168  bool evalGradients(
169  UT_Vector3 *gradients,
170  int gradients_stride,
171  const UT_Vector3 *positions,
172  int num_positions,
173  bool normalize = false) const;
174 
175  /// Get the storage type of the grid
176  SYS_FORCE_INLINE
177  UT_VDBType getStorageType() const
178  { return myGridAccessor.getStorageType(); }
179  /// Get the tuple size, usually 1 or 3
180  SYS_FORCE_INLINE
181  int getTupleSize() const
182  { return UTvdbGetGridTupleSize(getStorageType()); }
183 
184  bool isSDF() const;
185 
186  /// True if the two volumes map the same indices to the same positions.
187  bool isAligned(const GEO_PrimVDB *vdb) const;
188  /// True if the two volumes have the same active regions
189  bool isActiveRegionMatched(const GEO_PrimVDB *vdb) const;
190 
191  /// True if we are aligned with the world axes. Ie, all our
192  /// off diagonals are zero and our diagonal is positive.
193  bool isWorldAxisAligned() const;
194 
195  // Transform the matrix associated with this primitive. Translate is
196  // ignored.
197  void transform(const UT_Matrix4 &mat) override;
198 
199  /// Accessors for the 4x4 matrix representing the affine transform that
200  /// converts from index space voxel coordinates to world space. For frustum
201  /// maps, this will be transform as if the taper value is set to 1.
202  /// @{
203  void setTransform4(const UT_DMatrix4 &xform4);
204  void setTransform4(const UT_Matrix4 &xform4);
205  UT_Matrix4D getTransform4() const;
206  /// @}
207 
208  // Take the whole set of points into consideration when applying the
209  // point removal operation to this primitive. The method returns 0 if
210  // successful, -1 if it failed because it would have become degenerate,
211  // and -2 if it failed because it would have had to remove the primitive
212  // altogether.
213  int detachPoints(GA_PointGroup &grp) override;
214  /// Before a point is deleted, all primitives using the point will be
215  /// notified. The method should return "false" if it's impossible to
216  /// delete the point. Otherwise, the vertices should be removed.
217  GA_DereferenceStatus dereferencePoint(GA_Offset point,
218  bool dry_run=false) override;
219  GA_DereferenceStatus dereferencePoints(const GA_RangeMemberQuery &pt_q,
220  bool dry_run=false) override;
221  const GA_PrimitiveJSON *getJSON() const override;
222 
223  /// This method assigns a preallocated vertex to the quadric, optionally
224  /// creating the topological link between the primitive and new vertex.
225  void assignVertex(GA_Offset new_vtx, bool update_topology);
226 
227  /// Evalaute a point given a u,v coordinate (with derivatives)
228  bool evaluatePointRefMap(
229  GA_Offset result_vtx,
230  GA_AttributeRefMap &hlist,
231  fpreal u, fpreal v,
232  uint du, uint dv) const override;
233  /// Evalaute position given a u,v coordinate (with derivatives)
234  int evaluatePointV4(
235  UT_Vector4 &pos,
236  float u, float v = 0,
237  unsigned du=0, unsigned dv=0) const override
238  {
239  return GEO_Primitive::evaluatePointV4(pos, u, v,
240  du, dv);
241  }
242  /// @}
243 
244  /// Convert transforms between native volumes and VDBs
245  /// @{
246 
247  /// Get a GEO_PrimVolumeXform which represent's the grid's full transform.
248  /// The returned space's fromVoxelSpace() method will convert index space
249  /// voxel coordinates to world space positions (and the vice versa for
250  /// toVoxelSpace()).
251  /// Note: The transformation is not the same as `posToIndex`
252  /// getIndexSpaceTransform().toVoxelSpace(pos) == posToIndex(pos) + {0.5, 0.5, 0.5}
253  GEO_PrimVolumeXform getIndexSpaceTransform() const;
254 
255  /// Equivalent to getSpaceTransform(getGrid().evalActiveVoxelBoundingBox()).
256  /// The returned space's fromVoxelSpace() method will convert 0-1
257  /// coordinates over the active voxel bounding box to world space (and vice
258  /// versa for toVoxelSpace()).
259  GEO_PrimVolumeXform getSpaceTransform() const;
260 
261  /// Gives the equivalent to GEO_PrimVolume's getSpaceTransform() by using
262  /// the given bounding box to determine the bounds of the transform.
263  /// The resulting world space sample points will be offset by half a voxel
264  /// so that they match GEO_PrimVolume.
265  /// The returned space's fromVoxelSpace() method will convert 0-1
266  /// coordinates over the bbox extents to world space (and vice versa for
267  /// toVoxelSpace()).
268  GEO_PrimVolumeXform getSpaceTransform(const UT_BoundingBoxD &bbox) const;
269 
270  /// Sets the transform from a GEO_PrimVolume's getSpaceTransform() by using
271  /// the index space [(0,0,0), resolution] bbox. If force_taper is true,
272  /// then the resulting transform will always be a NonlinearFrustumMap even
273  /// if there is no tapering.
274  void setSpaceTransform(const GEO_PrimVolumeXform &space,
275  const UT_Vector3R &resolution,
276  bool force_taper = false);
277 
278  /// @}
279 
280  fpreal getTaper() const;
281 
282  /// Returns the resolution of the active voxel array.
283  /// Does *not* mean the indices go from 0..rx, however!
284  void getRes(int &rx, int &ry, int &rz) const;
285 
286  /// Computes the voxel diameter by taking a step in x, y, and z
287  /// converting to world space and taking the length of that vector.
288  fpreal getVoxelDiameter() const;
289 
290  /// Returns the length of the voxel when you take an x, y, and z step
291  UT_Vector3 getVoxelSize() const;
292 
293  /// Compute useful aggregate properties of the volume.
294  fpreal calcMinimum() const;
295  fpreal calcMaximum() const;
296  fpreal calcAverage() const;
297 
298  /// VDBs may either be unbounded, or created with a specific frustum
299  /// range. The latter is important for tapered VDBs that otherwise
300  /// have a singularity at the camera location. Tools can use the
301  /// presence of an idxbox as a clipping box in index space.
302  /// This does *NOT* relate to getRes - it may be much larger or
303  /// even in some cases smaller.
304  bool getFrustumBounds(UT_BoundingBox &idxbox) const;
305 
306  enum ActivateOperation
307  {
308  ACTIVATE_UNION, // Activate anything in source
309  ACTIVATE_INTERSECT, // Deactivate anything not in source
310  ACTIVATE_SUBTRACT, // Deactivate anything in source
311  ACTIVATE_COPY // Set our activation to match source
312  };
313 
314  /// Activates voxels given an *index* space bounding box. This
315  /// is an inclusive box.
316  /// If this is Frustum VDB, the activation will be clipped by that.
317  /// Setting the value only takes effect if the voxels are activated,
318  /// deactivated voxels are set to the background.
319  void activateIndexBBox(
320  const openvdb::CoordBBox& bbox,
321  ActivateOperation operation,
322  bool setvalue, fpreal value)
323  {
324  activateIndexBBoxAdapter(
325  &bbox, operation, setvalue, value);
326  }
327 
328  /// Activates all of the voxels in this VDB that are touched
329  /// by active voxels in the source.
330  /// If ignore_transform is true, voxels will be activated
331  /// by grid index instead of world space position.
332  void activateByVDB(const GEO_PrimVDB *vdb,
333  ActivateOperation operation,
334  bool setvalue, fpreal value,
335  bool ignore_transform=false);
336 
337  /// @{
338  /// Though not strictly required (i.e. not pure virtual), these methods
339  /// should be implemented for proper behaviour.
340  GEO_Primitive *copy(int preserve_shared_pts = 0) const override;
341 
342  // Have we been deactivated and stashed?
343  void stashed(bool beingstashed,
344  GA_Offset offset=GA_INVALID_OFFSET) override;
345 
346  /// @}
347 
348  /// @{
349  /// Optional interface methods. Though not required, implementing these
350  /// will give better behaviour for the new primitive.
351  UT_Vector3 baryCenter() const override;
352  fpreal calcVolume(const UT_Vector3 &refpt) const override;
353  /// Calculate the surface area of the active voxels where
354  /// a voxel face contributes if it borders an inactive voxel.
355  fpreal calcArea() const override;
356  /// @}
357 
358  /// @{
359  /// Enlarge a bounding box by the bounding box of the primitive. A
360  /// return value of false indicates an error in the operation, most
361  /// likely an invalid P. For any attribute other than the position
362  /// these methods simply enlarge the bounding box based on the vertex.
363  bool enlargeBoundingBox(
364  UT_BoundingRect &b,
365  const GA_Attribute *P) const override;
366  bool enlargeBoundingBox(
367  UT_BoundingBox &b,
368  const GA_Attribute *P) const override;
369  void enlargePointBounds(UT_BoundingBox &e) const override;
370  /// @}
371  /// Enlarge a bounding sphere to encompass the primitive. A return value
372  /// of false indicates an error in the operation, most likely an invalid
373  /// P. For any attribute other than the position this method simply
374  /// enlarges the sphere based on the vertex.
375  bool enlargeBoundingSphere(
376  UT_BoundingSphere &b,
377  const GA_Attribute *P) const override;
378 
379  /// Accessor for the local 3x3 affine transform matrix for the primitive.
380  /// For frustum maps, this will be transform as if the taper value is set
381  /// to 1.
382  /// @{
383  void getLocalTransform(UT_Matrix3D &result) const override;
384  void setLocalTransform(const UT_Matrix3D &new_mat3) override;
385  /// @}
386 
387  /// @internal Hack to condition 4x4 matrices that we avoid creating what
388  /// OpenVDB erroneously thinks are singular matrices. Returns true if mat4
389  /// was modified.
390  static bool conditionMatrix(UT_Matrix4D &mat4);
391 
392  /// Visualization accessors
393  /// @{
394  const GEO_VolumeOptions &getVisOptions() const { return myVis; }
395  void setVisOptions(const GEO_VolumeOptions &vis)
396  { setVisualization(vis.myMode, vis.myIso, vis.myDensity, vis.myLod); }
397 
398  void setVisualization(
399  GEO_VolumeVis vismode,
400  fpreal iso,
401  fpreal density,
402  GEO_VolumeVisLod lod = GEO_VOLUMEVISLOD_FULL)
403  {
404  myVis.myMode = vismode;
405  myVis.myIso = iso;
406  myVis.myDensity = density;
407  myVis.myLod = lod;
408  }
409  GEO_VolumeVis getVisualization() const { return myVis.myMode; }
410  fpreal getVisIso() const { return myVis.myIso; }
411  fpreal getVisDensity() const { return myVis.myDensity; }
412  GEO_VolumeVisLod getVisLod() const { return myVis.myLod; }
413  /// @}
414 
415  /// Load the order from a JSON value
416  bool loadOrder(const UT_JSONValue &p);
417 
418  /// @{
419  /// Save/Load vdb to a JSON stream
420  bool saveVDB(UT_JSONWriter &w, const GA_SaveMap &sm,
421  bool as_shmem = false) const;
422  bool loadVDB(UT_JSONParser &p,
423  bool as_shmem = false);
424  /// @}
425 
426  bool saveVisualization(
427  UT_JSONWriter &w,
428  const GA_SaveMap &map) const;
429  bool loadVisualization(
430  UT_JSONParser &p,
431  const GA_LoadMap &map);
432 
433  /// Method to perform quick lookup of vertex without the virtual call
434  GA_Offset fastVertexOffset(GA_Size UT_IF_ASSERT_P(index)) const
435  {
436  UT_ASSERT_P(index < 1);
437  return getVertexOffset();
438  }
439 
440  void setVertexPoint(int i, GA_Offset pt)
441  {
442  if (i == 0)
443  setPointOffset(pt);
444  }
445 
446  /// @brief Computes the total density of the volume, scaled by
447  /// the volume's size. Negative values will be ignored.
448  fpreal calcPositiveDensity() const;
449 
450  SYS_FORCE_INLINE
451  bool hasGrid() const { return myGridAccessor.hasGrid(); }
452 
453  /// @brief If this primitive's grid's voxel data (i.e., its tree)
454  /// is shared, replace the tree with a deep copy of itself that is
455  /// not shared with anyone else.
456  SYS_FORCE_INLINE
457  void makeGridUnique()
458  { myGridAccessor.makeGridUnique(); }
459 
460  /// @brief Returns true if the tree is not shared. If it is not shared,
461  /// one can make destructive edits without makeGridUnique.
462  bool isGridUnique() const
463  { return myGridAccessor.isGridUnique(); }
464 
465  /// @brief Return a reference to this primitive's grid.
466  /// @note Calling setGrid() invalidates all references previously returned.
467  SYS_FORCE_INLINE
468  const openvdb::GridBase & getConstGrid() const
469  { return myGridAccessor.getConstGrid(*this); }
470  /// @brief Return a reference to this primitive's grid.
471  /// @note Calling setGrid() invalidates all references previously returned.
472  SYS_FORCE_INLINE
473  const openvdb::GridBase & getGrid() const
474  { return getConstGrid(); }
475  /// @brief Return a reference to this primitive's grid.
476  /// @note Calling setGrid() invalidates all references previously returned.
477  /// @warning Call makeGridUnique() before modifying the grid's voxel data.
478  SYS_FORCE_INLINE
479  openvdb::GridBase & getGrid()
480  {
481  incrGridUniqueIds();
482  return myGridAccessor.getGrid(*this);
483  }
484 
485  /// @brief Return a shared pointer to this primitive's grid.
486  /// @note Calling setGrid() causes the grid to which the shared pointer
487  /// refers to be disassociated with this primitive.
488  SYS_FORCE_INLINE
489  openvdb::GridBase::ConstPtr getConstGridPtr() const
490  { return myGridAccessor.getConstGridPtr(*this); }
491  /// @brief Return a shared pointer to this primitive's grid.
492  /// @note Calling setGrid() causes the grid to which the shared pointer
493  /// refers to be disassociated with this primitive.
494  SYS_FORCE_INLINE
495  openvdb::GridBase::ConstPtr getGridPtr() const
496  { return getConstGridPtr(); }
497  /// @brief Return a shared pointer to this primitive's grid.
498  /// @note Calling setGrid() causes the grid to which the shared pointer
499  /// refers to be disassociated with this primitive.
500  /// @warning Call makeGridUnique() before modifying the grid's voxel data.
501  SYS_FORCE_INLINE
502  openvdb::GridBase::Ptr getGridPtr()
503  {
504  incrGridUniqueIds();
505  return myGridAccessor.getGridPtr(*this);
506  }
507 
508  /// @brief Set this primitive's grid to a shallow copy of the given grid.
509  /// @note Invalidates all previous getGrid() and getConstGrid() references
510  SYS_FORCE_INLINE
511  void setGrid(const openvdb::GridBase &grid, bool copyPosition=true)
512  {
513  incrGridUniqueIds();
514  myGridAccessor.setGrid(grid, *this, copyPosition);
515  }
516 
517  /// @brief Return a reference to this primitive's grid metadata.
518  /// @note Calling setGrid() invalidates all references previously returned.
519  const openvdb::MetaMap& getConstMetadata() const
520  { return getConstGrid(); }
521  /// @brief Return a reference to this primitive's grid metadata.
522  /// @note Calling setGrid() invalidates all references previously returned.
523  const openvdb::MetaMap& getMetadata() const
524  { return getConstGrid(); }
525  /// @brief Return a reference to this primitive's grid metadata.
526  /// @note Calling setGrid() invalidates all references previously returned.
527  SYS_FORCE_INLINE
528  openvdb::MetaMap& getMetadata()
529  {
530  incrMetadataUniqueId();
531  return myGridAccessor.getGrid(*this);
532  }
533 
534  /// @brief Return the value of this primitive's "name" attribute
535  /// in the given detail.
536  const char * getGridName() const;
537 
538  /// @brief Return this primitive's serial number.
539  /// @details A primitive's serial number never changes.
540  UniqueId getUniqueId() const
541  { return static_cast<UniqueId>(myUniqueId.relaxedLoad()); }
542 
543  /// @brief Return the serial number of this primitive's voxel data.
544  /// @details The serial number is incremented whenever a non-const
545  /// reference or pointer to this primitive's grid is requested
546  /// (whether or not the voxel data is ultimately modified).
547  UniqueId getTreeUniqueId() const
548  { return static_cast<UniqueId>(myTreeUniqueId.relaxedLoad()); }
549  /// @brief Return the serial number of this primitive's grid metadata.
550  /// @details The serial number is incremented whenever a non-const
551  /// reference to the metadata or non-const access to the grid is requested
552  /// (whether or not the metadata is ultimately modified).
553  UniqueId getMetadataUniqueId() const
554  { return static_cast<UniqueId>(myMetadataUniqueId.relaxedLoad()); }
555  /// @brief Return the serial number of this primitive's transform.
556  /// @details The serial number is incremented whenever the transform
557  /// is modified or non-const access to this primitive's grid is requested
558  /// (whether or not the transform is ultimately modified).
559  UniqueId getTransformUniqueId() const
560  { return static_cast<UniqueId>(myTransformUniqueId.relaxedLoad()); }
561 
562 
563  /// @brief If this primitive's grid resolves to one of the listed grid types,
564  /// invoke the functor @a op on the resolved grid.
565  /// @return @c true if the functor was invoked, @c false otherwise
566  ///
567  /// @par Example:
568  /// @code
569  /// auto printOp = [](const openvdb::GridBase& grid) { grid.print(); };
570  /// const GEO_PrimVDB* prim = ...;
571  /// using RealGridTypes = openvdb::TypeList<openvdb::FloatGrid, openvdb::DoubleGrid>;
572  /// // Print info about the primitive's grid if it is a floating-point grid.
573  /// prim->apply<RealGridTypes>(printOp);
574  /// @endcode
575  template<typename GridTypeListT, typename OpT>
576  bool apply(OpT& op) const
577  { return hasGrid() ? getConstGrid().apply<GridTypeListT>(op) : false; }
578 
579  /// @brief If this primitive's grid resolves to one of the listed grid types,
580  /// invoke the functor @a op on the resolved grid.
581  /// @return @c true if the functor was invoked, @c false otherwise
582  /// @details If @a makeUnique is true, deep copy the grid's tree before
583  /// invoking the functor if the tree is shared with other grids.
584  ///
585  /// @par Example:
586  /// @code
587  /// auto fillOp = [](const auto& grid) { // C++14
588  /// // Convert voxels in the given bounding box into background voxels.
589  /// grid.fill(openvdb::CoordBBox(openvdb::Coord(0), openvdb::Coord(99)),
590  /// grid.background(), /*active=*/false);
591  /// };
592  /// GEO_PrimVDB* prim = ...;
593  /// // Set background voxels in the primitive's grid if it is a floating-point grid.
594  /// using RealGridTypes = openvdb::TypeList<openvdb::FloatGrid, openvdb::DoubleGrid>;
595  /// prim->apply<RealGridTypes>(fillOp);
596  /// @endcode
597  template<typename GridTypeListT, typename OpT>
598  bool apply(OpT& op, bool makeUnique = true)
599  {
600  if (hasGrid()) {
601  auto& grid = myGridAccessor.getGrid(*this);
602  if (makeUnique) {
603  auto treePtr = grid.baseTreePtr();
604  if (treePtr.use_count() > 2) { // grid + treePtr = 2
605  // If the grid resolves to one of the listed types and its tree
606  // is shared with other grids, replace the tree with a deep copy.
607  grid.apply<GridTypeListT>([this](openvdb::GridBase& baseGrid) {
608  baseGrid.setTree(baseGrid.constBaseTree().copy());
609  this->incrTreeUniqueId();
610  });
611  }
612  }
613  if (grid.apply<GridTypeListT>(op)) {
614  incrGridUniqueIds();
615  return true;
616  }
617  }
618  return false;
619  }
620 
621 protected:
622  typedef SYS_AtomicCounter AtomicUniqueId; // 64-bit
623 
624  /// Register intrinsic attributes
625  GA_DECLARE_INTRINSICS(override)
626 
627  /// Return true if the given metadata token is an intrinsic
628  static bool isIntrinsicMetadata(const char *name);
629 
630  /// @warning vertexPoint() doesn't check the bounds. Use with caution.
631  GA_Offset vertexPoint(GA_Size) const
632  { return getPointOffset(); }
633 
634  /// Report approximate memory usage, excluding sizeof(*this),
635  /// because the subclass doesn't have access to myGridAccessor.
636  int64 getBaseMemoryUsage() const;
637 
638  // This is called by the subclasses to count the
639  // memory used by this, excluding sizeof(*this).
640  void countBaseMemory(UT_MemoryCounter &counter) const;
641 
642  /// @brief Return an ID number that is guaranteed to be unique across
643  /// all VDB primitives.
644  static UniqueId nextUniqueId();
645 
646  void incrTreeUniqueId()
647  { myTreeUniqueId.maximum(nextUniqueId()); }
648  void incrMetadataUniqueId()
649  { myMetadataUniqueId.maximum(nextUniqueId()); }
650  void incrTransformUniqueId()
651  { myTransformUniqueId.maximum(nextUniqueId()); }
652  void incrGridUniqueIds()
653  {
654  incrTreeUniqueId();
655  incrMetadataUniqueId();
656  incrTransformUniqueId();
657  }
658 
659  /// @brief Replace this primitive's grid with a shallow copy
660  /// of another primitive's grid.
661  void copyGridFrom(const GEO_PrimVDB&, bool copyPosition=true);
662 
663  /// @brief GridAccessor manages access to a GEO_PrimVDB's grid.
664  /// @details In keeping with OpenVDB library conventions, the grid
665  /// is stored internally by shared pointer. However, grid objects
666  /// are never shared among primitives, though their voxel data
667  /// (i.e., their trees) may be shared.
668  /// <p>Among other things, GridAccessor
669  /// - ensures that each primitive's transform and metadata are unique
670  /// (i.e., not shared with anyone else)
671  /// - allows primitives to share voxel data but, via makeGridUnique(),
672  /// provides a way to break the connection
673  /// - ensures that the primitive's transform and the grid's transform
674  /// are in sync (specifically, the translation component, which is
675  /// stored independently as a vertex offset).
676  class OPENVDB_HOUDINI_API GridAccessor
677  {
678  public:
679  SYS_FORCE_INLINE
680  GridAccessor() : myStorageType(UT_VDB_INVALID)
681  { }
682 
683  SYS_FORCE_INLINE
684  void clear()
685  {
686  myGrid.reset();
687  myStorageType = UT_VDB_INVALID;
688  }
689 
690  SYS_FORCE_INLINE
692  getGrid(const GEO_PrimVDB &prim)
693  { updateGridTranslates(prim); return *myGrid; }
694 
695  SYS_FORCE_INLINE
696  const openvdb::GridBase &
697  getConstGrid(const GEO_PrimVDB &prim) const
698  { updateGridTranslates(prim); return *myGrid; }
699 
700  SYS_FORCE_INLINE
702  getGridPtr(const GEO_PrimVDB &prim)
703  { updateGridTranslates(prim); return myGrid; }
704 
705  SYS_FORCE_INLINE
707  getConstGridPtr(const GEO_PrimVDB &prim) const
708  { updateGridTranslates(prim); return myGrid; }
709 
710  // These accessors will ensure the transform's translate is set into
711  // the vertex position.
712  SYS_FORCE_INLINE
713  void setGrid(const openvdb::GridBase& grid, GEO_PrimVDB& prim, bool copyPosition=true)
714  { setGridAdapter(&grid, prim, copyPosition); }
715  SYS_FORCE_INLINE
716  void setTransform(
717  const openvdb::math::Transform &xform,
718  GEO_PrimVDB &prim)
719  { setTransformAdapter(&xform, prim); }
720 
721  void makeGridUnique();
722  bool isGridUnique() const;
723 
724  SYS_FORCE_INLINE
725  UT_VDBType getStorageType() const { return myStorageType; }
726 
727  SYS_FORCE_INLINE
728  bool hasGrid() const { return myGrid != 0; }
729 
730  private:
731  void updateGridTranslates(const GEO_PrimVDB &prim) const;
732 
733  SYS_FORCE_INLINE
734  void setVertexPosition(
735  const openvdb::math::Transform &xform,
736  GEO_PrimVDB &prim)
737  { setVertexPositionAdapter(&xform, prim); }
738 
739  void setGridAdapter(const void* grid, GEO_PrimVDB&, bool copyPosition);
740  void setTransformAdapter(const void* xform, GEO_PrimVDB&);
741  void setVertexPositionAdapter(const void* xform, GEO_PrimVDB&);
742 
743  private:
744  openvdb::GridBase::Ptr myGrid;
745  UT_VDBType myStorageType;
746  };
747 
748 private:
749  void activateIndexBBoxAdapter(
750  const void* bbox,
751  ActivateOperation,
752  bool setvalue, fpreal value);
753 
754 
755  GridAccessor myGridAccessor;
756 
757  GEO_VolumeOptions myVis;
758 
759  mutable CE_VDBGrid *myCEGrid;
760  mutable bool myCEGridAuthorative;
761  mutable bool myCEGridIsOwned;
762 
763  AtomicUniqueId myUniqueId;
764  AtomicUniqueId myTreeUniqueId;
765  AtomicUniqueId myMetadataUniqueId;
766  AtomicUniqueId myTransformUniqueId;
767 
768 }; // class GEO_PrimVDB
769 
770 
771 #ifndef SESI_OPENVDB
772 namespace openvdb_houdini {
773 using ::GEO_VolumeOptions;
774 using ::GEO_PrimVDB;
775 }
776 #endif
777 
778 
779 ////////////////////////////////////////
780 
781 
782 namespace UT_VDBUtils {
783 
784 // This overload of UT_VDBUtils::callTypedGrid(), for GridBaseType = GEO_PrimVDB,
785 // calls makeGridUnique() on the primitive just before instantiating and
786 // invoking the functor on the primitive's grid. This delays the call
787 // to makeGridUnique() until it is known to be necessary and thus avoids
788 // making deep copies of grids of types that won't be processed.
789 template<typename GridType, typename OpType>
790 inline void
791 callTypedGrid(GEO_PrimVDB& prim, OpType& op)
792 {
793  prim.makeGridUnique();
794  op.template operator()<GridType>(*(UTverify_cast<GridType*>(&prim.getGrid())));
795 }
796 
797 // Overload of callTypedGrid() for GridBaseType = const GEO_PrimVDB
798 template<typename GridType, typename OpType>
799 inline void
800 callTypedGrid(const GEO_PrimVDB& prim, OpType& op)
801 {
802  op.template operator()<GridType>(*(UTverify_cast<const GridType*>(&prim.getConstGrid())));
803 }
804 
805 } // namespace UT_VDBUtils
806 
807 // Define UTvdbProcessTypedGrid*() (see UT_VDBUtils.h) for grids
808 // belonging to primitives, for various subsets of grid types.
809 UT_VDB_DECL_PROCESS_TYPED_GRID(GEO_PrimVDB&)
810 UT_VDB_DECL_PROCESS_TYPED_GRID(const GEO_PrimVDB&)
811 
812 
813 ////////////////////////////////////////
814 
815 
816 /// @brief Utility function to process the grid of a const primitive using functor @a op.
817 /// @details It will invoke @code op.operator()<GridT>(const GridT &grid) @endcode
818 /// @{
819 template <typename OpT>
820 inline bool GEOvdbProcessTypedGrid(const GEO_PrimVDB &vdb, OpT &op)
821 {
822  return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb.getGrid(), op);
823 }
824 
825 template <typename OpT>
826 inline bool GEOvdbProcessTypedGridReal(const GEO_PrimVDB &vdb, OpT &op)
827 {
828  return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb.getGrid(), op);
829 }
830 
831 template <typename OpT>
832 inline bool GEOvdbProcessTypedGridScalar(const GEO_PrimVDB &vdb, OpT &op)
833 {
834  return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb.getGrid(), op);
835 }
836 
837 template <typename OpT>
838 inline bool GEOvdbProcessTypedGridTopology(const GEO_PrimVDB &vdb, OpT &op)
839 {
840  return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb.getGrid(), op);
841 }
842 
843 template <typename OpT>
844 inline bool GEOvdbProcessTypedGridVec3(const GEO_PrimVDB &vdb, OpT &op)
845 {
846  return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb.getGrid(), op);
847 }
848 
849 template <typename OpT>
850 inline bool GEOvdbProcessTypedGridPoint(const GEO_PrimVDB &vdb, OpT &op)
851 {
852  return UTvdbProcessTypedGridPoint(vdb.getStorageType(), vdb.getGrid(), op);
853 }
854 /// @}
855 
856 /// @brief Utility function to process the grid of a primitive using functor @a op.
857 /// @param vdb the primitive whose grid is to be processed
858 /// @param op a functor with a call operator of the form
859 /// @code op.operator()<GridT>(GridT &grid) @endcode
860 /// @param makeUnique if @c true, call <tt>vdb.makeGridUnique()</tt> before
861 /// invoking the functor
862 /// @{
863 template <typename OpT>
864 inline bool GEOvdbProcessTypedGrid(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
865 {
866  if (makeUnique) return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb, op);
867  return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb.getGrid(), op);
868 }
869 
870 template <typename OpT>
871 inline bool GEOvdbProcessTypedGridReal(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
872 {
873  if (makeUnique) return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb, op);
874  return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb.getGrid(), op);
875 }
876 
877 template <typename OpT>
878 inline bool GEOvdbProcessTypedGridScalar(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
879 {
880  if (makeUnique) return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb, op);
881  return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb.getGrid(), op);
882 }
883 
884 template <typename OpT>
885 inline bool GEOvdbProcessTypedGridTopology(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
886 {
887  if (makeUnique) return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb, op);
888  return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb.getGrid(), op);
889 }
890 
891 template <typename OpT>
892 inline bool GEOvdbProcessTypedGridVec3(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
893 {
894  if (makeUnique) return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb, op);
895  return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb.getGrid(), op);
896 }
897 
898 template <typename OpT>
899 inline bool GEOvdbProcessTypedGridPoint(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
900 {
901  if (makeUnique) return UTvdbProcessTypedGridPoint(vdb.getStorageType(), vdb, op);
902  return UTvdbProcessTypedGridPoint(vdb.getStorageType(), vdb.getGrid(), op);
903 }
904 /// @}
905 
906 #endif // __HDK_GEO_PrimVDB__
907 
908 #endif // SESI_OPENVDB || SESI_OPENVDB_PRIM
SharedPtr< const GridBase > ConstPtr
Definition: Grid.h:81
GridType::Ptr normalize(const GridType &grid, bool threaded, InterruptT *interrupt)
Normalize the vectors of the given vector-valued grid.
Definition: GridOperators.h:1068
bool hasGrid(const std::string &fileName, const std::string &gridName)
Return true if the file contains a grid with the specified name.
Definition: IO.h:707
Abstract base class for typed grids.
Definition: Grid.h:77
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
#define OPENVDB_HOUDINI_API
Definition: Platform.h:262
static fileSize_t write(std::ostream &os, const GridHandle< BufferT > &handle, Codec codec)
static void read(std::istream &is, GridHandle< BufferT > &handle, Codec codec)
BBox< Coord > CoordBBox
Definition: NanoVDB.h:1658
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:19
TreeBase::Ptr baseTreePtr()
Return a pointer to this grid&#39;s tree, which might be shared with other grids. The pointer is guarante...
Definition: Grid.h:1240
ValueT value
Definition: GridBuilder.h:1287
bool apply(OpT &) const
If this grid resolves to one of the listed grid types, invoke the given functor on the resolved grid...
Definition: Grid.h:1811
Definition: AttributeTransferUtil.h:34
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216