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