8#ifndef OPENVDB_HOUDINI_ATTRIBUTE_TRANSFER_UTIL_HAS_BEEN_INCLUDED 
    9#define OPENVDB_HOUDINI_ATTRIBUTE_TRANSFER_UTIL_HAS_BEEN_INCLUDED 
   18#include <GA/GA_PageIterator.h> 
   19#include <GA/GA_SplittableRange.h> 
   20#include <GEO/GEO_PrimPolySoup.h> 
   21#include <SYS/SYS_Types.h> 
   41template <
typename ValueType> 
inline ValueType
 
   42evalAttr(
const GA_Attribute* atr, 
const GA_AIFTuple* aif,
 
   43    GA_Offset off, 
int idx)
 
   46    aif->get(atr, off, value, idx);
 
   47    return ValueType(value);
 
 
   50template <> 
inline float 
   52    GA_Offset off, 
int idx)
 
   55    aif->get(atr, off, value, idx);
 
 
   61    GA_Offset off, 
int idx)
 
   64    aif->get(atr, off, value, idx);
 
 
   70    GA_Offset off, 
int idx)
 
   73    aif->get(atr, off, value, idx);
 
 
   84    aif->get(atr, off, comp, 0);
 
   87    aif->get(atr, off, comp, 1);
 
   90    aif->get(atr, off, comp, 2);
 
 
  103    aif->get(atr, off, comp, 0);
 
  104    vec[0] = float(comp);
 
  106    aif->get(atr, off, comp, 1);
 
  107    vec[1] = float(comp);
 
  109    aif->get(atr, off, comp, 2);
 
  110    vec[2] = float(comp);
 
 
  122    aif->get(atr, off, comp, 0);
 
  123    vec[0] = double(comp);
 
  125    aif->get(atr, off, comp, 1);
 
  126    vec[1] = double(comp);
 
  128    aif->get(atr, off, comp, 2);
 
  129    vec[2] = double(comp);
 
 
  140template <
