OpenVDB 10.0.1
Loading...
Searching...
No Matches
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
29namespace openvdb_houdini {
30using ::GEO_VolumeOptions;
31using ::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
52class GEO_Detail;
53class GEO_PrimVolume;
54class GEO_PrimVolumeXform;
55class UT_MemoryCounter;
56
57class CE_VDBGrid;
58
59class OPENVDB_HOUDINI_API GEO_PrimVDB : public GEO_Primitive
60{
61public:
62 typedef uint64 UniqueId;
63
64protected:
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;
70public:
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
295 /// Computes the voxel diameter by taking a step in x, y, and z
296 /// converting to world space and taking the length of that vector.
297 fpreal getVoxelDiameter() const;
298
299 /// Returns the length of the voxel when you take an x, y, and z step
300 UT_Vector3 getVoxelSize() const;
301
302 /// Compute useful aggregate properties of the volume.
303 fpreal calcMinimum() const;
304 fpreal calcMaximum() const;
305 fpreal calcAverage() const;
306
307 /// VDBs may either be unbounded, or created with a specific frustum
308 /// range. The latter is important for tapered VDBs that otherwise
309 /// have a singularity at the camera location. Tools can use the
310 /// presence of an idxbox as a clipping box in index space.
311 /// This does *NOT* relate to getRes - it may be much larger or
312 /// even in some cases smaller.
313 bool getFrustumBounds(UT_BoundingBox &idxbox) const;
314
315 enum ActivateOperation
316 {
317 ACTIVATE_UNION, // Activate anything in source
318 ACTIVATE_INTERSECT, // Deactivate anything not in source
319 ACTIVATE_SUBTRACT, // Deactivate anything in source
320 ACTIVATE_COPY // Set our activation to match source
321 };
322
323 /// Activates voxels given an *index* space bounding box. This
324 /// is an inclusive box.
325 /// If this is Frustum VDB, the activation will be clipped by that.
326 /// Setting the value only takes effect if the voxels are activated,
327 /// deactivated voxels are set to the background.
328 void activateIndexBBox(
329 const openvdb::CoordBBox& bbox,
330 ActivateOperation operation,
331 bool setvalue, fpreal value)
332 {
333 activateIndexBBoxAdapter(
334 &bbox, operation, setvalue, value);
335 }
336
337 /// Activates all of the voxels in this VDB that are touched
338 /// by active voxels in the source.
339 /// If ignore_transform is true, voxels will be activated
340 /// by grid index instead of world space position.
341 void activateByVDB(const GEO_PrimVDB *vdb,
342 ActivateOperation operation,
343 bool setvalue, fpreal value,
344 bool ignore_transform=false);
345
346 /// @{
347 /// Though not strictly required (i.e. not pure virtual), these methods
348 /// should be implemented for proper behaviour.
349 GEO_Primitive *copy(int preserve_shared_pts = 0) const override;
350
351 // Have we been deactivated and stashed?
352 void stashed(bool beingstashed,
353 GA_Offset offset=GA_INVALID_OFFSET) override;
354
355 /// @}
356
357 /// @{
358 /// Optional interface methods. Though not required, implementing these
359 /// will give better behaviour for the new primitive.
360 UT_Vector3 baryCenter() const override;
361 fpreal calcVolume(const UT_Vector3 &refpt) const override;
362 /// Calculate the surface area of the active voxels where
363 /// a voxel face contributes if it borders an inactive voxel.
364 fpreal calcArea() const override;
365 /// @}
366
367 /// @{
368 /// Enlarge a bounding box by the bounding box of the primitive. A
369 /// return value of false indicates an error in the operation, most
370 /// likely an invalid P. For any attribute other than the position
371 /// these methods simply enlarge the bounding box based on the vertex.
372 bool enlargeBoundingBox(
373 UT_BoundingRect &b,
374 const GA_Attribute *P) const override;
375 bool enlargeBoundingBox(
376 UT_BoundingBox &b,
377 const GA_Attribute *P) const override;
378 void enlargePointBounds(UT_BoundingBox &e) const override;
379 /// @}
380 /// Enlarge a bounding sphere to encompass the primitive. A return value
381 /// of false indicates an error in the operation, most likely an invalid
382 /// P. For any attribute other than the position this method simply
383 /// enlarges the sphere based on the vertex.
384 bool enlargeBoundingSphere(
385 UT_BoundingSphere &b,
386 const GA_Attribute *P) const override;
387
388 /// Accessor for the local 3x3 affine transform matrix for the primitive.
389 /// For frustum maps, this will be transform as if the taper value is set
390 /// to 1.
391 /// @{
392 void getLocalTransform(UT_Matrix3D &result) const override;
393 void setLocalTransform(const UT_Matrix3D &new_mat3) override;
394 /// @}
395
396 /// @internal Hack to condition 4x4 matrices that we avoid creating what
397 /// OpenVDB erroneously thinks are singular matrices. Returns true if mat4
398 /// was modified.
399 static bool conditionMatrix(UT_Matrix4D &mat4);
400
401 /// Visualization accessors
402 /// @{
403 const GEO_VolumeOptions &getVisOptions() const { return myVis; }
404 void setVisOptions(const GEO_VolumeOptions &vis)
405 { setVisualization(vis.myMode, vis.myIso, vis.myDensity, vis.myLod); }
406
407 void setVisualization(
408 GEO_VolumeVis vismode,
409 fpreal iso,
410 fpreal density,
411 GEO_VolumeVisLod lod = GEO_VOLUMEVISLOD_FULL)
412 {
413 myVis.myMode = vismode;
414 myVis.myIso = iso;
415 myVis.myDensity = density;
416 myVis.myLod = lod;
417 }
418 GEO_VolumeVis getVisualization() const { return myVis.myMode; }
419 fpreal getVisIso() const { return myVis.myIso; }
420 fpreal getVisDensity() const { return myVis.myDensity; }
421 GEO_VolumeVisLod getVisLod() const { return myVis.myLod; }
422 /// @}
423
424 /// Load the order from a JSON value
425 bool loadOrder(const UT_JSONValue &p);
426
427 /// @{
428 /// Save/Load vdb to a JSON stream
429 bool saveVDB(UT_JSONWriter &w, const GA_SaveMap &sm,
430 bool as_shmem = false) const;
431 bool loadVDB(UT_JSONParser &p,
432 bool as_shmem = false);
433 /// @}
434
435 bool saveVisualization(
436 UT_JSONWriter &w,
437 const GA_SaveMap &map) const;
438 bool loadVisualization(
439 UT_JSONParser &p,
440 const GA_LoadMap &map);
441
442 /// Method to perform quick lookup of vertex without the virtual call
443 GA_Offset fastVertexOffset(GA_Size UT_IF_ASSERT_P(index)) const
444 {
445 UT_ASSERT_P(index < 1);
446 return getVertexOffset();
447 }
448
449 void setVertexPoint(int i, GA_Offset pt)
450 {
451 if (i == 0)
452 setPointOffset(pt);
453 }
454
455 /// @brief Computes the total density of the volume, scaled by
456 /// the volume's size. Negative values will be ignored.
457 fpreal calcPositiveDensity() const;
458
459 SYS_FORCE_INLINE
460 bool hasGrid() const { return myGridAccessor.hasGrid(); }
461
462 /// @brief If this primitive's grid's voxel data (i.e., its tree)
463 /// is shared, replace the tree with a deep copy of itself that is
464 /// not shared with anyone else.
465 SYS_FORCE_INLINE
466 void makeGridUnique()
467 { myGridAccessor.makeGridUnique(); }
468
469 /// @brief Returns true if the tree is not shared. If it is not shared,
470 /// one can make destructive edits without makeGridUnique.
471 bool isGridUnique() const
472 { return myGridAccessor.isGridUnique(); }
473
474 /// @brief Return a reference to this primitive's grid.
475 /// @note Calling setGrid() invalidates all references previously returned.
476 SYS_FORCE_INLINE
477 const openvdb::GridBase & getConstGrid() const
478 { return myGridAccessor.getConstGrid(*this); }
479 /// @brief Return a reference to this primitive's grid.
480 /// @note Calling setGrid() invalidates all references previously returned.
481 SYS_FORCE_INLINE
482 const openvdb::GridBase & getGrid() const
483 { return getConstGrid(); }
484 /// @brief Return a reference to this primitive's grid.
485 /// @note Calling setGrid() invalidates all references previously returned.
486 /// @warning Call makeGridUnique() before modifying the grid's voxel data.
487 SYS_FORCE_INLINE
488 openvdb::GridBase & getGrid()
489 {
490 incrGridUniqueIds();
491 return myGridAccessor.getGrid(*this);
492 }
493
494 /// @brief Return a shared pointer to this primitive's grid.
495 /// @note Calling setGrid() causes the grid to which the shared pointer
496 /// refers to be disassociated with this primitive.
497 SYS_FORCE_INLINE
498 openvdb::GridBase::ConstPtr getConstGridPtr() const
499 { return myGridAccessor.getConstGridPtr(*this); }
500 /// @brief Return a shared pointer to this primitive's grid.
501 /// @note Calling setGrid() causes the grid to which the shared pointer
502 /// refers to be disassociated with this primitive.
503 SYS_FORCE_INLINE
504 openvdb::GridBase::ConstPtr getGridPtr() const
505 { return getConstGridPtr(); }
506 /// @brief Return a shared pointer to this primitive's grid.
507 /// @note Calling setGrid() causes the grid to which the shared pointer
508 /// refers to be disassociated with this primitive.
509 /// @warning Call makeGridUnique() before modifying the grid's voxel data.
510 SYS_FORCE_INLINE
511 openvdb::GridBase::Ptr getGridPtr()
512 {
513 incrGridUniqueIds();
514 return myGridAccessor.getGridPtr(*this);
515 }
516
517 /// @brief Set this primitive's grid to a shallow copy of the given grid.
518 /// @note Invalidates all previous getGrid() and getConstGrid() references
519 SYS_FORCE_INLINE
520 void setGrid(const openvdb::GridBase &grid, bool copyPosition=true)
521 {
522 incrGridUniqueIds();
523 myGridAccessor.setGrid(grid, *this, copyPosition);
524 }
525
526 /// @brief Return a reference to this primitive's grid metadata.
527 /// @note Calling setGrid() invalidates all references previously returned.
528 const openvdb::MetaMap& getConstMetadata() const
529 { return getConstGrid(); }
530 /// @brief Return a reference to this primitive's grid metadata.
531 /// @note Calling setGrid() invalidates all references previously returned.
532 const openvdb::MetaMap& getMetadata() const
533 { return getConstGrid(); }
534 /// @brief Return a reference to this primitive's grid metadata.
535 /// @note Calling setGrid() invalidates all references previously returned.
536 SYS_FORCE_INLINE
537 openvdb::MetaMap& getMetadata()
538 {
539 incrMetadataUniqueId();
540 return myGridAccessor.getGrid(*this);
541 }
542
543 /// @brief Return the value of this primitive's "name" attribute
544 /// in the given detail.
545 const char * getGridName() const;
546
547 /// @brief Return this primitive's serial number.
548 /// @details A primitive's serial number never changes.
549 UniqueId getUniqueId() const
550 { return static_cast<UniqueId>(myUniqueId.relaxedLoad()); }
551
552 /// @brief Return the serial number of this primitive's voxel data.
553 /// @details The serial number is incremented whenever a non-const
554 /// reference or pointer to this primitive's grid is requested
555 /// (whether or not the voxel data is ultimately modified).
556 UniqueId getTreeUniqueId() const
557 { return static_cast<UniqueId>(myTreeUniqueId.relaxedLoad()); }
558 /// @brief Return the serial number of this primitive's grid metadata.
559 /// @details The serial number is incremented whenever a non-const
560 /// reference to the metadata or non-const access to the grid is requested
561 /// (whether or not the metadata is ultimately modified).
562 UniqueId getMetadataUniqueId() const
563 { return static_cast<UniqueId>(myMetadataUniqueId.relaxedLoad()); }
564 /// @brief Return the serial number of this primitive's transform.
565 /// @details The serial number is incremented whenever the transform
566 /// is modified or non-const access to this primitive's grid is requested
567 /// (whether or not the transform is ultimately modified).
568 UniqueId getTransformUniqueId() const
569 { return static_cast<UniqueId>(myTransformUniqueId.relaxedLoad()); }
570
571
572 /// @brief If this primitive's grid resolves to one of the listed grid types,
573 /// invoke the functor @a op on the resolved grid.
574 /// @return @c true if the functor was invoked, @c false otherwise
575 ///
576 /// @par Example:
577 /// @code
578 /// auto printOp = [](const openvdb::GridBase& grid) { grid.print(); };
579 /// const GEO_PrimVDB* prim = ...;
580 /// using RealGridTypes = openvdb::TypeList<openvdb::FloatGrid, openvdb::DoubleGrid>;
581 /// // Print info about the primitive's grid if it is a floating-point grid.
582 /// prim->apply<RealGridTypes>(printOp);
583 /// @endcode
584 template<typename GridTypeListT, typename OpT>
585 bool apply(OpT& op) const
586 { return hasGrid() ? getConstGrid().apply<GridTypeListT>(op) : false; }
587
588 /// @brief If this primitive's grid resolves to one of the listed grid types,
589 /// invoke the functor @a op on the resolved grid.
590 /// @return @c true if the functor was invoked, @c false otherwise
591 /// @details If @a makeUnique is true, deep copy the grid's tree before
592 /// invoking the functor if the tree is shared with other grids.
593 ///
594 /// @par Example:
595 /// @code
596 /// auto fillOp = [](const auto& grid) { // C++14
597 /// // Convert voxels in the given bounding box into background voxels.
598 /// grid.fill(openvdb::CoordBBox(openvdb::Coord(0), openvdb::Coord(99)),
599 /// grid.background(), /*active=*/false);
600 /// };
601 /// GEO_PrimVDB* prim = ...;
602 /// // Set background voxels in the primitive's grid if it is a floating-point grid.
603 /// using RealGridTypes = openvdb::TypeList<openvdb::FloatGrid, openvdb::DoubleGrid>;
604 /// prim->apply<RealGridTypes>(fillOp);
605 /// @endcode
606 template<typename GridTypeListT, typename OpT>
607 bool apply(OpT& op, bool makeUnique = true)
608 {
609 if (hasGrid()) {
610 auto& grid = myGridAccessor.getGrid(*this);
611 if (makeUnique) {
612 auto treePtr = grid.baseTreePtr();
613 if (treePtr.use_count() > 2) { // grid + treePtr = 2
614 // If the grid resolves to one of the listed types and its tree
615 // is shared with other grids, replace the tree with a deep copy.
616 grid.apply<GridTypeListT>([this](openvdb::GridBase& baseGrid) {
617 baseGrid.setTree(baseGrid.constBaseTree().copy());
618 this->incrTreeUniqueId();
619 });
620 }
621 }
622 if (grid.apply<GridTypeListT>(op)) {
623 incrGridUniqueIds();
624 return true;
625 }
626 }
627 return false;
628 }
629
630protected:
631 typedef SYS_AtomicCounter AtomicUniqueId; // 64-bit
632
633 /// Register intrinsic attributes
634 GA_DECLARE_INTRINSICS(override)
635
636 /// Return true if the given metadata token is an intrinsic
637 static bool isIntrinsicMetadata(const char *name);
638
639 /// @warning vertexPoint() doesn't check the bounds. Use with caution.
640 GA_Offset vertexPoint(GA_Size) const
641 { return getPointOffset(); }
642
643 /// Report approximate memory usage, excluding sizeof(*this),
644 /// because the subclass doesn't have access to myGridAccessor.
645 int64 getBaseMemoryUsage() const;
646
647 // This is called by the subclasses to count the
648 // memory used by this, excluding sizeof(*this).
649 void countBaseMemory(UT_MemoryCounter &counter) const;
650
651 /// @brief Return an ID number that is guaranteed to be unique across
652 /// all VDB primitives.
653 static UniqueId nextUniqueId();
654
655 void incrTreeUniqueId()
656 { myTreeUniqueId.maximum(nextUniqueId()); }
657 void incrMetadataUniqueId()
658 { myMetadataUniqueId.maximum(nextUniqueId()); }
659 void incrTransformUniqueId()
660 { myTransformUniqueId.maximum(nextUniqueId()); }
661 void incrGridUniqueIds()
662 {
663 incrTreeUniqueId();
664 incrMetadataUniqueId();
665 incrTransformUniqueId();
666 }
667
668 /// @brief Replace this primitive's grid with a shallow copy
669 /// of another primitive's grid.
670 void copyGridFrom(const GEO_PrimVDB&, bool copyPosition=true);
671
672 /// @brief GridAccessor manages access to a GEO_PrimVDB's grid.
673 /// @details In keeping with OpenVDB library conventions, the grid
674 /// is stored internally by shared pointer. However, grid objects
675 /// are never shared among primitives, though their voxel data
676 /// (i.e., their trees) may be shared.
677 /// <p>Among other things, GridAccessor
678 /// - ensures that each primitive's transform and metadata are unique
679 /// (i.e., not shared with anyone else)
680 /// - allows primitives to share voxel data but, via makeGridUnique(),
681 /// provides a way to break the connection
682 /// - ensures that the primitive's transform and the grid's transform
683 /// are in sync (specifically, the translation component, which is
684 /// stored independently as a vertex offset).
685 class OPENVDB_HOUDINI_API GridAccessor
686 {
687 public:
688 SYS_FORCE_INLINE
689 GridAccessor() : myStorageType(UT_VDB_INVALID)
690 { }
691
692 SYS_FORCE_INLINE
693 void clear()
694 {
695 myGrid.reset();
696 myStorageType = UT_VDB_INVALID;
697 }
698
699 SYS_FORCE_INLINE
701 getGrid(const GEO_PrimVDB &prim)
702 { updateGridTranslates(prim); return *myGrid; }
703
704 SYS_FORCE_INLINE
705 const openvdb::GridBase &
706 getConstGrid(const GEO_PrimVDB &prim) const
707 { updateGridTranslates(prim); return *myGrid; }
708
709 SYS_FORCE_INLINE
710 openvdb::GridBase::Ptr
711 getGridPtr(const GEO_PrimVDB &prim)
712 { updateGridTranslates(prim); return myGrid; }
713
714 SYS_FORCE_INLINE
715 openvdb::GridBase::ConstPtr
716 getConstGridPtr(const GEO_PrimVDB &prim) const
717 { updateGridTranslates(prim); return myGrid; }
718
719 // These accessors will ensure the transform's translate is set into
720 // the vertex position.
721 SYS_FORCE_INLINE
722 void setGrid(const openvdb::GridBase& grid, GEO_PrimVDB& prim, bool copyPosition=true)
723 { setGridAdapter(&grid, prim, copyPosition); }
724 SYS_FORCE_INLINE
725 void setTransform(
726 const openvdb::math::Transform &xform,
727 GEO_PrimVDB &prim)
728 { setTransformAdapter(&xform, prim); }
729
730 void makeGridUnique();
731 bool isGridUnique() const;
732
733 SYS_FORCE_INLINE
734 UT_VDBType getStorageType() const { return myStorageType; }
735
736 SYS_FORCE_INLINE
737 bool hasGrid() const { return myGrid != 0; }
738
739 private:
740 void updateGridTranslates(const GEO_PrimVDB &prim) const;
741
742 SYS_FORCE_INLINE
743 void setVertexPosition(
744 const openvdb::math::Transform &xform,
745 GEO_PrimVDB &prim)
746 { setVertexPositionAdapter(&xform, prim); }
747
748 void setGridAdapter(const void* grid, GEO_PrimVDB&, bool copyPosition);
749 void setTransformAdapter(const void* xform, GEO_PrimVDB&);
750 void setVertexPositionAdapter(const void* xform, GEO_PrimVDB&);
751
752 private:
753 openvdb::GridBase::Ptr myGrid;
754 UT_VDBType myStorageType;
755 };
756
757private:
758 void activateIndexBBoxAdapter(
759 const void* bbox,
760 ActivateOperation,
761 bool setvalue, fpreal value);
762
763
764 GridAccessor myGridAccessor;
765
766 GEO_VolumeOptions myVis;
767
768 mutable CE_VDBGrid *myCEGrid;
769 mutable bool myCEGridAuthorative;
770 mutable bool myCEGridIsOwned;
771
772 AtomicUniqueId myUniqueId;
773 AtomicUniqueId myTreeUniqueId;
774 AtomicUniqueId myMetadataUniqueId;
775 AtomicUniqueId myTransformUniqueId;
776
777}; // class GEO_PrimVDB
778
779
780#ifndef SESI_OPENVDB
781namespace openvdb_houdini {
782using ::GEO_VolumeOptions;
783using ::GEO_PrimVDB;
784}
785#endif
786
787
788////////////////////////////////////////
789
790
791namespace UT_VDBUtils {
792
793// This overload of UT_VDBUtils::callTypedGrid(), for GridBaseType = GEO_PrimVDB,
794// calls makeGridUnique() on the primitive just before instantiating and
795// invoking the functor on the primitive's grid. This delays the call
796// to makeGridUnique() until it is known to be necessary and thus avoids
797// making deep copies of grids of types that won't be processed.
798template<typename GridType, typename OpType>
799inline void
800callTypedGrid(GEO_PrimVDB& prim, OpType& op)
801{
802 prim.makeGridUnique();
803 op.template operator()<GridType>(*(UTverify_cast<GridType*>(&prim.getGrid())));
804}
805
806// Overload of callTypedGrid() for GridBaseType = const GEO_PrimVDB
807template<typename GridType, typename OpType>
808inline void
809callTypedGrid(const GEO_PrimVDB& prim, OpType& op)
810{
811 op.template operator()<GridType>(*(UTverify_cast<const GridType*>(&prim.getConstGrid())));
812}
813
814} // namespace UT_VDBUtils
815
816// Define UTvdbProcessTypedGrid*() (see UT_VDBUtils.h) for grids
817// belonging to primitives, for various subsets of grid types.
818UT_VDB_DECL_PROCESS_TYPED_GRID(GEO_PrimVDB&)
819UT_VDB_DECL_PROCESS_TYPED_GRID(const GEO_PrimVDB&)
820
821
822////////////////////////////////////////
823
824
825/// @brief Utility function to process the grid of a const primitive using functor @a op.
826/// @details It will invoke @code op.operator()<GridT>(const GridT &grid) @endcode
827/// @{
828template <typename OpT>
829inline bool GEOvdbProcessTypedGrid(const GEO_PrimVDB &vdb, OpT &op)
830{
831 return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb.getGrid(), op);
832}
833
834template <typename OpT>
835inline bool GEOvdbProcessTypedGridReal(const GEO_PrimVDB &vdb, OpT &op)
836{
837 return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb.getGrid(), op);
838}
839
840template <typename OpT>
841inline bool GEOvdbProcessTypedGridScalar(const GEO_PrimVDB &vdb, OpT &op)
842{
843 return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb.getGrid(), op);
844}
845
846template <typename OpT>
847inline bool GEOvdbProcessTypedGridTopology(const GEO_PrimVDB &vdb, OpT &op)
848{
849 return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb.getGrid(), op);
850}
851
852template <typename OpT>
853inline bool GEOvdbProcessTypedGridVec3(const GEO_PrimVDB &vdb, OpT &op)
854{
855 return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb.getGrid(), op);
856}
857
858template <typename OpT>
859inline bool GEOvdbProcessTypedGridPoint(const GEO_PrimVDB &vdb, OpT &op)
860{
861 return UTvdbProcessTypedGridPoint(vdb.getStorageType(), vdb.getGrid(), op);
862}
863/// @}
864
865/// @brief Utility function to process the grid of a primitive using functor @a op.
866/// @param vdb the primitive whose grid is to be processed
867/// @param op a functor with a call operator of the form
868/// @code op.operator()<GridT>(GridT &grid) @endcode
869/// @param makeUnique if @c true, call <tt>vdb.makeGridUnique()</tt> before
870/// invoking the functor
871/// @{
872template <typename OpT>
873inline bool GEOvdbProcessTypedGrid(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
874{
875 if (makeUnique) return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb, op);
876 return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb.getGrid(), op);
877}
878
879template <typename OpT>
880inline bool GEOvdbProcessTypedGridReal(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
881{
882 if (makeUnique) return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb, op);
883 return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb.getGrid(), op);
884}
885
886template <typename OpT>
887inline bool GEOvdbProcessTypedGridScalar(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
888{
889 if (makeUnique) return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb, op);
890 return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb.getGrid(), op);
891}
892
893template <typename OpT>
894inline bool GEOvdbProcessTypedGridTopology(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
895{
896 if (makeUnique) return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb, op);
897 return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb.getGrid(), op);
898}
899
900template <typename OpT>
901inline bool GEOvdbProcessTypedGridVec3(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
902{
903 if (makeUnique) return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb, op);
904 return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb.getGrid(), op);
905}
906
907template <typename OpT>
908inline bool GEOvdbProcessTypedGridPoint(GEO_PrimVDB &vdb, OpT &op, bool makeUnique = true)
909{
910 if (makeUnique) return UTvdbProcessTypedGridPoint(vdb.getStorageType(), vdb, op);
911 return UTvdbProcessTypedGridPoint(vdb.getStorageType(), vdb.getGrid(), op);
912}
913/// @}
914
915#endif // __HDK_GEO_PrimVDB__
916
917#endif // SESI_OPENVDB || SESI_OPENVDB_PRIM
ValueT value
Definition: GridBuilder.h:1290
#define OPENVDB_HOUDINI_API
Definition: Platform.h:259
Abstract base class for typed grids.
Definition: Grid.h:78
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
TreeBase::Ptr baseTreePtr()
Return a pointer to this grid's tree, which might be shared with other grids. The pointer is guarante...
Definition: Grid.h:1227
Container that maps names (strings) to values of arbitrary types.
Definition: MetaMap.h:20
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:249
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:709
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:243
Definition: AttributeTransferUtil.h:34