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