OpenVDB  9.0.1
AttributeTransferUtil.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @file AttributeTransferUtil.h
5 /// @author FX R&D Simulation team
6 /// @brief Utility methods used by the From/To Polygons and From Particles SOPs
7 
8 #ifndef OPENVDB_HOUDINI_ATTRIBUTE_TRANSFER_UTIL_HAS_BEEN_INCLUDED
9 #define OPENVDB_HOUDINI_ATTRIBUTE_TRANSFER_UTIL_HAS_BEEN_INCLUDED
10 
11 #include "Utils.h"
12 
13 #include <openvdb/openvdb.h>
14 #include <openvdb/math/Proximity.h>
16 #include <openvdb/util/Util.h>
17 
18 #include <GA/GA_PageIterator.h>
19 #include <GA/GA_SplittableRange.h>
20 #include <GEO/GEO_PrimPolySoup.h>
21 #include <SYS/SYS_Types.h>
22 
23 #include <algorithm> // for std::sort()
24 #include <cmath> // for std::floor()
25 #include <limits>
26 #include <memory>
27 #include <set>
28 #include <sstream>
29 #include <string>
30 #include <type_traits>
31 #include <vector>
32 
33 
34 namespace openvdb_houdini {
35 
36 ////////////////////////////////////////
37 
38 /// Get OpenVDB specific value, by calling GA_AIFTuple::get()
39 /// with appropriate arguments.
40 
41 template <typename ValueType> inline ValueType
42 evalAttr(const GA_Attribute* atr, const GA_AIFTuple* aif,
43  GA_Offset off, int idx)
44 {
45  fpreal64 value;
46  aif->get(atr, off, value, idx);
47  return ValueType(value);
48 }
49 
50 template <> inline float
51 evalAttr<float>(const GA_Attribute* atr, const GA_AIFTuple* aif,
52  GA_Offset off, int idx)
53 {
54  fpreal32 value;
55  aif->get(atr, off, value, idx);
56  return float(value);
57 }
58 
59 template <> inline openvdb::Int32
60 evalAttr<openvdb::Int32>(const GA_Attribute* atr, const GA_AIFTuple* aif,
61  GA_Offset off, int idx)
62 {
63  int32 value;
64  aif->get(atr, off, value, idx);
65  return openvdb::Int32(value);
66 }
67 
68 template <> inline openvdb::Int64
69 evalAttr<openvdb::Int64>(const GA_Attribute* atr, const GA_AIFTuple* aif,
70  GA_Offset off, int idx)
71 {
72  int64 value;
73  aif->get(atr, off, value, idx);
74  return openvdb::Int64(value);
75 }
76 
77 template <> inline openvdb::Vec3i
78 evalAttr<openvdb::Vec3i>(const GA_Attribute* atr, const GA_AIFTuple* aif,
79  GA_Offset off, int)
80 {
81  openvdb::Vec3i vec;
82 
83  int32 comp;
84  aif->get(atr, off, comp, 0);
85  vec[0] = openvdb::Int32(comp);
86 
87  aif->get(atr, off, comp, 1);
88  vec[1] = openvdb::Int32(comp);
89 
90  aif->get(atr, off, comp, 2);
91  vec[2] = openvdb::Int32(comp);
92 
93  return vec;
94 }
95 
96 template <> inline openvdb::Vec3s
97 evalAttr<openvdb::Vec3s>(const GA_Attribute* atr, const GA_AIFTuple* aif,
98  GA_Offset off, int)
99 {
100  openvdb::Vec3s vec;
101 
102  fpreal32 comp;
103  aif->get(atr, off, comp, 0);
104  vec[0] = float(comp);
105 
106  aif->get(atr, off, comp, 1);
107  vec[1] = float(comp);
108 
109  aif->get(atr, off, comp, 2);
110  vec[2] = float(comp);
111 
112  return vec;
113 }
114 
115 template <> inline openvdb::Vec3d
116 evalAttr<openvdb::Vec3d>(const GA_Attribute* atr, const GA_AIFTuple* aif,
117  GA_Offset off, int)
118 {
119  openvdb::Vec3d vec;
120 
121  fpreal64 comp;
122  aif->get(atr, off, comp, 0);
123  vec[0] = double(comp);
124 
125  aif->get(atr, off, comp, 1);
126  vec[1] = double(comp);
127 
128  aif->get(atr, off, comp, 2);
129  vec[2] = double(comp);
130 
131  return vec;
132 }
133 
134 
135 ////////////////////////////////////////
136 
137 
138 /// Combine different value types.
139 
140 template <typename ValueType> inline ValueType
141 combine(const ValueType& v0, const ValueType& v1, const ValueType& v2,
142  const openvdb::Vec3d& w)
143 {
144  return ValueType(v0 * w[0] + v1 * w[1] + v2 * w[2]);
145 }
146 
147 template <> inline openvdb::Int32
148 combine(const openvdb::Int32& v0, const openvdb::Int32& v1,
149  const openvdb::Int32& v2, const openvdb::Vec3d& w)
150 {
151  if (w[2] > w[0] && w[2] > w[1]) return v2;
152  if (w[1] > w[0] && w[1] > w[2]) return v1;
153  return v0;
154 }
155 
156 template <> inline openvdb::Int64
157 combine(const openvdb::Int64& v0, const openvdb::Int64& v1,
158  const openvdb::Int64& v2, const openvdb::Vec3d& w)
159 {
160  if (w[2] > w[0] && w[2] > w[1]) return v2;
161  if (w[1] > w[0] && w[1] > w[2]) return v1;
162  return v0;
163 }
164 
165 template <> inline openvdb::Vec3i
166 combine(const openvdb::Vec3i& v0, const openvdb::Vec3i& v1,
167  const openvdb::Vec3i& v2, const openvdb::Vec3d& w)
168 {
169  if (w[2] > w[0] && w[2] > w[1]) return v2;
170  if (w[1] > w[0] && w[1] > w[2]) return v1;
171  return v0;
172 }
173 
174 template <> inline openvdb::Vec3s
175 combine(const openvdb::Vec3s& v0, const openvdb::Vec3s& v1,
176  const openvdb::Vec3s& v2, const openvdb::Vec3d& w)
177 {
178  openvdb::Vec3s vec;
179 
180  vec[0] = float(v0[0] * w[0] + v1[0] * w[1] + v2[0] * w[2]);
181  vec[1] = float(v0[1] * w[0] + v1[1] * w[1] + v2[1] * w[2]);
182  vec[2] = float(v0[2] * w[0] + v1[2] * w[1] + v2[2] * w[2]);
183 
184  return vec;
185 }
186 
187 template <> inline openvdb::Vec3d
188 combine(const openvdb::Vec3d& v0, const openvdb::Vec3d& v1,
189  const openvdb::Vec3d& v2, const openvdb::Vec3d& w)
190 {
191  openvdb::Vec3d vec;
192 
193  vec[0] = v0[0] * w[0] + v1[0] * w[1] + v2[0] * w[2];
194  vec[1] = v0[1] * w[0] + v1[1] * w[1] + v2[1] * w[2];
195  vec[2] = v0[2] * w[0] + v1[2] * w[1] + v2[2] * w[2];
196 
197  return vec;
198 }
199 
200 
201 ////////////////////////////////////////
202 
203 
204 /// @brief Get an OpenVDB-specific value by evaluating GA_Default::get()
205 /// with appropriate arguments.
206 template <typename ValueType> inline ValueType
207 evalAttrDefault(const GA_Defaults& defaults, int idx)
208 {
209  fpreal64 value;
210  defaults.get(idx, value);
211  return ValueType(value);
212 }
213 
214 template <> inline float
215 evalAttrDefault<float>(const GA_Defaults& defaults, int /*idx*/)
216 {
217  fpreal32 value;
218  defaults.get(0, value);
219  return float(value);
220 }
221 
222 template <> inline openvdb::Int32
223 evalAttrDefault<openvdb::Int32>(const GA_Defaults& defaults, int idx)
224 {
225  int32 value;
226  defaults.get(idx, value);
227  return openvdb::Int32(value);
228 }
229 
230 template <> inline openvdb::Int64
231 evalAttrDefault<openvdb::Int64>(const GA_Defaults& defaults, int idx)
232 {
233  int64 value;
234  defaults.get(idx, value);
235  return openvdb::Int64(value);
236 }
237 
238 template <> inline openvdb::Vec3i
239 evalAttrDefault<openvdb::Vec3i>(const GA_Defaults& defaults, int)
240 {
241  openvdb::Vec3i vec;
242  int32 value;
243 
244  defaults.get(0, value);
245  vec[0] = openvdb::Int32(value);
246 
247  defaults.get(1, value);
248  vec[1] = openvdb::Int32(value);
249 
250  defaults.get(2, value);
251  vec[2] = openvdb::Int32(value);
252 
253  return vec;
254 }
255 
256 template <> inline openvdb::Vec3s
257 evalAttrDefault<openvdb::Vec3s>(const GA_Defaults& defaults, int)
258 {
259  openvdb::Vec3s vec;
260  fpreal32 value;
261 
262  defaults.get(0, value);
263  vec[0] = float(value);
264 
265  defaults.get(1, value);
266  vec[1] = float(value);
267 
268  defaults.get(2, value);
269  vec[2] = float(value);
270 
271  return vec;
272 }
273 
274 template <> inline openvdb::Vec3d
275 evalAttrDefault<openvdb::Vec3d>(const GA_Defaults& defaults, int)
276 {
277  openvdb::Vec3d vec;
278  fpreal64 value;
279 
280  defaults.get(0, value);
281  vec[0] = double(value);
282 
283  defaults.get(1, value);
284  vec[1] = double(value);
285 
286  defaults.get(2, value);
287  vec[2] = double(value);
288 
289  return vec;
290 }
291 
292 template <> inline openvdb::math::Quat<float>
293 evalAttrDefault<openvdb::math::Quat<float>>(const GA_Defaults& defaults, int)
294 {
295  openvdb::math::Quat<float> quat;
296  fpreal32 value;
297 
298  for (int i = 0; i < 4; i++) {
299  defaults.get(i, value);
300  quat[i] = float(value);
301  }
302 
303  return quat;
304 }
305 
306 template <> inline openvdb::math::Quat<double>
307 evalAttrDefault<openvdb::math::Quat<double>>(const GA_Defaults& defaults, int)
308 {
309  openvdb::math::Quat<double> quat;
310  fpreal64 value;
311 
312  for (int i = 0; i < 4; i++) {
313  defaults.get(i, value);
314  quat[i] = double(value);
315  }
316 
317  return quat;
318 }
319 
320 template <> inline openvdb::math::Mat3<float>
321 evalAttrDefault<openvdb::math::Mat3<float>>(const GA_Defaults& defaults, int)
322 {
323  openvdb::math::Mat3<float> mat;
324  fpreal64 value;
325  float* data = mat.asPointer();
326 
327  for (int i = 0; i < 9; i++) {
328  defaults.get(i, value);
329  data[i] = float(value);
330  }
331 
332  return mat;
333 }
334 
335 template <> inline openvdb::math::Mat3<double>
336 evalAttrDefault<openvdb::math::Mat3<double>>(const GA_Defaults& defaults, int)
337 {
338  openvdb::math::Mat3<double> mat;
339  fpreal64 value;
340  double* data = mat.asPointer();
341 
342  for (int i = 0; i < 9; i++) {
343  defaults.get(i, value);
344  data[i] = double(value);
345  }
346 
347  return mat;
348 }
349 
350 template <> inline openvdb::math::Mat4<float>
351 evalAttrDefault<openvdb::math::Mat4<float>>(const GA_Defaults& defaults, int)
352 {
353  openvdb::math::Mat4<float> mat;
354  fpreal64 value;
355  float* data = mat.asPointer();
356 
357  for (int i = 0; i < 16; i++) {
358  defaults.get(i, value);
359  data[i] = float(value);
360  }
361 
362  return mat;
363 }
364 
365 template <> inline openvdb::math::Mat4<double>
366 evalAttrDefault<openvdb::math::Mat4<double>>(const GA_Defaults& defaults, int)
367 {
368  openvdb::math::Mat4<double> mat;
369  fpreal64 value;
370  double* data = mat.asPointer();
371 
372  for (int i = 0; i < 16; i++) {
373  defaults.get(i, value);
374  data[i] = double(value);
375  }
376 
377  return mat;
378 }
379 
380 
381 ////////////////////////////////////////
382 
383 
385 {
386 public:
387  using Ptr = std::shared_ptr<AttributeDetailBase>;
388 
389  virtual ~AttributeDetailBase() = default;
390 
391  AttributeDetailBase(const AttributeDetailBase&) = default;
393 
394  virtual void set(const openvdb::Coord& ijk, const GA_Offset (&offsets)[3],
395  const openvdb::Vec3d& weights) = 0;
396 
397  virtual void set(const openvdb::Coord& ijk, GA_Offset offset) = 0;
398 
399  virtual openvdb::GridBase::Ptr& grid() = 0;
400  virtual std::string& name() = 0;
401 
402  virtual AttributeDetailBase::Ptr copy() = 0;
403 
404 protected:
406 };
407 
408 
409 using AttributeDetailList = std::vector<AttributeDetailBase::Ptr>;
410 
411 
412 ////////////////////////////////////////
413 
414 
415 template <class VDBGridType>
417 {
418 public:
419  using ValueType = typename VDBGridType::ValueType;
420 
423  const GA_Attribute* attribute,
424  const GA_AIFTuple* tupleAIF,
425  const int tupleIndex,
426  const bool isVector = false);
427 
428  void set(const openvdb::Coord& ijk, const GA_Offset (&offsets)[3],
429  const openvdb::Vec3d& weights) override;
430 
431  void set(const openvdb::Coord& ijk, GA_Offset offset) override;
432 
433  openvdb::GridBase::Ptr& grid() override { return mGrid; }
434  std::string& name() override { return mName; }
435 
436  AttributeDetailBase::Ptr copy() override;
437 
438 protected:
439  AttributeDetail();
440 
441 private:
443  typename VDBGridType::Accessor mAccessor;
444 
445  const GA_Attribute* mAttribute;
446  const GA_AIFTuple* mTupleAIF;
447  const int mTupleIndex;
448  std::string mName;
449 };
450 
451 
452 template <class VDBGridType>
454  mAttribute(nullptr),
455  mTupleAIF(nullptr),
456  mTupleIndex(0)
457 {
458 }
459 
460 
461 template <class VDBGridType>
464  const GA_Attribute* attribute,
465  const GA_AIFTuple* tupleAIF,
466  const int tupleIndex,
467  const bool isVector):
468  mGrid(grid),
469  mAccessor(openvdb::GridBase::grid<VDBGridType>(mGrid)->getAccessor()),
470  mAttribute(attribute),
471  mTupleAIF(tupleAIF),
472  mTupleIndex(tupleIndex)
473 {
474  std::ostringstream name;
475  name << mAttribute->getName();
476 
477  const int tupleSize = mTupleAIF->getTupleSize(mAttribute);
478 
479  if(!isVector && tupleSize != 1) {
480  name << "_" << mTupleIndex;
481  }
482 
483  mName = name.str();
484 }
485 
486 
487 template <class VDBGridType>
488 void
489 AttributeDetail<VDBGridType>::set(const openvdb::Coord& ijk,
490  const GA_Offset (&offsets)[3], const openvdb::Vec3d& weights)
491 {
492  ValueType v0 = evalAttr<ValueType>(
493  mAttribute, mTupleAIF, offsets[0], mTupleIndex);
494 
495  ValueType v1 = evalAttr<ValueType>(
496  mAttribute, mTupleAIF, offsets[1], mTupleIndex);
497 
498  ValueType v2 = evalAttr<ValueType>(
499  mAttribute, mTupleAIF, offsets[2], mTupleIndex);
500 
501  mAccessor.setValue(ijk, combine<ValueType>(v0, v1, v2, weights));
502 }
503 
504 template <class VDBGridType>
505 void
506 AttributeDetail<VDBGridType>::set(const openvdb::Coord& ijk, GA_Offset offset)
507 {
508  mAccessor.setValue(ijk,
509  evalAttr<ValueType>(mAttribute, mTupleAIF, offset, mTupleIndex));
510 }
511 
512 template <class VDBGridType>
515 {
517 }
518 
519 
520 ////////////////////////////////////////
521 
522 
523 // TBB object to transfer mesh attributes.
524 // Only quads and/or triangles are supported
525 // NOTE: This class has all code in the header and so it cannot have OPENVDB_HOUDINI_API.
527 {
528 public:
529  using IterRange = openvdb::tree::IteratorRange<openvdb::Int32Tree::LeafCIter>;
530 
531  inline
533  AttributeDetailList &pointAttributes,
534  AttributeDetailList &vertexAttributes,
535  AttributeDetailList &primitiveAttributes,
536  const openvdb::Int32Grid& closestPrimGrid,
537  const openvdb::math::Transform& transform,
538  const GU_Detail& meshGdp);
539 
540  inline
541  MeshAttrTransfer(const MeshAttrTransfer &other);
542 
543  inline
545 
546  /// Main calls
547  inline void runParallel();
548  inline void runSerial();
549 
550  inline void operator()(IterRange &range) const;
551 
552 private:
553  AttributeDetailList mPointAttributes, mVertexAttributes, mPrimitiveAttributes;
554  const openvdb::Int32Grid& mClosestPrimGrid;
555 
556  const openvdb::math::Transform& mTransform;
557 
558  const GA_Detail &mMeshGdp;
559 };
560 
561 
563  AttributeDetailList& pointAttributes,
564  AttributeDetailList& vertexAttributes,
565  AttributeDetailList& primitiveAttributes,
566  const openvdb::Int32Grid& closestPrimGrid,
567  const openvdb::math::Transform& transform,
568  const GU_Detail& meshGdp):
569  mPointAttributes(pointAttributes),
570  mVertexAttributes(vertexAttributes),
571  mPrimitiveAttributes(primitiveAttributes),
572  mClosestPrimGrid(closestPrimGrid),
573  mTransform(transform),
574  mMeshGdp(meshGdp)
575 {
576 }
577 
578 
580  mPointAttributes(other.mPointAttributes.size()),
581  mVertexAttributes(other.mVertexAttributes.size()),
582  mPrimitiveAttributes(other.mPrimitiveAttributes.size()),
583  mClosestPrimGrid(other.mClosestPrimGrid),
584  mTransform(other.mTransform),
585  mMeshGdp(other.mMeshGdp)
586 {
587  // Deep-copy the AttributeDetail arrays, to construct unique tree
588  // accessors per thread.
589 
590  for (size_t i = 0, N = other.mPointAttributes.size(); i < N; ++i) {
591  mPointAttributes[i] = other.mPointAttributes[i]->copy();
592  }
593 
594  for (size_t i = 0, N = other.mVertexAttributes.size(); i < N; ++i) {
595  mVertexAttributes[i] = other.mVertexAttributes[i]->copy();
596  }
597 
598  for (size_t i = 0, N = other.mPrimitiveAttributes.size(); i < N; ++i) {
599  mPrimitiveAttributes[i] = other.mPrimitiveAttributes[i]->copy();
600  }
601 }
602 
603 
604 void
606 {
607  IterRange range(mClosestPrimGrid.tree().beginLeaf());
608  tbb::parallel_for(range, *this);
609 }
610 
611 void
613 {
614  IterRange range(mClosestPrimGrid.tree().beginLeaf());
615  (*this)(range);
616 }
617 
618 
619 void
621 {
623 
624  openvdb::Coord ijk;
625 
626  const bool ptnAttrTransfer = mPointAttributes.size() > 0;
627  const bool vtxAttrTransfer = mVertexAttributes.size() > 0;
628 
629  GA_Offset vtxOffsetList[4], ptnOffsetList[4], vtxOffsets[3], ptnOffsets[3], prmOffset;
630  openvdb::Vec3d ptnList[4], xyz, cpt, cpt2, uvw, uvw2;
631 
632  for ( ; range; ++range) {
633  iter = range.iterator()->beginValueOn();
634  for ( ; iter; ++iter) {
635 
636  ijk = iter.getCoord();
637 
638  const GA_Index prmIndex = iter.getValue();
639  prmOffset = mMeshGdp.primitiveOffset(prmIndex);
640 
641  // Transfer primitive attributes
642  for (size_t i = 0, N = mPrimitiveAttributes.size(); i < N; ++i) {
643  mPrimitiveAttributes[i]->set(ijk, prmOffset);
644  }
645 
646  if (!ptnAttrTransfer && !vtxAttrTransfer) continue;
647 
648  // Transfer vertex and point attributes
649  const GA_Primitive * primRef = mMeshGdp.getPrimitiveList().get(prmOffset);
650 
651  const GA_Size vtxn = primRef->getVertexCount();
652 
653  // Get vertex and point offests
654  for (GA_Size vtx = 0; vtx < vtxn; ++vtx) {
655  const GA_Offset vtxoff = primRef->getVertexOffset(vtx);
656  ptnOffsetList[vtx] = mMeshGdp.vertexPoint(vtxoff);
657  vtxOffsetList[vtx] = vtxoff;
658 
659  UT_Vector3 p = mMeshGdp.getPos3(ptnOffsetList[vtx]);
660  ptnList[vtx][0] = double(p[0]);
661  ptnList[vtx][1] = double(p[1]);
662  ptnList[vtx][2] = double(p[2]);
663  }
664 
665  xyz = mTransform.indexToWorld(ijk);
666 
667  // Compute barycentric coordinates
668 
670  ptnList[0], ptnList[2], ptnList[1], xyz, uvw);
671 
672  vtxOffsets[0] = vtxOffsetList[0]; // cpt offsets
673  ptnOffsets[0] = ptnOffsetList[0];
674  vtxOffsets[1] = vtxOffsetList[2];
675  ptnOffsets[1] = ptnOffsetList[2];
676  vtxOffsets[2] = vtxOffsetList[1];
677  ptnOffsets[2] = ptnOffsetList[1];
678 
679  if (4 == vtxn) {
681  ptnList[0], ptnList[3], ptnList[2], xyz, uvw2);
682 
683  if ((cpt2 - xyz).lengthSqr() < (cpt - xyz).lengthSqr()) {
684  uvw = uvw2;
685  vtxOffsets[1] = vtxOffsetList[3];
686  ptnOffsets[1] = ptnOffsetList[3];
687  vtxOffsets[2] = vtxOffsetList[2];
688  ptnOffsets[2] = ptnOffsetList[2];
689  }
690  }
691 
692  // Transfer vertex attributes
693  for (size_t i = 0, N = mVertexAttributes.size(); i < N; ++i) {
694  mVertexAttributes[i]->set(ijk, vtxOffsets, uvw);
695  }
696 
697  // Transfer point attributes
698  for (size_t i = 0, N = mPointAttributes.size(); i < N; ++i) {
699  mPointAttributes[i]->set(ijk, ptnOffsets, uvw);
700  }
701 
702  } // end sparse voxel iteration.
703  } // end leaf-node iteration
704 }
705 
706 
707 ////////////////////////////////////////
708 
709 
710 // TBB object to transfer mesh attributes.
711 // Only quads and/or triangles are supported
712 // NOTE: This class has all code in the header and so it cannot have OPENVDB_HOUDINI_API.
714 {
715 public:
716  using IterRange = openvdb::tree::IteratorRange<openvdb::Int32Tree::LeafCIter>;
717 
718  inline PointAttrTransfer(
719  AttributeDetailList &pointAttributes,
720  const openvdb::Int32Grid& closestPtnIdxGrid,
721  const GU_Detail& ptGeop);
722 
723  inline PointAttrTransfer(const PointAttrTransfer &other);
724 
725  inline ~PointAttrTransfer() {}
726 
727  /// Main calls
728  inline void runParallel();
729  inline void runSerial();
730 
731  inline void operator()(IterRange &range) const;
732 
733 private:
734  AttributeDetailList mPointAttributes;
735  const openvdb::Int32Grid& mClosestPtnIdxGrid;
736  const GA_Detail &mPtGeo;
737 };
738 
739 
741  AttributeDetailList& pointAttributes,
742  const openvdb::Int32Grid& closestPtnIdxGrid,
743  const GU_Detail& ptGeop):
744  mPointAttributes(pointAttributes),
745  mClosestPtnIdxGrid(closestPtnIdxGrid),
746  mPtGeo(ptGeop)
747 {
748 }
749 
750 
752  mPointAttributes(other.mPointAttributes.size()),
753  mClosestPtnIdxGrid(other.mClosestPtnIdxGrid),
754  mPtGeo(other.mPtGeo)
755 {
756  // Deep-copy the AttributeDetail arrays, to construct unique tree
757  // accessors per thread.
758 
759  for (size_t i = 0, N = other.mPointAttributes.size(); i < N; ++i) {
760  mPointAttributes[i] = other.mPointAttributes[i]->copy();
761  }
762 }
763 
764 
765 void
767 {
768  IterRange range(mClosestPtnIdxGrid.tree().beginLeaf());
769  tbb::parallel_for(range, *this);
770 }
771 
772 void
774 {
775  IterRange range(mClosestPtnIdxGrid.tree().beginLeaf());
776  (*this)(range);
777 }
778 
779 
780 void
782 {
784  openvdb::Coord ijk;
785 
786  for ( ; range; ++range) {
787  iter = range.iterator()->beginValueOn();
788  for ( ; iter; ++iter) {
789 
790  ijk = iter.getCoord();
791 
792  const GA_Index pointIndex = iter.getValue();
793  const GA_Offset pointOffset = mPtGeo.pointOffset(pointIndex);
794 
795  // Transfer point attributes
796  for (size_t i = 0, N = mPointAttributes.size(); i < N; ++i) {
797  mPointAttributes[i]->set(ijk, pointOffset);
798  }
799  } // end sparse voxel iteration.
800  } // end leaf-node iteration
801 }
802 
803 
804 ////////////////////////////////////////
805 
806 // Mesh to Mesh Attribute Transfer Utils
807 
808 
810 {
811  using Ptr = std::shared_ptr<AttributeCopyBase>;
812 
813  virtual ~AttributeCopyBase() {}
814  virtual void copy(GA_Offset /*source*/, GA_Offset /*target*/) = 0;
815  virtual void copy(GA_Offset&, GA_Offset&, GA_Offset&, GA_Offset /*target*/,
816  const openvdb::Vec3d& /*uvw*/) = 0;
817 protected:
819 };
820 
821 
822 template<class ValueType>
824 {
825 public:
826  AttributeCopy(const GA_Attribute& sourceAttr, GA_Attribute& targetAttr)
827  : mSourceAttr(sourceAttr)
828  , mTargetAttr(targetAttr)
829  , mAIFTuple(*mSourceAttr.getAIFTuple())
830  , mTupleSize(mAIFTuple.getTupleSize(&mSourceAttr))
831  {
832  }
833 
834  void copy(GA_Offset source, GA_Offset target) override
835  {
836  ValueType data;
837  for (int i = 0; i < mTupleSize; ++i) {
838  mAIFTuple.get(&mSourceAttr, source, data, i);
839  mAIFTuple.set(&mTargetAttr, target, data, i);
840  }
841  }
842 
843  void copy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target,
844  const openvdb::Vec3d& uvw) override
845  {
846  doCopy<ValueType>(v0, v1, v2, target, uvw);
847  }
848 
849 private:
850  template<typename T>
852  doCopy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target, const openvdb::Vec3d& uvw)
853  {
854  GA_Offset source = v0;
855  double min = uvw[0];
856 
857  if (uvw[1] < min) {
858  min = uvw[1];
859  source = v1;
860  }
861  if (uvw[2] < min) source = v2;
862 
863 
864  ValueType data;
865  for (int i = 0; i < mTupleSize; ++i) {
866  mAIFTuple.get(&mSourceAttr, source, data, i);
867  mAIFTuple.set(&mTargetAttr, target, data, i);
868  }
869  }
870 
871  template <typename T>
873  doCopy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target, const openvdb::Vec3d& uvw)
874  {
875  ValueType a, b, c;
876  for (int i = 0; i < mTupleSize; ++i) {
877  mAIFTuple.get(&mSourceAttr, v0, a, i);
878  mAIFTuple.get(&mSourceAttr, v1, b, i);
879  mAIFTuple.get(&mSourceAttr, v2, c, i);
880  mAIFTuple.set(&mTargetAttr, target, a*uvw[0] + b*uvw[1] + c*uvw[2], i);
881  }
882  }
883 
884 
885  const GA_Attribute& mSourceAttr;
886  GA_Attribute& mTargetAttr;
887  const GA_AIFTuple& mAIFTuple;
888  int mTupleSize;
889 };
890 
891 
893 {
894 public:
895  StrAttributeCopy(const GA_Attribute& sourceAttr, GA_Attribute& targetAttr)
896  : mSourceAttr(sourceAttr)
897  , mTargetAttr(targetAttr)
898  , mAIF(*mSourceAttr.getAIFSharedStringTuple())
899  , mTupleSize(mAIF.getTupleSize(&mSourceAttr))
900  {
901  }
902 
903  void copy(GA_Offset source, GA_Offset target) override
904  {
905  for (int i = 0; i < mTupleSize; ++i) {
906  mAIF.setString(&mTargetAttr, target, mAIF.getString(&mSourceAttr, source, i), i);
907  }
908  }
909 
910  void copy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target,
911  const openvdb::Vec3d& uvw) override
912  {
913  GA_Offset source = v0;
914  double min = uvw[0];
915 
916  if (uvw[1] < min) {
917  min = uvw[1];
918  source = v1;
919  }
920  if (uvw[2] < min) source = v2;
921 
922  for (int i = 0; i < mTupleSize; ++i) {
923  mAIF.setString(&mTargetAttr, target, mAIF.getString(&mSourceAttr, source, i), i);
924  }
925  }
926 
927 protected:
928  const GA_Attribute& mSourceAttr;
929  GA_Attribute& mTargetAttr;
930  const GA_AIFSharedStringTuple& mAIF;
932 };
933 
934 
935 ////////////////////////////////////////
936 
937 
939 createAttributeCopier(const GA_Attribute& sourceAttr, GA_Attribute& targetAttr)
940 {
941  const GA_AIFTuple * aifTuple = sourceAttr.getAIFTuple();
943 
944  if (aifTuple) {
945  const GA_Storage sourceStorage = aifTuple->getStorage(&sourceAttr);
946  const GA_Storage targetStorage = aifTuple->getStorage(&targetAttr);
947 
948  const int sourceTupleSize = aifTuple->getTupleSize(&sourceAttr);
949  const int targetTupleSize = aifTuple->getTupleSize(&targetAttr);
950 
951  if (sourceStorage == targetStorage && sourceTupleSize == targetTupleSize) {
952  switch (sourceStorage)
953  {
954  case GA_STORE_INT16:
955  case GA_STORE_INT32:
956  attr = AttributeCopyBase::Ptr(
957  new AttributeCopy<int32>(sourceAttr, targetAttr));
958  break;
959  case GA_STORE_INT64:
960  attr = AttributeCopyBase::Ptr(
961  new AttributeCopy<int64>(sourceAttr, targetAttr));
962  break;
963  case GA_STORE_REAL16:
964  case GA_STORE_REAL32:
965  attr = AttributeCopyBase::Ptr(
966  new AttributeCopy<fpreal32>(sourceAttr, targetAttr));
967  break;
968  case GA_STORE_REAL64:
969  attr = AttributeCopyBase::Ptr(
970  new AttributeCopy<fpreal64>(sourceAttr, targetAttr));
971  break;
972  default:
973  break;
974  }
975  }
976  } else {
977  const GA_AIFSharedStringTuple * aifString = sourceAttr.getAIFSharedStringTuple();
978  if (aifString) {
979  attr = AttributeCopyBase::Ptr(new StrAttributeCopy(sourceAttr, targetAttr));
980  }
981  }
982 
983  return attr;
984 }
985 
986 
987 ////////////////////////////////////////
988 
989 
990 inline GA_Offset
992  const GU_Detail& geo, const std::set<GA_Index>& primitives, const openvdb::Vec3d& p,
993  GA_Offset& vert0, GA_Offset& vert1, GA_Offset& vert2, openvdb::Vec3d& uvw)
994 {
995  std::set<GA_Index>::const_iterator it = primitives.begin();
996 
997  GA_Offset primOffset = GA_INVALID_OFFSET;
998  const GA_Primitive * primRef = nullptr;
999  double minDist = std::numeric_limits<double>::max();
1000 
1001  openvdb::Vec3d a, b, c, d, tmpUVW;
1002  UT_Vector3 tmpPoint;
1003 
1004  for (; it != primitives.end(); ++it) {
1005 
1006  const GA_Offset offset = geo.primitiveOffset(*it);
1007  primRef = geo.getPrimitiveList().get(offset);
1008 
1009  const GA_Size vertexCount = primRef->getVertexCount();
1010 
1011 
1012  if (vertexCount == 3 || vertexCount == 4) {
1013 
1014  tmpPoint = geo.getPos3(primRef->getPointOffset(0));
1015  a[0] = tmpPoint.x();
1016  a[1] = tmpPoint.y();
1017  a[2] = tmpPoint.z();
1018 
1019  tmpPoint = geo.getPos3(primRef->getPointOffset(1));
1020  b[0] = tmpPoint.x();
1021  b[1] = tmpPoint.y();
1022  b[2] = tmpPoint.z();
1023 
1024  tmpPoint = geo.getPos3(primRef->getPointOffset(2));
1025  c[0] = tmpPoint.x();
1026  c[1] = tmpPoint.y();
1027  c[2] = tmpPoint.z();
1028 
1029  double tmpDist =
1030  (p - openvdb::math::closestPointOnTriangleToPoint(a, c, b, p, tmpUVW)).lengthSqr();
1031 
1032  if (tmpDist < minDist) {
1033  minDist = tmpDist;
1034  primOffset = offset;
1035  uvw = tmpUVW;
1036  vert0 = primRef->getVertexOffset(0);
1037  vert1 = primRef->getVertexOffset(2);
1038  vert2 = primRef->getVertexOffset(1);
1039  }
1040 
1041  if (vertexCount == 4) {
1042  tmpPoint = geo.getPos3(primRef->getPointOffset(3));
1043  d[0] = tmpPoint.x();
1044  d[1] = tmpPoint.y();
1045  d[2] = tmpPoint.z();
1046 
1048  a, d, c, p, tmpUVW)).lengthSqr();
1049  if (tmpDist < minDist) {
1050  minDist = tmpDist;
1051  primOffset = offset;
1052  uvw = tmpUVW;
1053  vert0 = primRef->getVertexOffset(0);
1054  vert1 = primRef->getVertexOffset(3);
1055  vert2 = primRef->getVertexOffset(2);
1056  }
1057  }
1058 
1059  }
1060  }
1061 
1062  return primOffset;
1063 }
1064 
1065 
1066 // Faster for small primitive counts
1067 inline GA_Offset
1069  const GU_Detail& geo, std::vector<GA_Index>& primitives, const openvdb::Vec3d& p,
1070  GA_Offset& vert0, GA_Offset& vert1, GA_Offset& vert2, openvdb::Vec3d& uvw)
1071 {
1072  GA_Offset primOffset = GA_INVALID_OFFSET;
1073  const GA_Primitive * primRef = nullptr;
1074  double minDist = std::numeric_limits<double>::max();
1075 
1076  openvdb::Vec3d a, b, c, d, tmpUVW;
1077  UT_Vector3 tmpPoint;
1078 
1079  std::sort(primitives.begin(), primitives.end());
1080 
1081  GA_Index lastPrim = -1;
1082  for (size_t n = 0, N = primitives.size(); n < N; ++n) {
1083  if (primitives[n] == lastPrim) continue;
1084  lastPrim = primitives[n];
1085 
1086  const GA_Offset offset = geo.primitiveOffset(lastPrim);
1087  primRef = geo.getPrimitiveList().get(offset);
1088 
1089  const GA_Size vertexCount = primRef->getVertexCount();
1090 
1091 
1092  if (vertexCount == 3 || vertexCount == 4) {
1093 
1094  tmpPoint = geo.getPos3(primRef->getPointOffset(0));
1095  a[0] = tmpPoint.x();
1096  a[1] = tmpPoint.y();
1097  a[2] = tmpPoint.z();
1098 
1099  tmpPoint = geo.getPos3(primRef->getPointOffset(1));
1100  b[0] = tmpPoint.x();
1101  b[1] = tmpPoint.y();
1102  b[2] = tmpPoint.z();
1103 
1104  tmpPoint = geo.getPos3(primRef->getPointOffset(2));
1105  c[0] = tmpPoint.x();
1106  c[1] = tmpPoint.y();
1107  c[2] = tmpPoint.z();
1108 
1109  double tmpDist =
1110  (p - openvdb::math::closestPointOnTriangleToPoint(a, c, b, p, tmpUVW)).lengthSqr();
1111 
1112  if (tmpDist < minDist) {
1113  minDist = tmpDist;
1114  primOffset = offset;
1115  uvw = tmpUVW;
1116  vert0 = primRef->getVertexOffset(0);
1117  vert1 = primRef->getVertexOffset(2);
1118  vert2 = primRef->getVertexOffset(1);
1119  }
1120 
1121  if (vertexCount == 4) {
1122  tmpPoint = geo.getPos3(primRef->getPointOffset(3));
1123  d[0] = tmpPoint.x();
1124  d[1] = tmpPoint.y();
1125  d[2] = tmpPoint.z();
1126 
1128  a, d, c, p, tmpUVW)).lengthSqr();
1129  if (tmpDist < minDist) {
1130  minDist = tmpDist;
1131  primOffset = offset;
1132  uvw = tmpUVW;
1133  vert0 = primRef->getVertexOffset(0);
1134  vert1 = primRef->getVertexOffset(3);
1135  vert2 = primRef->getVertexOffset(2);
1136  }
1137  }
1138 
1139  }
1140  }
1141 
1142  return primOffset;
1143 }
1144 
1145 
1146 ////////////////////////////////////////
1147 
1148 
1149 template<class GridType>
1151 {
1152 public:
1153  using IndexT = typename GridType::ValueType;
1154  using IndexAccT = typename GridType::ConstAccessor;
1155  using AttrCopyPtrVec = std::vector<AttributeCopyBase::Ptr>;
1156 
1158  const GU_Detail& sourceGeo,
1159  GU_Detail& targetGeo,
1160  const GridType& indexGrid,
1161  AttrCopyPtrVec& primAttributes,
1162  AttrCopyPtrVec& vertAttributes)
1163  : mSourceGeo(sourceGeo)
1164  , mTargetGeo(targetGeo)
1165  , mIndexGrid(indexGrid)
1166  , mPrimAttributes(primAttributes)
1167  , mVertAttributes(vertAttributes)
1168  {
1169  }
1170 
1171  inline void operator()(const GA_SplittableRange&) const;
1172 
1173 private:
1174  inline void copyPrimAttrs(const GA_Primitive&, const UT_Vector3&, IndexAccT&) const;
1175 
1176  template<typename PrimT>
1177  inline void copyVertAttrs(const PrimT&, const UT_Vector3&, IndexAccT&) const;
1178 
1179  const GU_Detail& mSourceGeo;
1180  GU_Detail& mTargetGeo;
1181  const GridType& mIndexGrid;
1182  AttrCopyPtrVec& mPrimAttributes;
1183  AttrCopyPtrVec& mVertAttributes;
1184 };
1185 
1186 
1187 template<class GridType>
1188 inline void
1189 TransferPrimitiveAttributesOp<GridType>::operator()(const GA_SplittableRange& range) const
1190 {
1191  if (mPrimAttributes.empty() && mVertAttributes.empty()) return;
1192 
1193  auto polyIdxAcc = mIndexGrid.getConstAccessor();
1194 
1195  for (GA_PageIterator pageIt = range.beginPages(); !pageIt.atEnd(); ++pageIt) {
1196  auto start = GA_Offset(), end = GA_Offset();
1197  for (GA_Iterator blockIt(pageIt.begin()); blockIt.blockAdvance(start, end); ) {
1198  for (auto targetOffset = start; targetOffset < end; ++targetOffset) {
1199  const auto* target = mTargetGeo.getPrimitiveList().get(targetOffset);
1200  if (!target) continue;
1201 
1202  const auto targetN = mTargetGeo.getGEOPrimitive(targetOffset)->computeNormal();
1203 
1204  if (!mPrimAttributes.empty()) {
1205  // Transfer primitive attributes.
1206  copyPrimAttrs(*target, targetN, polyIdxAcc);
1207  }
1208 
1209  if (!mVertAttributes.empty()) {
1210  if (target->getTypeId() != GA_PRIMPOLYSOUP) {
1211  copyVertAttrs(*target, targetN, polyIdxAcc);
1212  } else {
1213  if (const auto* soup = UTverify_cast<const GEO_PrimPolySoup*>(target)) {
1214  // Iterate in parallel over the member polygons of a polygon soup.
1215  using SizeRange = UT_BlockedRange<GA_Size>;
1216  const auto processPolyRange = [&](const SizeRange& range) {
1217  auto threadLocalPolyIdxAcc = mIndexGrid.getConstAccessor();
1218  for (GEO_PrimPolySoup::PolygonIterator it(*soup, range.begin());
1219  !it.atEnd() && (it.polygon() < range.end()); ++it)
1220  {
1221  copyVertAttrs(it, it.computeNormal(), threadLocalPolyIdxAcc);
1222  }
1223  };
1224  UTparallelFor(SizeRange(0, soup->getPolygonCount()), processPolyRange);
1225  }
1226  }
1227  }
1228  }
1229  }
1230  }
1231 }
1232 
1233 
1234 /// @brief Find the closest match to the target primitive from among the source primitives
1235 /// and copy primitive attributes from that primitive to the target primitive.
1236 /// @note This isn't a particularly useful operation when the target is a polygon soup,
1237 /// because the entire soup is a single primitive, whereas the source primitives
1238 /// are likely to be individual polygons.
1239 template<class GridType>
1240 inline void
1242  const GA_Primitive& targetPrim,
1243  const UT_Vector3& targetNormal,
1244  IndexAccT& polyIdxAcc) const
1245 {
1246  const auto& transform = mIndexGrid.transform();
1247 
1248  UT_Vector3 sourceN, targetN = targetNormal;
1249  const bool isPolySoup = (targetPrim.getTypeId() == GA_PRIMPOLYSOUP);
1250 
1251  // Compute avg. vertex position.
1252  openvdb::Vec3d pos(0, 0, 0);
1253  int count = static_cast<int>(targetPrim.getVertexCount());
1254  for (int vtx = 0; vtx < count; ++vtx) {
1255  pos += UTvdbConvert(targetPrim.getPos3(vtx));
1256  }
1257  if (count > 1) pos /= double(count);
1258 
1259  // Find closest source primitive to current avg. vertex position.
1260  const auto coord = openvdb::Coord::floor(transform.worldToIndex(pos));
1261 
1262  std::vector<GA_Index> primitives, similarPrimitives;
1263  IndexT primIndex;
1264  openvdb::Coord ijk;
1265 
1266  primitives.reserve(8);
1267  similarPrimitives.reserve(8);
1268  for (int d = 0; d < 8; ++d) {
1269  ijk[0] = coord[0] + (((d & 0x02) >> 1) ^ (d & 0x01));
1270  ijk[1] = coord[1] + ((d & 0x02) >> 1);
1271  ijk[2] = coord[2] + ((d & 0x04) >> 2);
1272 
1273  if (polyIdxAcc.probeValue(ijk, primIndex) &&
1275 
1276  GA_Offset tmpOffset = mSourceGeo.primitiveOffset(primIndex);
1277  sourceN = mSourceGeo.getGEOPrimitive(tmpOffset)->computeNormal();
1278 
1279  // Skip the normal test when the target is a polygon soup, because
1280  // the entire soup is a single primitive, whose normal is unlikely
1281  // to coincide with any of the source primitives.
1282  if (isPolySoup || sourceN.dot(targetN) > 0.5) {
1283  similarPrimitives.push_back(primIndex);
1284  } else {
1285  primitives.push_back(primIndex);
1286  }
1287  }
1288  }
1289 
1290  if (!primitives.empty() || !similarPrimitives.empty()) {
1291  GA_Offset source, v0, v1, v2;
1292  openvdb::Vec3d uvw;
1293  if (!similarPrimitives.empty()) {
1294  source = findClosestPrimitiveToPoint(
1295  mSourceGeo, similarPrimitives, pos, v0, v1, v2, uvw);
1296  } else {
1297  source = findClosestPrimitiveToPoint(
1298  mSourceGeo, primitives, pos, v0, v1, v2, uvw);
1299  }
1300 
1301  // Transfer attributes
1302  const auto targetOffset = targetPrim.getMapOffset();
1303  for (size_t n = 0, N = mPrimAttributes.size(); n < N; ++n) {
1304  mPrimAttributes[n]->copy(source, targetOffset);
1305  }
1306  }
1307 }
1308 
1309 
1310 /// @brief Find the closest match to the target primitive from among the source primitives
1311 /// (using slightly different criteria than copyPrimAttrs()) and copy vertex attributes
1312 /// from that primitive's vertices to the target primitive's vertices.
1313 /// @note When the target is a polygon soup, @a targetPrim should be a
1314 /// @b GEO_PrimPolySoup::PolygonIterator that points to one of the member polygons of the soup.
1315 template<typename GridType>
1316 template<typename PrimT>
1317 inline void
1319  const PrimT& targetPrim,
1320  const UT_Vector3& targetNormal,
1321  IndexAccT& polyIdxAcc) const
1322 {
1323  const auto& transform = mIndexGrid.transform();
1324 
1325  openvdb::Vec3d pos, uvw;
1326  openvdb::Coord ijk;
1327  UT_Vector3 sourceNormal;
1328  std::vector<GA_Index> primitives, similarPrimitives;
1329 
1330  primitives.reserve(8);
1331  similarPrimitives.reserve(8);
1332  for (GA_Size vtx = 0, vtxN = targetPrim.getVertexCount(); vtx < vtxN; ++vtx) {
1333  pos = UTvdbConvert(targetPrim.getPos3(vtx));
1334  const auto coord = openvdb::Coord::floor(transform.worldToIndex(pos));
1335 
1336  primitives.clear();
1337  similarPrimitives.clear();
1338  int primIndex;
1339  for (int d = 0; d < 8; ++d) {
1340  ijk[0] = coord[0] + (((d & 0x02) >> 1) ^ (d & 0x01));
1341  ijk[1] = coord[1] + ((d & 0x02) >> 1);
1342  ijk[2] = coord[2] + ((d & 0x04) >> 2);
1343 
1344  if (polyIdxAcc.probeValue(ijk, primIndex) &&
1346  {
1347  GA_Offset tmpOffset = mSourceGeo.primitiveOffset(primIndex);
1348  sourceNormal = mSourceGeo.getGEOPrimitive(tmpOffset)->computeNormal();
1349  if (sourceNormal.dot(targetNormal) > 0.5) {
1350  primitives.push_back(primIndex);
1351  }
1352  }
1353  }
1354 
1355  if (!primitives.empty() || !similarPrimitives.empty()) {
1356  GA_Offset v0, v1, v2;
1357  if (!similarPrimitives.empty()) {
1358  findClosestPrimitiveToPoint(mSourceGeo, similarPrimitives, pos, v0, v1, v2, uvw);
1359  } else {
1360  findClosestPrimitiveToPoint(mSourceGeo, primitives, pos, v0, v1, v2, uvw);
1361  }
1362 
1363  for (size_t n = 0, N = mVertAttributes.size(); n < N; ++n) {
1364  mVertAttributes[n]->copy(v0, v1, v2, targetPrim.getVertexOffset(vtx), uvw);
1365  }
1366  }
1367  }
1368 }
1369 
1370 
1371 ////////////////////////////////////////
1372 
1373 
1374 template<class GridType>
1376 {
1377 public:
1379  const GU_Detail& sourceGeo, GU_Detail& targetGeo, const GridType& indexGrid,
1380  std::vector<AttributeCopyBase::Ptr>& pointAttributes,
1381  const GA_PrimitiveGroup* surfacePrims = nullptr);
1382 
1383  void operator()(const GA_SplittableRange&) const;
1384 private:
1385  const GU_Detail& mSourceGeo;
1386  GU_Detail& mTargetGeo;
1387  const GridType& mIndexGrid;
1388  std::vector<AttributeCopyBase::Ptr>& mPointAttributes;
1389  const GA_PrimitiveGroup* mSurfacePrims;
1390 };
1391 
1392 template<class GridType>
1394  const GU_Detail& sourceGeo, GU_Detail& targetGeo, const GridType& indexGrid,
1395  std::vector<AttributeCopyBase::Ptr>& pointAttributes,
1396  const GA_PrimitiveGroup* surfacePrims)
1397  : mSourceGeo(sourceGeo)
1398  , mTargetGeo(targetGeo)
1399  , mIndexGrid(indexGrid)
1400  , mPointAttributes(pointAttributes)
1401  , mSurfacePrims(surfacePrims)
1402 {
1403 }
1404 
1405 template<class GridType>
1406 void
1407 TransferPointAttributesOp<GridType>::operator()(const GA_SplittableRange& range) const
1408 {
1409  using IndexT = typename GridType::ValueType;
1410 
1411  GA_Offset start, end, vtxOffset, primOffset, target, v0, v1, v2;
1412 
1413  typename GridType::ConstAccessor polyIdxAcc = mIndexGrid.getConstAccessor();
1414  const openvdb::math::Transform& transform = mIndexGrid.transform();
1415  openvdb::Vec3d pos, indexPos, uvw;
1416  std::vector<GA_Index> primitives;
1417  openvdb::Coord ijk, coord;
1418 
1419  primitives.reserve(8);
1420  for (GA_PageIterator pageIt = range.beginPages(); !pageIt.atEnd(); ++pageIt) {
1421  for (GA_Iterator blockIt(pageIt.begin()); blockIt.blockAdvance(start, end); ) {
1422  for (target = start; target < end; ++target) {
1423 
1424 
1425  vtxOffset = mTargetGeo.pointVertex(target);
1426 
1427  // Check if point is referenced by a surface primitive.
1428  if (mSurfacePrims) {
1429  bool surfacePrim = false;
1430 
1431  while (GAisValid(vtxOffset)) {
1432 
1433  primOffset = mTargetGeo.vertexPrimitive(vtxOffset);
1434 
1435  if (mSurfacePrims->containsIndex(mTargetGeo.primitiveIndex(primOffset))) {
1436  surfacePrim = true;
1437  break;
1438  }
1439 
1440  vtxOffset = mTargetGeo.vertexToNextVertex(vtxOffset);
1441  }
1442 
1443  if (!surfacePrim) continue;
1444  }
1445 
1446  const UT_Vector3 p = mTargetGeo.getPos3(target);
1447  pos[0] = p.x();
1448  pos[1] = p.y();
1449  pos[2] = p.z();
1450 
1451  indexPos = transform.worldToIndex(pos);
1452  coord[0] = int(std::floor(indexPos[0]));
1453  coord[1] = int(std::floor(indexPos[1]));
1454  coord[2] = int(std::floor(indexPos[2]));
1455 
1456  primitives.clear();
1457  IndexT primIndex;
1458 
1459  for (int d = 0; d < 8; ++d) {
1460  ijk[0] = coord[0] + (((d & 0x02) >> 1) ^ (d & 0x01));
1461  ijk[1] = coord[1] + ((d & 0x02) >> 1);
1462  ijk[2] = coord[2] + ((d & 0x04) >> 2);
1463 
1464  if (polyIdxAcc.probeValue(ijk, primIndex) &&
1466  primitives.push_back(primIndex);
1467  }
1468  }
1469 
1470  if (!primitives.empty()) {
1471  findClosestPrimitiveToPoint(mSourceGeo, primitives, pos, v0, v1, v2, uvw);
1472 
1473  v0 = mSourceGeo.vertexPoint(v0);
1474  v1 = mSourceGeo.vertexPoint(v1);
1475  v2 = mSourceGeo.vertexPoint(v2);
1476 
1477  for (size_t n = 0, N = mPointAttributes.size(); n < N; ++n) {
1478  mPointAttributes[n]->copy(v0, v1, v2, target, uvw);
1479  }
1480  }
1481  }
1482  }
1483  }
1484 }
1485 
1486 
1487 ////////////////////////////////////////
1488 
1489 
1490 template<class GridType>
1491 inline void
1493  const GU_Detail& sourceGeo,
1494  GU_Detail& targetGeo,
1495  GridType& indexGrid,
1496  openvdb::util::NullInterrupter& boss,
1497  const GA_PrimitiveGroup* primitives = nullptr)
1498 {
1499  // Match public primitive attributes
1500  GA_AttributeDict::iterator it = sourceGeo.primitiveAttribs().begin(GA_SCOPE_PUBLIC);
1501 
1502  if (indexGrid.activeVoxelCount() == 0) return;
1503 
1504  std::vector<AttributeCopyBase::Ptr> primAttributeList;
1505 
1506  // Primitive attributes
1507  for (; !it.atEnd(); ++it) {
1508  const GA_Attribute* sourceAttr = it.attrib();
1509  if (nullptr == targetGeo.findPrimitiveAttribute(it.name())) {
1510  targetGeo.addPrimAttrib(sourceAttr);
1511  }
1512  GA_Attribute* targetAttr = targetGeo.findPrimitiveAttribute(it.name());
1513 
1514  if (sourceAttr && targetAttr) {
1515  AttributeCopyBase::Ptr att = createAttributeCopier(*sourceAttr, *targetAttr);
1516  if(att) primAttributeList.push_back(att);
1517  }
1518  }
1519 
1520  if (boss.wasInterrupted()) return;
1521 
1522  std::vector<AttributeCopyBase::Ptr> vertAttributeList;
1523 
1524  it = sourceGeo.vertexAttribs().begin(GA_SCOPE_PUBLIC);
1525 
1526  // Vertex attributes
1527  for (; !it.atEnd(); ++it) {
1528  const GA_Attribute* sourceAttr = it.attrib();
1529  if (nullptr == targetGeo.findVertexAttribute(it.name())) {
1530  targetGeo.addVertexAttrib(sourceAttr);
1531  }
1532  GA_Attribute* targetAttr = targetGeo.findVertexAttribute(it.name());
1533 
1534  if (sourceAttr && targetAttr) {
1535  targetAttr->hardenAllPages();
1536  AttributeCopyBase::Ptr att = createAttributeCopier(*sourceAttr, *targetAttr);
1537  if(att) vertAttributeList.push_back(att);
1538  }
1539  }
1540 
1541  if (!boss.wasInterrupted() && (!primAttributeList.empty() || !vertAttributeList.empty())) {
1542 
1543  UTparallelFor(GA_SplittableRange(targetGeo.getPrimitiveRange(primitives)),
1544  TransferPrimitiveAttributesOp<GridType>(sourceGeo, targetGeo, indexGrid,
1545  primAttributeList, vertAttributeList));
1546  }
1547 
1548  if (!boss.wasInterrupted()) {
1549  std::vector<AttributeCopyBase::Ptr> pointAttributeList;
1550  it = sourceGeo.pointAttribs().begin(GA_SCOPE_PUBLIC);
1551 
1552  // Point attributes
1553  for (; !it.atEnd(); ++it) {
1554  if (std::string(it.name()) == "P") continue; // Ignore previous point positions.
1555 
1556  const GA_Attribute* sourceAttr = it.attrib();
1557  if (nullptr == targetGeo.findPointAttribute(it.name())) {
1558  targetGeo.addPointAttrib(sourceAttr);
1559  }
1560  GA_Attribute* targetAttr = targetGeo.findPointAttribute(it.name());
1561 
1562  if (sourceAttr && targetAttr) {
1563  AttributeCopyBase::Ptr att = createAttributeCopier(*sourceAttr, *targetAttr);
1564  if(att) pointAttributeList.push_back(att);
1565  }
1566  }
1567 
1568  if (!boss.wasInterrupted() && !pointAttributeList.empty()) {
1569  UTparallelFor(GA_SplittableRange(targetGeo.getPointRange()),
1570  TransferPointAttributesOp<GridType>(sourceGeo, targetGeo, indexGrid,
1571  pointAttributeList, primitives));
1572 
1573  }
1574  }
1575 }
1576 
1577 template<class GridType>
1578 void
1580  const GU_Detail& sourceGeo,
1581  GU_Detail& targetGeo,
1582  GridType& indexGrid,
1583  Interrupter& boss,
1584  const GA_PrimitiveGroup* primitives = nullptr)
1585 {
1586  transferPrimitiveAttributes(sourceGeo, targetGeo, indexGrid, boss.interrupter(), primitives);
1587 }
1588 
1589 } // namespace openvdb_houdini
1590 
1591 #endif // OPENVDB_HOUDINI_ATTRIBUTE_TRANSFER_UTIL_HAS_BEEN_INCLUDED
virtual openvdb::GridBase::Ptr & grid()=0
Definition: AttributeTransferUtil.h:416
void copy(GA_Offset source, GA_Offset target) override
Definition: AttributeTransferUtil.h:903
const GA_AIFSharedStringTuple & mAIF
Definition: AttributeTransferUtil.h:930
OPENVDB_API const Index32 INVALID_IDX
void set(const openvdb::Coord &ijk, const GA_Offset(&offsets)[3], const openvdb::Vec3d &weights) override
Definition: AttributeTransferUtil.h:489
AttributeCopyBase()
Definition: AttributeTransferUtil.h:818
void copy(GA_Offset &v0, GA_Offset &v1, GA_Offset &v2, GA_Offset target, const openvdb::Vec3d &uvw) override
Definition: AttributeTransferUtil.h:910
AttributeDetailBase::Ptr copy() override
Definition: AttributeTransferUtil.h:514
std::shared_ptr< AttributeDetailBase > Ptr
Definition: AttributeTransferUtil.h:387
ValueType evalAttr(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int idx)
Definition: AttributeTransferUtil.h:42
void operator()(const GA_SplittableRange &) const
Definition: AttributeTransferUtil.h:1407
SharedPtr< GridBase > Ptr
Definition: Grid.h:80
GA_Offset findClosestPrimitiveToPoint(const GU_Detail &geo, const std::set< GA_Index > &primitives, const openvdb::Vec3d &p, GA_Offset &vert0, GA_Offset &vert1, GA_Offset &vert2, openvdb::Vec3d &uvw)
Definition: AttributeTransferUtil.h:991
AttributeDetail()
Definition: AttributeTransferUtil.h:453
Vec3< int32_t > Vec3i
Definition: Vec3.h:665
openvdb::tree::IteratorRange< openvdb::Int32Tree::LeafCIter > IterRange
Definition: AttributeTransferUtil.h:716
TransferPrimitiveAttributesOp(const GU_Detail &sourceGeo, GU_Detail &targetGeo, const GridType &indexGrid, AttrCopyPtrVec &primAttributes, AttrCopyPtrVec &vertAttributes)
Definition: AttributeTransferUtil.h:1157
void runParallel()
Main calls.
Definition: AttributeTransferUtil.h:766
~MeshAttrTransfer()
Definition: AttributeTransferUtil.h:544
void copy(GA_Offset source, GA_Offset target) override
Definition: AttributeTransferUtil.h:834
void operator()(IterRange &range) const
Definition: AttributeTransferUtil.h:781
openvdb::util::NullInterrupter & interrupter()
Return a reference to the base class of the stored interrupter.
Definition: Utils.h:227
virtual ~AttributeCopyBase()
Definition: AttributeTransferUtil.h:813
Definition: AttributeTransferUtil.h:1150
int mTupleSize
Definition: AttributeTransferUtil.h:931
Utility classes and functions for OpenVDB plugins.
typename VDBGridType::ValueType ValueType
Definition: AttributeTransferUtil.h:419
std::vector< AttributeCopyBase::Ptr > AttrCopyPtrVec
Definition: AttributeTransferUtil.h:1155
GA_Attribute & mTargetAttr
Definition: AttributeTransferUtil.h:929
const GA_Attribute & mSourceAttr
Definition: AttributeTransferUtil.h:928
int64_t Int64
Definition: Types.h:57
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:107
ScalarToVectorConverter< GridType >::Type::Ptr cpt(const GridType &grid, bool threaded, InterruptT *interrupt)
Compute the Closest-Point Transform (CPT) from a distance field.
Definition: GridOperators.h:951
MeshAttrTransfer(AttributeDetailList &pointAttributes, AttributeDetailList &vertexAttributes, AttributeDetailList &primitiveAttributes, const openvdb::Int32Grid &closestPrimGrid, const openvdb::math::Transform &transform, const GU_Detail &meshGdp)
Definition: AttributeTransferUtil.h:562
float evalAttr< float >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int idx)
Definition: AttributeTransferUtil.h:51
Definition: AttributeTransferUtil.h:526
std::shared_ptr< AttributeCopyBase > Ptr
Definition: AttributeTransferUtil.h:811
OPENVDB_API Vec3d closestPointOnTriangleToPoint(const Vec3d &a, const Vec3d &b, const Vec3d &c, const Vec3d &p, Vec3d &uvw)
Closest Point on Triangle to Point. Given a triangle abc and a point p, return the point on abc close...
StrAttributeCopy(const GA_Attribute &sourceAttr, GA_Attribute &targetAttr)
Definition: AttributeTransferUtil.h:895
std::vector< AttributeDetailBase::Ptr > AttributeDetailList
Definition: AttributeTransferUtil.h:409
TreeType & tree()
Return a reference to this grid&#39;s tree, which might be shared with other grids.
Definition: Grid.h:917
std::string & name() override
Definition: AttributeTransferUtil.h:434
PointAttrTransfer(AttributeDetailList &pointAttributes, const openvdb::Int32Grid &closestPtnIdxGrid, const GU_Detail &ptGeop)
Definition: AttributeTransferUtil.h:740
float evalAttrDefault< float >(const GA_Defaults &defaults, int)
Definition: AttributeTransferUtil.h:215
Definition: AttributeTransferUtil.h:823
Base class for tree-traversal iterators over tile and voxel values.
Definition: TreeIterator.h:616
typename GridType::ConstAccessor IndexAccT
Definition: AttributeTransferUtil.h:1154
AttributeCopy(const GA_Attribute &sourceAttr, GA_Attribute &targetAttr)
Definition: AttributeTransferUtil.h:826
AttributeDetailBase & operator=(const AttributeDetailBase &)=default
void runSerial()
Definition: AttributeTransferUtil.h:773
Definition: Exceptions.h:13
AttributeDetailBase()
Definition: AttributeTransferUtil.h:405
Definition: AttributeTransferUtil.h:809
ValueT value
Definition: GridBuilder.h:1287
virtual AttributeDetailBase::Ptr copy()=0
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition: TreeIterator.h:692
Definition: AttributeTransferUtil.h:1375
typename GridType::ValueType IndexT
Definition: AttributeTransferUtil.h:1153
openvdb::tree::IteratorRange< openvdb::Int32Tree::LeafCIter > IterRange
Definition: AttributeTransferUtil.h:529
openvdb::GridBase::Ptr & grid() override
Definition: AttributeTransferUtil.h:433
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:28
Definition: AttributeTransferUtil.h:713
Deprecated wrapper class with the same interface as HoudiniInterrupter, however it does not derive fr...
Definition: Utils.h:208
Definition: AttributeTransferUtil.h:892
Definition: AttributeTransferUtil.h:34
GridType
List of types that are currently supported by NanoVDB.
Definition: NanoVDB.h:216
~PointAttrTransfer()
Definition: AttributeTransferUtil.h:725
void transferPrimitiveAttributes(const GU_Detail &sourceGeo, GU_Detail &targetGeo, GridType &indexGrid, openvdb::util::NullInterrupter &boss, const GA_PrimitiveGroup *primitives=nullptr)
Definition: AttributeTransferUtil.h:1492
Coord getCoord() const
Return the global coordinates of the voxel or tile to which this iterator is currently pointing...
Definition: TreeIterator.h:671
int32_t Int32
Definition: Types.h:56
void copy(GA_Offset &v0, GA_Offset &v1, GA_Offset &v2, GA_Offset target, const openvdb::Vec3d &uvw) override
Definition: AttributeTransferUtil.h:843
Vec3< float > Vec3s
Definition: Vec3.h:667
ValueType evalAttrDefault(const GA_Defaults &defaults, int idx)
Get an OpenVDB-specific value by evaluating GA_Default::get() with appropriate arguments.
Definition: AttributeTransferUtil.h:207
uint32_t Index32
Definition: Types.h:52
virtual std::string & name()=0
void operator()(const GA_SplittableRange &) const
Definition: AttributeTransferUtil.h:1189
AttributeCopyBase::Ptr createAttributeCopier(const GA_Attribute &sourceAttr, GA_Attribute &targetAttr)
Definition: AttributeTransferUtil.h:939
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:103
Definition: AttributeTransferUtil.h:384
void runParallel()
Main calls.
Definition: AttributeTransferUtil.h:605
ValueType combine(const ValueType &v0, const ValueType &v1, const ValueType &v2, const openvdb::Vec3d &w)
Combine different value types.
Definition: AttributeTransferUtil.h:141
void runSerial()
Definition: AttributeTransferUtil.h:612
void operator()(IterRange &range) const
Definition: AttributeTransferUtil.h:620
tbb::blocked_range< SizeType > SizeRange
Definition: ConjGradient.h:35
TransferPointAttributesOp(const GU_Detail &sourceGeo, GU_Detail &targetGeo, const GridType &indexGrid, std::vector< AttributeCopyBase::Ptr > &pointAttributes, const GA_PrimitiveGroup *surfacePrims=nullptr)
Definition: AttributeTransferUtil.h:1393