OpenVDB: AttributeTransferUtil.h Source File

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
383 class AttributeDetailBase
384 {
385 public:
386 using Ptr = std::shared_ptr<AttributeDetailBase>;
387
388 virtual ~AttributeDetailBase() = default;
389
390 AttributeDetailBase(const AttributeDetailBase&) = default;
391 AttributeDetailBase& operator=(const AttributeDetailBase&) = default;
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
401 virtual AttributeDetailBase::Ptr copy() = 0;
402
403 protected:
404 AttributeDetailBase() {}
405 };
406
407
408 using AttributeDetailList = std::vector<AttributeDetailBase::Ptr>;
409
410
412
413
414 template <class VDBGridType>
415 class AttributeDetail: public AttributeDetailBase
416 {
417 public:
418 using ValueType = typename VDBGridType::ValueType;
419
420 AttributeDetail(
421 openvdb::GridBase::Ptr grid,
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:
441 openvdb::GridBase::Ptr mGrid;
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>
452 AttributeDetail<VDBGridType>::AttributeDetail():
453 mAttribute(nullptr),
454 mTupleAIF(nullptr),
455 mTupleIndex(0)
456 {
457 }
458
459
460 template <class VDBGridType>
461 AttributeDetail<VDBGridType>::AttributeDetail(
462 openvdb::GridBase::Ptr grid,
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
488 AttributeDetail<VDBGridType>::set(const openvdb::Coord& ijk,
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
505 AttributeDetail<VDBGridType>::set(const openvdb::Coord& ijk, GA_Offset offset)
506 {
507 mAccessor.setValue(ijk,
508 evalAttr<ValueType>(mAttribute, mTupleAIF, offset, mTupleIndex));
509 }
510
511 template <class VDBGridType>
512 AttributeDetailBase::Ptr
513 AttributeDetail<VDBGridType>::copy()
514 {
515 return AttributeDetailBase::Ptr(new AttributeDetail<VDBGridType>(*this));
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.
525 class MeshAttrTransfer
526 {
527 public:
528 using IterRange = openvdb::tree::IteratorRange<openvdb::Int32Tree::LeafCIter>;
529
530 inline
531 MeshAttrTransfer(
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
543 ~MeshAttrTransfer() {}
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
561 MeshAttrTransfer::MeshAttrTransfer(
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
578 MeshAttrTransfer::MeshAttrTransfer(const MeshAttrTransfer &other):
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
604 MeshAttrTransfer::runParallel()
605 {
606 IterRange range(mClosestPrimGrid.tree().beginLeaf());
607 tbb::parallel_for(range, *this);
608 }
609
610 void
611 MeshAttrTransfer::runSerial()
612 {
613 IterRange range(mClosestPrimGrid.tree().beginLeaf());
614 (*this)(range);
615 }
616
617
618 void
619 MeshAttrTransfer::operator()(IterRange &range) const
620 {
621 openvdb::Int32Tree::LeafNodeType::ValueOnCIter iter;
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
668 cpt = closestPointOnTriangleToPoint(
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) {
679 cpt2 = closestPointOnTriangleToPoint(
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.
712 class PointAttrTransfer
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
739 PointAttrTransfer::PointAttrTransfer(
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
750 PointAttrTransfer::PointAttrTransfer(const PointAttrTransfer &other):
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
765 PointAttrTransfer::runParallel()
766 {
767 IterRange range(mClosestPtnIdxGrid.tree().beginLeaf());
768 tbb::parallel_for(range, *this);
769 }
770
771 void
772 PointAttrTransfer::runSerial()
773 {
774 IterRange range(mClosestPtnIdxGrid.tree().beginLeaf());
775 (*this)(range);
776 }
777
778
779 void
780 PointAttrTransfer::operator()(IterRange &range) const
781 {
782 openvdb::Int32Tree::LeafNodeType::ValueOnCIter iter;
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
808 struct AttributeCopyBase
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:
817 AttributeCopyBase() {}
818 };
819
820
821 template<class ValueType>
822 struct AttributeCopy: public AttributeCopyBase
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
891 struct StrAttributeCopy: public AttributeCopyBase
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;
930 int mTupleSize;
931 };
932
933
935
936
937 inline AttributeCopyBase::Ptr
938 createAttributeCopier(const GA_Attribute& sourceAttr, GA_Attribute& targetAttr)
939 {
940 const GA_AIFTuple * aifTuple = sourceAttr.getAIFTuple();
941 AttributeCopyBase::Ptr attr;
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
990 findClosestPrimitiveToPoint(
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
1046 tmpDist = (p - openvdb::math::closestPointOnTriangleToPoint(
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
1067 findClosestPrimitiveToPoint(
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
1126 tmpDist = (p - openvdb::math::closestPointOnTriangleToPoint(
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>
1149 class TransferPrimitiveAttributesOp
1150 {
1151 public:
1152 using IndexT = typename GridType::ValueType;
1153 using IndexAccT = typename GridType::ConstAccessor;
1154 using AttrCopyPtrVec = std::vector<AttributeCopyBase::Ptr>;
1155
1156 TransferPrimitiveAttributesOp(
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
1240 TransferPrimitiveAttributesOp<GridType>::copyPrimAttrs(
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) &&
1270 openvdb::Index32(primIndex) != openvdb::util::INVALID_IDX) {
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) &&
1339 (openvdb::Index32(primIndex) != openvdb::util::INVALID_IDX))
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>
1369 class TransferPointAttributesOp
1370 {
1371 public:
1372 TransferPointAttributesOp(
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>
1387 TransferPointAttributesOp<GridType>::TransferPointAttributesOp(
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) &&
1458 openvdb::Index32(primIndex) != openvdb::util::INVALID_IDX) {
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
1485 transferPrimitiveAttributes(
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:28
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_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