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