OpenVDB: openvdb_houdini/GEO_PrimVDB.h Source File

OpenVDB 9.1.0

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