typename ValueType> 
inline ValueType
 
  141combine(
const ValueType& v0, 
const ValueType& v1, 
const ValueType& v2,
 
  144    return ValueType(v0 * w[0] + v1 * w[1] + v2 * w[2]);
 
 
  151    if (w[2] > w[0] && w[2] > w[1]) 
return v2;
 
  152    if (w[1] > w[0] && w[1] > w[2]) 
return v1;
 
 
  160    if (w[2] > w[0] && w[2] > w[1]) 
return v2;
 
  161    if (w[1] > w[0] && w[1] > w[2]) 
return v1;
 
 
  169    if (w[2] > w[0] && w[2] > w[1]) 
return v2;
 
  170    if (w[1] > w[0] && w[1] > w[2]) 
return v1;
 
 
  180    vec[0] = float(v0[0] * w[0] + v1[0] * w[1] + v2[0] * w[2]);
 
  181    vec[1] = float(v0[1] * w[0] + v1[1] * w[1] + v2[1] * w[2]);
 
  182    vec[2] = float(v0[2] * w[0] + v1[2] * w[1] + v2[2] * w[2]);
 
 
  193    vec[0] = v0[0] * w[0] + v1[0] * w[1] + v2[0] * w[2];
 
  194    vec[1] = v0[1] * w[0] + v1[1] * w[1] + v2[1] * w[2];
 
  195    vec[2] = v0[2] * w[0] + v1[2] * w[1] + v2[2] * w[2];
 
 
  206template <
typename ValueType> 
inline ValueType
 
  210    defaults.get(idx, value);
 
  211    return ValueType(value);
 
 
  214template <> 
inline float 
  218    defaults.get(0, value);
 
 
  226    defaults.get(idx, value);
 
 
  234    defaults.get(idx, value);
 
 
  244    defaults.get(0, value);
 
  247    defaults.get(1, value);
 
  250    defaults.get(2, value);
 
 
  262    defaults.get(0, value);
 
  263    vec[0] = float(value);
 
  265    defaults.get(1, value);
 
  266    vec[1] = float(value);
 
  268    defaults.get(2, value);
 
  269    vec[2] = float(value);
 
 
  280    defaults.get(0, value);
 
  281    vec[0] = double(value);
 
  283    defaults.get(1, value);
 
  284    vec[1] = double(value);
 
  286    defaults.get(2, value);
 
  287    vec[2] = double(value);
 
  292template <> 
inline openvdb::math::Quat<float>
 
  295    openvdb::math::Quat<float> quat;
 
  298    for (
int i = 0; i < 4; i++) {
 
  299        defaults.get(i, value);
 
  300        quat[i] = float(value);
 
  306template <> 
inline openvdb::math::Quat<double>
 
  309    openvdb::math::Quat<double> quat;
 
  312    for (
int i = 0; i < 4; i++) {
 
  313        defaults.get(i, value);
 
  314        quat[i] = double(value);
 
  320template <> 
inline openvdb::math::Mat3<float>
 
  323    openvdb::math::Mat3<float> mat;
 
  325    float* data = mat.asPointer();
 
  327    for (
int i = 0; i < 9; i++) {
 
  328        defaults.get(i, value);
 
  329        data[i] = float(value);
 
  335template <> 
inline openvdb::math::Mat3<double>
 
  338    openvdb::math::Mat3<double> mat;
 
  340    double* data = mat.asPointer();
 
  342    for (
int i = 0; i < 9; i++) {
 
  343        defaults.get(i, value);
 
  344        data[i] = double(value);
 
 
  350template <> 
inline openvdb::math::Mat4<float>
 
  353    openvdb::math::Mat4<float> mat;
 
  355    float* data = mat.asPointer();
 
  357    for (
int i = 0; i < 16; i++) {
 
  358        defaults.get(i, value);
 
  359        data[i] = float(value);
 
  365template <> 
inline openvdb::math::Mat4<double>
 
  368    openvdb::math::Mat4<double> mat;
 
  370    double* data = mat.asPointer();
 
  372    for (
int i = 0; i < 16; i++) {
 
  373        defaults.get(i, value);
 
  374        data[i] = double(value);
 
  387    using Ptr = std::shared_ptr<AttributeDetailBase>;
 
  399    virtual openvdb::GridBase::Ptr& 
grid() = 0;
 
  400    virtual std::string& 
name() = 0;
 
 
  415template <
class VDBGr
idType>
 
  422        openvdb::GridBase::Ptr 
grid,
 
  423        const GA_Attribute* attribute,
 
  424        const GA_AIFTuple* tupleAIF,
 
  425        const int tupleIndex,
 
  426        const bool isVector = 
false);
 
  433    openvdb::GridBase::Ptr& 
grid()
 override { 
return mGrid; }
 
  434    std::string& 
name()
 override { 
return mName; }
 
  442    openvdb::GridBase::Ptr mGrid;
 
  443    typename VDBGridType::Accessor mAccessor;
 
  445    const GA_Attribute* mAttribute;
 
  446    const GA_AIFTuple*  mTupleAIF;
 
  447    const int           mTupleIndex;
 
 
  452template <
class VDBGr
idType>
 
  461template <
class VDBGr
idType>
 
  463    openvdb::GridBase::Ptr 
grid,
 
  464    const GA_Attribute* attribute,
 
  465    const GA_AIFTuple* tupleAIF,
 
  466    const int tupleIndex,
 
  467    const bool isVector):
 
  469    mAccessor(
openvdb::GridBase::
grid<VDBGridType>(mGrid)->getAccessor()),
 
  470    mAttribute(attribute),
 
  472    mTupleIndex(tupleIndex)
 
  474    std::ostringstream 
name;
 
  475    name << mAttribute->getName();
 
  477    const int tupleSize = mTupleAIF->getTupleSize(mAttribute);
 
  479    if(!isVector && tupleSize != 1) {
 
  480        name << 
"_" << mTupleIndex;
 
 
  487template <
class VDBGr
idType>
 
  493        mAttribute, mTupleAIF, offsets[0], mTupleIndex);
 
  496        mAttribute, mTupleAIF, offsets[1], mTupleIndex);
 
  499        mAttribute, mTupleAIF, offsets[2], mTupleIndex);
 
 
  504template <
class VDBGr
idType>
 
  508    mAccessor.setValue(ijk,
 
 
  512template <
class VDBGr
idType>
 
  529    using IterRange = openvdb::tree::IteratorRange<openvdb::Int32Tree::LeafCIter>;
 
  537        const openvdb::math::Transform& transform,
 
  538        const GU_Detail& meshGdp);
 
  556    const openvdb::math::Transform& mTransform;
 
  558    const GA_Detail &mMeshGdp;
 
 
  567    const openvdb::math::Transform& transform,
 
  568    const GU_Detail& meshGdp):
 
  569    mPointAttributes(pointAttributes),
 
  570    mVertexAttributes(vertexAttributes),
 
  571    mPrimitiveAttributes(primitiveAttributes),
 
  572    mClosestPrimGrid(closestPrimGrid),
 
  573    mTransform(transform),
 
 
  580    mPointAttributes(other.mPointAttributes.size()),
 
  581    mVertexAttributes(other.mVertexAttributes.size()),
 
  582    mPrimitiveAttributes(other.mPrimitiveAttributes.size()),
 
  583    mClosestPrimGrid(other.mClosestPrimGrid),
 
  584    mTransform(other.mTransform),
 
  585    mMeshGdp(other.mMeshGdp)
 
  590    for (
size_t i = 0, N = other.mPointAttributes.size(); i < N; ++i) {
 
  591       mPointAttributes[i] = other.mPointAttributes[i]->copy();
 
  594    for (
size_t i = 0, N = other.mVertexAttributes.size(); i < N; ++i) {
 
  595       mVertexAttributes[i] = other.mVertexAttributes[i]->copy();
 
  598    for (
size_t i = 0, N = other.mPrimitiveAttributes.size(); i < N; ++i) {
 
  599       mPrimitiveAttributes[i] =  other.mPrimitiveAttributes[i]->copy();
 
 
  607    IterRange range(mClosestPrimGrid.tree().beginLeaf());
 
  608    tbb::parallel_for(range, *
this);
 
 
  614    IterRange range(mClosestPrimGrid.tree().beginLeaf());
 
 
  626    const bool ptnAttrTransfer = mPointAttributes.size() > 0;
 
  627    const bool vtxAttrTransfer = mVertexAttributes.size() > 0;
 
  629    GA_Offset vtxOffsetList[4], ptnOffsetList[4], vtxOffsets[3], ptnOffsets[3], prmOffset;
 
  632    for ( ; range; ++range) {
 
  633        iter = range.iterator()->beginValueOn();
 
  634        for ( ; iter; ++iter) {
 
  638            const GA_Index prmIndex = iter.
getValue();
 
  639            prmOffset = mMeshGdp.primitiveOffset(prmIndex);
 
  642            for (
size_t i = 0, N = mPrimitiveAttributes.size(); i < N; ++i) {
 
  643                mPrimitiveAttributes[i]->set(ijk, prmOffset);
 
  646            if (!ptnAttrTransfer && !vtxAttrTransfer) 
continue;
 
  649            const GA_Primitive * primRef = mMeshGdp.getPrimitiveList().get(prmOffset);
 
  651            const GA_Size vtxn = primRef->getVertexCount();
 
  654            for (GA_Size vtx = 0; vtx < vtxn; ++vtx) {
 
  655                const GA_Offset vtxoff = primRef->getVertexOffset(vtx);
 
  656                ptnOffsetList[vtx] = mMeshGdp.vertexPoint(vtxoff);
 
  657                vtxOffsetList[vtx] = vtxoff;
 
  659                UT_Vector3 p = mMeshGdp.getPos3(ptnOffsetList[vtx]);
 
  660                ptnList[vtx][0] = double(p[0]);
 
  661                ptnList[vtx][1] = double(p[1]);
 
  662                ptnList[vtx][2] = double(p[2]);
 
  665            xyz = mTransform.indexToWorld(ijk);
 
  669            cpt = closestPointOnTriangleToPoint(
 
  670                    ptnList[0], ptnList[2], ptnList[1], xyz, uvw);
 
  672            vtxOffsets[0] = vtxOffsetList[0]; 
 
  673            ptnOffsets[0] = ptnOffsetList[0];
 
  674            vtxOffsets[1] = vtxOffsetList[2];
 
  675            ptnOffsets[1] = ptnOffsetList[2];
 
  676            vtxOffsets[2] = vtxOffsetList[1];
 
  677            ptnOffsets[2] = ptnOffsetList[1];
 
  680                cpt2 = closestPointOnTriangleToPoint(
 
  681                        ptnList[0], ptnList[3], ptnList[2], xyz, uvw2);
 
  683                if ((cpt2 - xyz).lengthSqr() < (cpt - xyz).lengthSqr()) {
 
  685                    vtxOffsets[1] = vtxOffsetList[3];
 
  686                    ptnOffsets[1] = ptnOffsetList[3];
 
  687                    vtxOffsets[2] = vtxOffsetList[2];
 
  688                    ptnOffsets[2] = ptnOffsetList[2];
 
  693            for (
size_t i = 0, N = mVertexAttributes.size(); i < N; ++i) {
 
  694                mVertexAttributes[i]->set(ijk, vtxOffsets, uvw);
 
  698            for (
size_t i = 0, N = mPointAttributes.size(); i < N; ++i) {
 
  699                mPointAttributes[i]->set(ijk, ptnOffsets, uvw);
 
 
  716    using IterRange = openvdb::tree::IteratorRange<openvdb::Int32Tree::LeafCIter>;
 
  721        const GU_Detail& ptGeop);
 
  736    const GA_Detail &mPtGeo;
 
 
  743    const GU_Detail& ptGeop):
 
  744    mPointAttributes(pointAttributes),
 
  745    mClosestPtnIdxGrid(closestPtnIdxGrid),
 
 
  752    mPointAttributes(other.mPointAttributes.size()),
 
  753    mClosestPtnIdxGrid(other.mClosestPtnIdxGrid),
 
  759    for (
size_t i = 0, N = other.mPointAttributes.size(); i < N; ++i) {
 
  760       mPointAttributes[i] = other.mPointAttributes[i]->copy();
 
 
  768    IterRange range(mClosestPtnIdxGrid.tree().beginLeaf());
 
  769    tbb::parallel_for(range, *
this);
 
 
  775    IterRange range(mClosestPtnIdxGrid.tree().beginLeaf());
 
 
  786    for ( ; range; ++range) {
 
  787        iter = range.iterator()->beginValueOn();
 
  788        for ( ; iter; ++iter) {
 
  792            const GA_Index pointIndex = iter.
getValue();
 
  793            const GA_Offset pointOffset = mPtGeo.pointOffset(pointIndex);
 
  796            for (
size_t i = 0, N = mPointAttributes.size(); i < N; ++i) {
 
  797                mPointAttributes[i]->set(ijk, pointOffset);
 
 
  811    using Ptr = std::shared_ptr<AttributeCopyBase>;
 
  814    virtual void copy(GA_Offset , GA_Offset ) = 0;
 
  815    virtual void copy(GA_Offset&, GA_Offset&, GA_Offset&, GA_Offset ,
 
 
  822template<
class ValueType>
 
  827        : mSourceAttr(sourceAttr)
 
  828        , mTargetAttr(targetAttr)
 
  829        , mAIFTuple(*mSourceAttr.getAIFTuple())
 
  830        , mTupleSize(mAIFTuple.getTupleSize(&mSourceAttr))
 
 
  834    void copy(GA_Offset source, GA_Offset target)
 override 
  837        for (
int i = 0; i < mTupleSize; ++i) {
 
  838            mAIFTuple.get(&mSourceAttr, source, data, i);
 
  839            mAIFTuple.set(&mTargetAttr, target, data, i);
 
 
  843    void copy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target,
 
  846        doCopy<ValueType>(v0, v1, v2, target, uvw);
 
 
  851    typename std::enable_if<std::is_integral<T>::value>::type
 
  852    doCopy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target, 
const openvdb::Vec3d& uvw)
 
  854        GA_Offset source = v0;
 
  861        if (uvw[2] < min) source = v2;
 
  865        for (
int i = 0; i < mTupleSize; ++i) {
 
  866            mAIFTuple.get(&mSourceAttr, source, data, i);
 
  867            mAIFTuple.set(&mTargetAttr, target, data, i);
 
  871    template <
typename T>
 
  872    typename std::enable_if<std::is_floating_point<T>::value>::type
 
  873    doCopy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target, 
const openvdb::Vec3d& uvw)
 
  876        for (
int i = 0; i < mTupleSize; ++i) {
 
  877            mAIFTuple.get(&mSourceAttr, v0, a, i);
 
  878            mAIFTuple.get(&mSourceAttr, v1, b, i);
 
  879            mAIFTuple.get(&mSourceAttr, v2, c, i);
 
  880            mAIFTuple.set(&mTargetAttr, target, a*uvw[0] + b*uvw[1] + c*uvw[2], i);
 
  885    const GA_Attribute& mSourceAttr;
 
  886    GA_Attribute& mTargetAttr;
 
  887    const GA_AIFTuple& mAIFTuple;
 
 
  903    void copy(GA_Offset source, GA_Offset target)
 override 
 
  910    void copy(GA_Offset& v0, GA_Offset& v1, GA_Offset& v2, GA_Offset target,
 
  913        GA_Offset source = v0;
 
  920        if (uvw[2] < min) source = v2;
 
 
  930    const GA_AIFSharedStringTuple& 
mAIF;
 
 
  941    const GA_AIFTuple * aifTuple = sourceAttr.getAIFTuple();
 
  945        const GA_Storage sourceStorage = aifTuple->getStorage(&sourceAttr);
 
  946        const GA_Storage targetStorage = aifTuple->getStorage(&targetAttr);
 
  948        const int sourceTupleSize = aifTuple->getTupleSize(&sourceAttr);
 
  949        const int targetTupleSize = aifTuple->getTupleSize(&targetAttr);
 
  951        if (sourceStorage == targetStorage && sourceTupleSize == targetTupleSize) {
 
  952            switch (sourceStorage)
 
  963                case GA_STORE_REAL16:
 
  964                case GA_STORE_REAL32:
 
  968                case GA_STORE_REAL64:
 
  977        const GA_AIFSharedStringTuple * aifString = sourceAttr.getAIFSharedStringTuple();
 
 
  992    const GU_Detail& geo, 
const std::set<GA_Index>& primitives, 
const openvdb::Vec3d& p,
 
  993    GA_Offset& vert0, GA_Offset& vert1, GA_Offset& vert2, 
openvdb::Vec3d& uvw)
 
  995    std::set<GA_Index>::const_iterator it = primitives.begin();
 
  997    GA_Offset primOffset = GA_INVALID_OFFSET;
 
  998    const GA_Primitive * primRef = 
nullptr;
 
  999    double minDist = std::numeric_limits<double>::max();
 
 1002    UT_Vector3 tmpPoint;
 
 1004    for (; it != primitives.end(); ++it) {
 
 1006        const GA_Offset offset = geo.primitiveOffset(*it);
 
 1007        primRef = geo.getPrimitiveList().get(offset);
 
 1009        const GA_Size vertexCount = primRef->getVertexCount();
 
 1012        if (vertexCount == 3 || vertexCount == 4) {
 
 1014            tmpPoint = geo.getPos3(primRef->getPointOffset(0));
 
 1015            a[0] = tmpPoint.
x();
 
 1016            a[1] = tmpPoint.
y();
 
 1017            a[2] = tmpPoint.
z();
 
 1019            tmpPoint = geo.getPos3(primRef->getPointOffset(1));
 
 1020            b[0] = tmpPoint.
x();
 
 1021            b[1] = tmpPoint.
y();
 
 1022            b[2] = tmpPoint.
z();
 
 1024            tmpPoint = geo.getPos3(primRef->getPointOffset(2));
 
 1025            c[0] = tmpPoint.
x();
 
 1026            c[1] = tmpPoint.
y();
 
 1027            c[2] = tmpPoint.
z();
 
 1030                (p - openvdb::math::closestPointOnTriangleToPoint(a, c, b, p, tmpUVW)).lengthSqr();
 
 1032            if (tmpDist < minDist) {
 
 1034                primOffset = offset;
 
 1036                vert0 = primRef->getVertexOffset(0);
 
 1037                vert1 = primRef->getVertexOffset(2);
 
 1038                vert2 = primRef->getVertexOffset(1);
 
 1041            if (vertexCount == 4) {
 
 1042                tmpPoint = geo.getPos3(primRef->getPointOffset(3));
 
 1043                d[0] = tmpPoint.
x();
 
 1044                d[1] = tmpPoint.
y();
 
 1045                d[2] = tmpPoint.
z();
 
 1047                tmpDist = (p - openvdb::math::closestPointOnTriangleToPoint(
 
 1048                    a, d, c, p, tmpUVW)).lengthSqr();
 
 1049                if (tmpDist < minDist) {
 
 1051                    primOffset = offset;
 
 1053                    vert0 = primRef->getVertexOffset(0);
 
 1054                    vert1 = primRef->getVertexOffset(3);
 
 1055                    vert2 = primRef->getVertexOffset(2);
 
 
 1069    const GU_Detail& geo, std::vector<GA_Index>& primitives, 
const openvdb::Vec3d& p,
 
 1070    GA_Offset& vert0, GA_Offset& vert1, GA_Offset& vert2, 
openvdb::Vec3d& uvw)
 
 1072    GA_Offset primOffset = GA_INVALID_OFFSET;
 
 1073    const GA_Primitive * primRef = 
nullptr;
 
 1074    double minDist = std::numeric_limits<double>::max();
 
 1077    UT_Vector3 tmpPoint;
 
 1079    std::sort(primitives.begin(), primitives.end());
 
 1081    GA_Index lastPrim = -1;
 
 1082    for (
size_t n = 0, N = primitives.size(); n < N; ++n) {
 
 1083        if (primitives[n] == lastPrim) 
continue;
 
 1084        lastPrim = primitives[n];
 
 1086        const GA_Offset offset = geo.primitiveOffset(lastPrim);
 
 1087        primRef = geo.getPrimitiveList().get(offset);
 
 1089        const GA_Size vertexCount = primRef->getVertexCount();
 
 1092        if (vertexCount == 3 || vertexCount == 4) {
 
 1094            tmpPoint = geo.getPos3(primRef->getPointOffset(0));
 
 1095            a[0] = tmpPoint.
x();
 
 1096            a[1] = tmpPoint.
y();
 
 1097            a[2] = tmpPoint.
z();
 
 1099            tmpPoint = geo.getPos3(primRef->getPointOffset(1));
 
 1100            b[0] = tmpPoint.
x();
 
 1101            b[1] = tmpPoint.
y();
 
 1102            b[2] = tmpPoint.
z();
 
 1104            tmpPoint = geo.getPos3(primRef->getPointOffset(2));
 
 1105            c[0] = tmpPoint.
x();
 
 1106            c[1] = tmpPoint.
y();
 
 1107            c[2] = tmpPoint.
z();
 
 1110                (p - openvdb::math::closestPointOnTriangleToPoint(a, c, b, p, tmpUVW)).lengthSqr();
 
 1112            if (tmpDist < minDist) {
 
 1114                primOffset = offset;
 
 1116                vert0 = primRef->getVertexOffset(0);
 
 1117                vert1 = primRef->getVertexOffset(2);
 
 1118                vert2 = primRef->getVertexOffset(1);
 
 1121            if (vertexCount == 4) {
 
 1122                tmpPoint = geo.getPos3(primRef->getPointOffset(3));
 
 1123                d[0] = tmpPoint.
x();
 
 1124                d[1] = tmpPoint.
y();
 
 1125                d[2] = tmpPoint.
z();
 
 1127                tmpDist = (p - openvdb::math::closestPointOnTriangleToPoint(
 
 1128                    a, d, c, p, tmpUVW)).lengthSqr();
 
 1129                if (tmpDist < minDist) {
 
 1131                    primOffset = offset;
 
 1133                    vert0 = primRef->getVertexOffset(0);
 
 1134                    vert1 = primRef->getVertexOffset(3);
 
 1135                    vert2 = primRef->getVertexOffset(2);
 
 
 1149template<
class Gr
idType>
 
 1158        const GU_Detail& sourceGeo,
 
 1159        GU_Detail& targetGeo,
 
 1160        const GridType& indexGrid,
 
 1163        : mSourceGeo(sourceGeo)
 
 1164        , mTargetGeo(targetGeo)
 
 1165        , mIndexGrid(indexGrid)
 
 1166        , mPrimAttributes(primAttributes)
 
 1167        , mVertAttributes(vertAttributes)
 
 
 1171    inline void operator()(
const GA_SplittableRange&) 
const;
 
 1174    inline void copyPrimAttrs(
const GA_Primitive&, 
const UT_Vector3&, 
IndexAccT&) 
const;
 
 1176    template<
typename PrimT>
 
 1177    inline void copyVertAttrs(
const PrimT&, 
const UT_Vector3&, 
IndexAccT&) 
const;
 
 1179    const GU_Detail& mSourceGeo;
 
 1180    GU_Detail& mTargetGeo;
 
 1181    const GridType& mIndexGrid;
 
 
 1187template<
class Gr
idType>
 
 1191    if (mPrimAttributes.empty() && mVertAttributes.empty()) 
return;
 
 1193    auto polyIdxAcc = mIndexGrid.getConstAccessor();
 
 1195    for (GA_PageIterator pageIt = range.beginPages(); !pageIt.atEnd(); ++pageIt) {
 
 1196        auto start = GA_Offset(), end = GA_Offset();
 
 1197        for (GA_Iterator blockIt(pageIt.begin()); blockIt.blockAdvance(start, end); ) {
 
 1198            for (
auto targetOffset = start; targetOffset < end; ++targetOffset) {
 
 1199                const auto* target = mTargetGeo.getPrimitiveList().get(targetOffset);
 
 1200                if (!target) 
continue;
 
 1202                const auto targetN = mTargetGeo.getGEOPrimitive(targetOffset)->computeNormal();
 
 1204                if (!mPrimAttributes.empty()) {
 
 1206                    copyPrimAttrs(*target, targetN, polyIdxAcc);
 
 1209                if (!mVertAttributes.empty()) {
 
 1210                    if (target->getTypeId() != GA_PRIMPOLYSOUP) {
 
 1211                        copyVertAttrs(*target, targetN, polyIdxAcc);
 
 1213                        if (
const auto* soup = UTverify_cast<const GEO_PrimPolySoup*>(target)) {
 
 1215                            using SizeRange = UT_BlockedRange<GA_Size>;
 
 1216                            const auto processPolyRange = [&](
const SizeRange& range) {
 
 1217                                auto threadLocalPolyIdxAcc = mIndexGrid.getConstAccessor();
 
 1218                                for (GEO_PrimPolySoup::PolygonIterator it(*soup, range.begin());
 
 1219                                    !it.atEnd() && (it.polygon() < range.end()); ++it)
 
 1221                                    copyVertAttrs(it, it.computeNormal(), threadLocalPolyIdxAcc);
 
 1224                            UTparallelFor(SizeRange(0, soup->getPolygonCount()), processPolyRange);
 
 
 1239template<
class Gr
idType>
 
 1241TransferPrimitiveAttributesOp<GridType>::copyPrimAttrs(
 
 1242    const GA_Primitive& targetPrim,
 
 1243    const UT_Vector3& targetNormal,
 
 1244    IndexAccT& polyIdxAcc)
 const 
 1246    const auto& transform = mIndexGrid.transform();
 
 1248    UT_Vector3 sourceN, targetN = targetNormal;
 
 1249    const bool isPolySoup = (targetPrim.getTypeId() == GA_PRIMPOLYSOUP);
 
 1253    int count = 
static_cast<int>(targetPrim.getVertexCount());
 
 1254    for (
int vtx = 0; vtx < count; ++vtx) {
 
 1255        pos += UTvdbConvert(targetPrim.getPos3(vtx));
 
 1257    if (count > 1) pos /= double(count);
 
 1262    std::vector<GA_Index> primitives, similarPrimitives;
 
 1266    primitives.reserve(8);
 
 1267    similarPrimitives.reserve(8);
 
 1268    for (
int d = 0; d < 8; ++d) {
 
 1269        ijk[0] = coord[0] + (((d & 0x02) >> 1) ^ (d & 0x01));
 
 1270        ijk[1] = coord[1] + ((d & 0x02) >> 1);
 
 1271        ijk[2] = coord[2] + ((d & 0x04) >> 2);
 
 1273        if (polyIdxAcc.probeValue(ijk, primIndex) &&
 
 1276            GA_Offset tmpOffset = mSourceGeo.primitiveOffset(primIndex);
 
 1277            sourceN = mSourceGeo.getGEOPrimitive(tmpOffset)->computeNormal();
 
 1282            if (isPolySoup || sourceN.dot(targetN) > 0.5) {
 
 1283                similarPrimitives.push_back(primIndex);
 
 1285                primitives.push_back(primIndex);
 
 1290    if (!primitives.empty() || !similarPrimitives.empty()) {
 
 1291        GA_Offset source, v0, v1, v2;
 
 1293        if (!similarPrimitives.empty()) {
 
 1295                mSourceGeo, similarPrimitives, pos, v0, v1, v2, uvw);
 
 1298                mSourceGeo, primitives, pos, v0, v1, v2, uvw);
 
 1302        const auto targetOffset = targetPrim.getMapOffset();
 
 1303        for (
size_t n = 0, N = mPrimAttributes.size(); n < N; ++n) {
 
 1304            mPrimAttributes[n]->copy(source, targetOffset);
 
 1315template<
typename Gr
idType>
 
 1316template<
typename PrimT>
 
 1318TransferPrimitiveAttributesOp<GridType>::copyVertAttrs(
 
 1319    const PrimT& targetPrim,
 
 1320    const UT_Vector3& targetNormal,
 
 1321    IndexAccT& polyIdxAcc)
 const 
 1323    const auto& transform = mIndexGrid.transform();
 
 1327    UT_Vector3 sourceNormal;
 
 1328    std::vector<GA_Index> primitives, similarPrimitives;
 
 1330    primitives.reserve(8);
 
 1331    similarPrimitives.reserve(8);
 
 1332    for (GA_Size vtx = 0, vtxN = targetPrim.getVertexCount(); vtx < vtxN; ++vtx) {
 
 1333        pos = UTvdbConvert(targetPrim.getPos3(vtx));
 
 1337        similarPrimitives.clear();
 
 1339        for (
int d = 0; d < 8; ++d) {
 
 1340            ijk[0] = coord[0] + (((d & 0x02) >> 1) ^ (d & 0x01));
 
 1341            ijk[1] = coord[1] + ((d & 0x02) >> 1);
 
 1342            ijk[2] = coord[2] + ((d & 0x04) >> 2);
 
 1344            if (polyIdxAcc.probeValue(ijk, primIndex) &&
 
 1347                GA_Offset tmpOffset = mSourceGeo.primitiveOffset(primIndex);
 
 1348                sourceNormal = mSourceGeo.getGEOPrimitive(tmpOffset)->computeNormal();
 
 1349                if (sourceNormal.dot(targetNormal) > 0.5) {
 
 1350                    primitives.push_back(primIndex);
 
 1355        if (!primitives.empty() || !similarPrimitives.empty()) {
 
 1356            GA_Offset v0, v1, v2;
 
 1357            if (!similarPrimitives.empty()) {
 
 1363            for (
size_t n = 0, N = mVertAttributes.size(); n < N; ++n) {
 
 1364                mVertAttributes[n]->copy(v0, v1, v2, targetPrim.getVertexOffset(vtx), uvw);
 
 1374template<
class Gr
idType>
 
 1379        const GU_Detail& sourceGeo, GU_Detail& targetGeo, 
const GridType& indexGrid,
 
 1380        std::vector<AttributeCopyBase::Ptr>& pointAttributes,
 
 1381        const GA_PrimitiveGroup* surfacePrims = 
nullptr);
 
 1383    void operator()(
const GA_SplittableRange&) 
const;
 
 1385    const GU_Detail& mSourceGeo;
 
 1386    GU_Detail& mTargetGeo;
 
 1387    const GridType& mIndexGrid;
 
 1388    std::vector<AttributeCopyBase::Ptr>& mPointAttributes;
 
 1389    const GA_PrimitiveGroup* mSurfacePrims;
 
 
 1392template<
class Gr
idType>
 
 1394    const GU_Detail& sourceGeo, GU_Detail& targetGeo, 
const GridType& indexGrid,
 
 1395    std::vector<AttributeCopyBase::Ptr>& pointAttributes,
 
 1396    const GA_PrimitiveGroup* surfacePrims)
 
 1397    : mSourceGeo(sourceGeo)
 
 1398    , mTargetGeo(targetGeo)
 
 1399    , mIndexGrid(indexGrid)
 
 1400    , mPointAttributes(pointAttributes)
 
 1401    , mSurfacePrims(surfacePrims)
 
 
 1405template<
class Gr
idType>
 
 1409    using IndexT = 
typename GridType::ValueType;
 
 1411    GA_Offset start, end, vtxOffset, primOffset, target, v0, v1, v2;
 
 1413    typename GridType::ConstAccessor polyIdxAcc = mIndexGrid.getConstAccessor();
 
 1414    const openvdb::math::Transform& transform = mIndexGrid.transform();
 
 1416    std::vector<GA_Index> primitives;
 
 1419    primitives.reserve(8);
 
 1420    for (GA_PageIterator pageIt = range.beginPages(); !pageIt.atEnd(); ++pageIt) {
 
 1421        for (GA_Iterator blockIt(pageIt.begin()); blockIt.blockAdvance(start, end); ) {
 
 1422            for (target = start; target < end; ++target) {
 
 1425                vtxOffset = mTargetGeo.pointVertex(target);
 
 1428                if (mSurfacePrims) {
 
 1429                    bool surfacePrim = 
false;
 
 1431                    while (GAisValid(vtxOffset)) {
 
 1433                        primOffset = mTargetGeo.vertexPrimitive(vtxOffset);
 
 1435                        if (mSurfacePrims->containsIndex(mTargetGeo.primitiveIndex(primOffset))) {
 
 1440                        vtxOffset = mTargetGeo.vertexToNextVertex(vtxOffset);
 
 1443                    if (!surfacePrim) 
continue;
 
 1446                const UT_Vector3 p = mTargetGeo.getPos3(target);
 
 1451                indexPos = transform.worldToIndex(pos);
 
 1452                coord[0] = int(std::floor(indexPos[0]));
 
 1453                coord[1] = int(std::floor(indexPos[1]));
 
 1454                coord[2] = int(std::floor(indexPos[2]));
 
 1459                for (
int d = 0; d < 8; ++d) {
 
 1460                    ijk[0] = coord[0] + (((d & 0x02) >> 1) ^ (d & 0x01));
 
 1461                    ijk[1] = coord[1] + ((d & 0x02) >> 1);
 
 1462                    ijk[2] = coord[2] + ((d & 0x04) >> 2);
 
 1464                    if (polyIdxAcc.probeValue(ijk, primIndex) &&
 
 1466                        primitives.push_back(primIndex);
 
 1470                if (!primitives.empty()) {
 
 1473                    v0 = mSourceGeo.vertexPoint(v0);
 
 1474                    v1 = mSourceGeo.vertexPoint(v1);
 
 1475                    v2 = mSourceGeo.vertexPoint(v2);
 
 1477                    for (
size_t n = 0, N = mPointAttributes.size(); n < N; ++n) {
 
 1478                        mPointAttributes[n]->copy(v0, v1, v2, target, uvw);
 
 
 1490template<
class Gr
idType>
 
 1493    const GU_Detail& sourceGeo,
 
 1494    GU_Detail& targetGeo,
 
 1495    GridType& indexGrid,
 
 1496    openvdb::util::NullInterrupter& boss,
 
 1497    const GA_PrimitiveGroup* primitives = 
nullptr)
 
 1500    GA_AttributeDict::iterator it = sourceGeo.primitiveAttribs().begin(GA_SCOPE_PUBLIC);
 
 1502    if (indexGrid.activeVoxelCount() == 0) 
return;
 
 1504    std::vector<AttributeCopyBase::Ptr> primAttributeList;
 
 1507    for (; !it.atEnd(); ++it) {
 
 1508        const GA_Attribute* sourceAttr = it.attrib();
 
 1509        if (
nullptr == targetGeo.findPrimitiveAttribute(it.name())) {
 
 1510            targetGeo.addPrimAttrib(sourceAttr);
 
 1512        GA_Attribute* targetAttr = targetGeo.findPrimitiveAttribute(it.name());
 
 1514        if (sourceAttr && targetAttr) {
 
 1516            if(att) primAttributeList.push_back(att);
 
 1520    if (boss.wasInterrupted()) 
return;
 
 1522    std::vector<AttributeCopyBase::Ptr> vertAttributeList;
 
 1524    it = sourceGeo.vertexAttribs().begin(GA_SCOPE_PUBLIC);
 
 1527    for (; !it.atEnd(); ++it) {
 
 1528        const GA_Attribute* sourceAttr = it.attrib();
 
 1529        if (
nullptr == targetGeo.findVertexAttribute(it.name())) {
 
 1530            targetGeo.addVertexAttrib(sourceAttr);
 
 1532        GA_Attribute* targetAttr = targetGeo.findVertexAttribute(it.name());
 
 1534        if (sourceAttr && targetAttr) {
 
 1535            targetAttr->hardenAllPages();
 
 1537            if(att) vertAttributeList.push_back(att);
 
 1541    if (!boss.wasInterrupted() && (!primAttributeList.empty() || !vertAttributeList.empty())) {
 
 1543        UTparallelFor(GA_SplittableRange(targetGeo.getPrimitiveRange(primitives)),
 
 1545                primAttributeList, vertAttributeList));
 
 1548    if (!boss.wasInterrupted()) {
 
 1549        std::vector<AttributeCopyBase::Ptr> pointAttributeList;
 
 1550        it = sourceGeo.pointAttribs().begin(GA_SCOPE_PUBLIC);
 
 1553        for (; !it.atEnd(); ++it) {
 
 1554            if (std::string(it.name()) == 
"P") 
continue; 
 
 1556            const GA_Attribute* sourceAttr = it.attrib();
 
 1557            if (
nullptr == targetGeo.findPointAttribute(it.name())) {
 
 1558                targetGeo.addPointAttrib(sourceAttr);
 
 1560            GA_Attribute* targetAttr = targetGeo.findPointAttribute(it.name());
 
 1562            if (sourceAttr && targetAttr) {
 
 1564                if(att) pointAttributeList.push_back(att);
 
 1568        if (!boss.wasInterrupted() && !pointAttributeList.empty()) {
 
 1569            UTparallelFor(GA_SplittableRange(targetGeo.getPointRange()),
 
 1571                    pointAttributeList, primitives));
 
 
 1577template<
class Gr
idType>
 
 1580    const GU_Detail& sourceGeo,
 
 1581    GU_Detail& targetGeo,
 
 1582    GridType& indexGrid,
 
 1584    const GA_PrimitiveGroup* primitives = 
nullptr)
 
 
 
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
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
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition Vec3.h:86
T & y()
Definition Vec3.h:87
T & z()
Definition Vec3.h:88
const ValueT & getValue() const
Return the tile or voxel value to which this iterator is currently pointing.
Definition TreeIterator.h:693
Coord getCoord() const
Return the global coordinates of the voxel or tile to which this iterator is currently pointing.
Definition TreeIterator.h:672
TreeValueIteratorBase< const Tree, typename RootNodeType::ValueOnCIter > ValueOnCIter
Definition Tree.h:1053
virtual void set(const openvdb::Coord &ijk, GA_Offset offset)=0
virtual openvdb::GridBase::Ptr & grid()=0
std::shared_ptr< AttributeDetailBase > Ptr
Definition AttributeTransferUtil.h:387
virtual std::string & name()=0
AttributeDetailBase()
Definition AttributeTransferUtil.h:405
virtual void set(const openvdb::Coord &ijk, const GA_Offset(&offsets)[3], const openvdb::Vec3d &weights)=0
virtual AttributeDetailBase::Ptr copy()=0
AttributeDetailBase(const AttributeDetailBase &)=default
AttributeDetailBase & operator=(const AttributeDetailBase &)=default
virtual ~AttributeDetailBase()=default
typename VDBGridType::ValueType ValueType
Definition AttributeTransferUtil.h:419
AttributeDetail(openvdb::GridBase::Ptr grid, const GA_Attribute *attribute, const GA_AIFTuple *tupleAIF, const int tupleIndex, const bool isVector=false)
Definition AttributeTransferUtil.h:462
openvdb::GridBase::Ptr & grid() override
Definition AttributeTransferUtil.h:433
void set(const openvdb::Coord &ijk, const GA_Offset(&offsets)[3], const openvdb::Vec3d &weights) override
Definition AttributeTransferUtil.h:489
std::string & name() override
Definition AttributeTransferUtil.h:434
AttributeDetail()
Definition AttributeTransferUtil.h:453
AttributeDetailBase::Ptr copy() override
Definition AttributeTransferUtil.h:514
Deprecated wrapper class with the same interface as HoudiniInterrupter, however it does not derive fr...
Definition Utils.h:209
openvdb::util::NullInterrupter & interrupter()
Return a reference to the base class of the stored interrupter.
Definition Utils.h:227
void runSerial()
Definition AttributeTransferUtil.h:612
void runParallel()
Main calls.
Definition AttributeTransferUtil.h:605
~MeshAttrTransfer()
Definition AttributeTransferUtil.h:544
void operator()(IterRange &range) const
Definition AttributeTransferUtil.h:620
MeshAttrTransfer(AttributeDetailList &pointAttributes, AttributeDetailList &vertexAttributes, AttributeDetailList &primitiveAttributes, const openvdb::Int32Grid &closestPrimGrid, const openvdb::math::Transform &transform, const GU_Detail &meshGdp)
Definition AttributeTransferUtil.h:562
openvdb::tree::IteratorRange< openvdb::Int32Tree::LeafCIter > IterRange
Definition AttributeTransferUtil.h:529
void runSerial()
Definition AttributeTransferUtil.h:773
void runParallel()
Main calls.
Definition AttributeTransferUtil.h:766
void operator()(IterRange &range) const
Definition AttributeTransferUtil.h:781
~PointAttrTransfer()
Definition AttributeTransferUtil.h:725
openvdb::tree::IteratorRange< openvdb::Int32Tree::LeafCIter > IterRange
Definition AttributeTransferUtil.h:716
PointAttrTransfer(AttributeDetailList &pointAttributes, const openvdb::Int32Grid &closestPtnIdxGrid, const GU_Detail &ptGeop)
Definition AttributeTransferUtil.h:740
Definition AttributeTransferUtil.h:1376
TransferPointAttributesOp(const GU_Detail &sourceGeo, GU_Detail &targetGeo, const GridType &indexGrid, std::vector< AttributeCopyBase::Ptr > &pointAttributes, const GA_PrimitiveGroup *surfacePrims=nullptr)
Definition AttributeTransferUtil.h:1393
void operator()(const GA_SplittableRange &) const
Definition AttributeTransferUtil.h:1407
Definition AttributeTransferUtil.h:1151
typename GridType::ValueType IndexT
Definition AttributeTransferUtil.h:1153
void operator()(const GA_SplittableRange &) const
Definition AttributeTransferUtil.h:1189
TransferPrimitiveAttributesOp(const GU_Detail &sourceGeo, GU_Detail &targetGeo, const GridType &indexGrid, AttrCopyPtrVec &primAttributes, AttrCopyPtrVec &vertAttributes)
Definition AttributeTransferUtil.h:1157
typename GridType::ConstAccessor IndexAccT
Definition AttributeTransferUtil.h:1154
std::vector< AttributeCopyBase::Ptr > AttrCopyPtrVec
Definition AttributeTransferUtil.h:1155
Vec3< double > Vec3d
Definition Vec3.h:665
Vec3< int32_t > Vec3i
Definition Vec3.h:662
Vec3< float > Vec3s
Definition Vec3.h:664
int64_t Int64
Definition Types.h:57
uint32_t Index32
Definition Types.h:52
int32_t Int32
Definition Types.h:56
Grid< Int32Tree > Int32Grid
Definition openvdb.h:76
Definition AttributeTransferUtil.h:34
openvdb::Int32 evalAttrDefault< openvdb::Int32 >(const GA_Defaults &defaults, int idx)
Definition AttributeTransferUtil.h:223
openvdb::Vec3i evalAttr< openvdb::Vec3i >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int)
Definition AttributeTransferUtil.h:78
std::vector< AttributeDetailBase::Ptr > AttributeDetailList
Definition AttributeTransferUtil.h:409
ValueType evalAttr(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int idx)
Definition AttributeTransferUtil.h:42
openvdb::Int64 evalAttr< openvdb::Int64 >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int idx)
Definition AttributeTransferUtil.h:69
float evalAttr< float >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int idx)
Definition AttributeTransferUtil.h:51
ValueType evalAttrDefault(const GA_Defaults &defaults, int idx)
Get an OpenVDB-specific value by evaluating GA_Default::get() with appropriate arguments.
Definition AttributeTransferUtil.h:207
AttributeCopyBase::Ptr createAttributeCopier(const GA_Attribute &sourceAttr, GA_Attribute &targetAttr)
Definition AttributeTransferUtil.h:939
openvdb::Int32 evalAttr< openvdb::Int32 >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int idx)
Definition AttributeTransferUtil.h:60
ValueType combine(const ValueType &v0, const ValueType &v1, const ValueType &v2, const openvdb::Vec3d &w)
Combine different value types.
Definition AttributeTransferUtil.h:141
openvdb::Vec3s evalAttrDefault< openvdb::Vec3s >(const GA_Defaults &defaults, int)
Definition AttributeTransferUtil.h:257
void transferPrimitiveAttributes(const GU_Detail &sourceGeo, GU_Detail &targetGeo, GridType &indexGrid, openvdb::util::NullInterrupter &boss, const GA_PrimitiveGroup *primitives=nullptr)
Definition AttributeTransferUtil.h:1492
openvdb::Vec3d evalAttr< openvdb::Vec3d >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int)
Definition AttributeTransferUtil.h:116
GA_Offset findClosestPrimitiveToPoint(const GU_Detail &geo, const std::set< GA_Index > &primitives, const openvdb::Vec3d &p, GA_Offset &vert0, GA_Offset &vert1, GA_Offset &vert2, openvdb::Vec3d &uvw)
Definition AttributeTransferUtil.h:991
openvdb::Vec3d evalAttrDefault< openvdb::Vec3d >(const GA_Defaults &defaults, int)
Definition AttributeTransferUtil.h:275
openvdb::Vec3s evalAttr< openvdb::Vec3s >(const GA_Attribute *atr, const GA_AIFTuple *aif, GA_Offset off, int)
Definition AttributeTransferUtil.h:97
openvdb::Vec3i evalAttrDefault< openvdb::Vec3i >(const GA_Defaults &defaults, int)
Definition AttributeTransferUtil.h:239
float evalAttrDefault< float >(const GA_Defaults &defaults, int)
Definition AttributeTransferUtil.h:215
openvdb::Int64 evalAttrDefault< openvdb::Int64 >(const GA_Defaults &defaults, int idx)
Definition AttributeTransferUtil.h:231
Definition Exceptions.h:13
Utility classes and functions for OpenVDB plugins.
virtual ~AttributeCopyBase()
Definition AttributeTransferUtil.h:813
std::shared_ptr< AttributeCopyBase > Ptr
Definition AttributeTransferUtil.h:811
virtual void copy(GA_Offset, GA_Offset)=0
virtual void copy(GA_Offset &, GA_Offset &, GA_Offset &, GA_Offset, const openvdb::Vec3d &)=0
AttributeCopyBase()
Definition AttributeTransferUtil.h:818
Definition AttributeTransferUtil.h:824
void copy(GA_Offset source, GA_Offset target) override
Definition AttributeTransferUtil.h:834
void copy(GA_Offset &v0, GA_Offset &v1, GA_Offset &v2, GA_Offset target, const openvdb::Vec3d &uvw) override
Definition AttributeTransferUtil.h:843
AttributeCopy(const GA_Attribute &sourceAttr, GA_Attribute &targetAttr)
Definition AttributeTransferUtil.h:826
Definition AttributeTransferUtil.h:893
void copy(GA_Offset source, GA_Offset target) override
Definition AttributeTransferUtil.h:903
const GA_Attribute & mSourceAttr
Definition AttributeTransferUtil.h:928
void copy(GA_Offset &v0, GA_Offset &v1, GA_Offset &v2, GA_Offset target, const openvdb::Vec3d &uvw) override
Definition AttributeTransferUtil.h:910
const GA_AIFSharedStringTuple & mAIF
Definition AttributeTransferUtil.h:930
int mTupleSize
Definition AttributeTransferUtil.h:931
StrAttributeCopy(const GA_Attribute &sourceAttr, GA_Attribute &targetAttr)
Definition AttributeTransferUtil.h:895
GA_Attribute & mTargetAttr
Definition AttributeTransferUtil.h:929