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