OpenVDB 11.0.0
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 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
631protected:
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
711 openvdb::GridBase::Ptr
712 getGridPtr(const GEO_PrimVDB &prim)
713 { updateGridTranslates(prim); return myGrid; }
714
715 SYS_FORCE_INLINE
716 openvdb::GridBase::ConstPtr
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
758private:
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
782namespace openvdb_houdini {
783using ::GEO_VolumeOptions;
784using ::GEO_PrimVDB;
785}
786#endif
787
788
789////////////////////////////////////////
790
791
792namespace 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.
799template<typename GridType, typename OpType>
800inline void
801callTypedGrid(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
808template<typename GridType, typename OpType>
809inline void
810callTypedGrid(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.
819UT_VDB_DECL_PROCESS_TYPED_GRID(GEO_PrimVDB&)
820UT_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/// @{
829template <typename OpT>
830inline bool GEOvdbProcessTypedGrid(const GEO_PrimVDB &vdb, OpT &op)
831{
832 return UTvdbProcessTypedGrid(vdb.getStorageType(), vdb.getGrid(), op);
833}
834
835template <typename OpT>
836inline bool GEOvdbProcessTypedGridReal(const GEO_PrimVDB &vdb, OpT &op)
837{
838 return UTvdbProcessTypedGridReal(vdb.getStorageType(), vdb.getGrid(), op);
839}
840
841template <typename OpT>
842inline bool GEOvdbProcessTypedGridScalar(const GEO_PrimVDB &vdb, OpT &op)
843{
844 return UTvdbProcessTypedGridScalar(vdb.getStorageType(), vdb.getGrid(), op);
845}
846
847template <typename OpT>
848inline bool GEOvdbProcessTypedGridTopology(const GEO_PrimVDB &vdb, OpT &op)
849{
850 return UTvdbProcessTypedGridTopology(vdb.getStorageType(), vdb.getGrid(), op);
851}
852
853template <typename OpT>
854inline bool GEOvdbProcessTypedGridVec3(const GEO_PrimVDB &vdb, OpT &op)
855{
856 return UTvdbProcessTypedGridVec3(vdb.getStorageType(), vdb.getGrid(), op);
857}
858
859template <typename OpT>
860inline 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/// @{
873template <typename OpT>
874inline 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
880template <typename OpT>
881inline 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
887template <typename OpT>
888inline 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
894template <typename OpT>
895inline 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
901template <typename OpT>
902inline 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
908template <typename OpT>
909inline 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
#define OPENVDB_HOUDINI_API
Definition Platform.h:282
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:251
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
GridType
List of types that are currently supported by NanoVDB.
Definition NanoVDB.h:317
Definition AttributeTransferUtil.h:34