From fa2719004ffd03ad53801b0456ddb92eec32d9f0 Mon Sep 17 00:00:00 2001 From: SideFX Date: Tue, 26 Nov 2019 01:00:18 -0500 Subject: [PATCH] Matching to Houdini build 18.5.41. --- src/houdini/custom/USD/GEO_FilePrimUtils.C | 19 +- src/houdini/lib/H_USD/HUSD/CMakeSources.cmake | 2 + src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.C | 385 ++++++++++++++++++ src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.h | 46 +++ src/houdini/lib/H_USD/gusd/GU_PackedUSD.cpp | 76 ++-- src/houdini/lib/H_USD/gusd/GU_USD.h | 10 + src/houdini/lib/H_USD/gusd/agentUtils.cpp | 44 +- src/houdini/lib/H_USD/gusd/agentUtils.h | 2 +- src/houdini/lib/H_USD/gusd/meshWrapper.cpp | 3 +- src/houdini/lib/H_USD/gusd/primWrapper.cpp | 4 +- 10 files changed, 532 insertions(+), 59 deletions(-) create mode 100644 src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.C create mode 100644 src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.h diff --git a/src/houdini/custom/USD/GEO_FilePrimUtils.C b/src/houdini/custom/USD/GEO_FilePrimUtils.C index 1c97faf3..4488598d 100644 --- a/src/houdini/custom/USD/GEO_FilePrimUtils.C +++ b/src/houdini/custom/USD/GEO_FilePrimUtils.C @@ -302,7 +302,12 @@ initSubsets(GEO_FilePrim &fileprim, prop = subprim.addProperty(UsdGeomTokens->indices, SdfValueTypeNames->IntArray, new GEO_FilePropAttribSource(faceset->extractMembers())); - prop->setValueIsDefault(true); + // Use the topology handling value to decide if geometry subset + // membership should be time varying or not. There is a Hydra bug + // that requires geom subsets be time varying if the mesh topology + // is time varying. + prop->setValueIsDefault( + options.myTopologyHandling != GEO_USD_TOPOLOGY_ANIMATED); } } @@ -321,7 +326,8 @@ static void initPartition(GEO_FilePrim &fileprim, GEO_FilePrimMap &fileprimmap, const GT_DataArrayHandle &hou_attr, - const std::string &attr_name) + const std::string &attr_name, + const GEO_ImportOptions &options) { struct Partition { UT_StringHolder mySubsetName; @@ -412,7 +418,12 @@ initPartition(GEO_FilePrim &fileprim, prop = subprim.addProperty(UsdGeomTokens->indices, SdfValueTypeNames->IntArray, new GEO_FilePropConstantArraySource(partition.myIndices)); - prop->setValueIsDefault(true); + // Use the topology handling value to decide if geometry subset + // membership should be time varying or not. There is a Hydra bug + // that requires geom subsets be time varying if the mesh topology + // is time varying. + prop->setValueIsDefault( + options.myTopologyHandling != GEO_USD_TOPOLOGY_ANIMATED); prop = subprim.addProperty(UsdGeomTokens->familyName, SdfValueTypeNames->Token, new GEO_FilePropConstantSource(attr_name_token)); @@ -1629,7 +1640,7 @@ initExtraAttribs(GEO_FilePrim &fileprim, if (!hou_attr->hasArrayEntries()) initPartition(fileprim, fileprimmap, - hou_attr, attr_name.toStdString()); + hou_attr, attr_name.toStdString(), options); } else if (options.multiMatch(attr_name)) { diff --git a/src/houdini/lib/H_USD/HUSD/CMakeSources.cmake b/src/houdini/lib/H_USD/HUSD/CMakeSources.cmake index ea54c21f..1e1ed5f2 100644 --- a/src/houdini/lib/H_USD/HUSD/CMakeSources.cmake +++ b/src/houdini/lib/H_USD/HUSD/CMakeSources.cmake @@ -71,6 +71,7 @@ set( husd_sources HUSD_SetMetadata.C HUSD_SetRelationships.C HUSD_ShaderTranslator.C + HUSD_Skeleton.C HUSD_SpecHandle.C HUSD_Stitch.C HUSD_TimeCode.C @@ -172,6 +173,7 @@ set( husd_hdk_headers HUSD_SetMetadata.h HUSD_SetRelationships.h HUSD_ShaderTranslator.h + HUSD_Skeleton.h HUSD_SpecHandle.h HUSD_Stitch.h HUSD_TimeCode.h diff --git a/src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.C b/src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.C new file mode 100644 index 00000000..386f08fd --- /dev/null +++ b/src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.C @@ -0,0 +1,385 @@ +/* + * PROPRIETARY INFORMATION. This software is proprietary to + * Side Effects Software Inc., and is not to be reproduced, + * transmitted, or disclosed in any way without written permission. +*/ + +#include "HUSD_Skeleton.h" + +#include "HUSD_ErrorScope.h" +#include "HUSD_TimeCode.h" +#include "XUSD_Data.h" +#include "XUSD_Utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +static bool +husdFindSkelBindings(const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath, + UsdSkelCache &skelcache, + std::vector &bindings) +{ + XUSD_ConstDataPtr data(readlock.data()); + + if (!data || !data->isStageValid()) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, "Invalid stage."); + return false; + } + + SdfPath sdfpath = HUSDgetSdfPath(skelrootpath); + UsdPrim prim(data->stage()->GetPrimAtPath(sdfpath)); + if (!prim) + { + HUSD_ErrorScope::addError(HUSD_ERR_CANT_FIND_PRIM, + skelrootpath.c_str()); + return false; + } + + UsdSkelRoot skelroot(prim); + if (!skelroot) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Primitive is not a SkelRoot."); + return false; + } + + skelcache.Populate(skelroot); + + bindings.clear(); + skelcache.ComputeSkelBindings(skelroot, &bindings); + + if (bindings.empty()) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Could not find any skeleton bindings."); + return false; + } + + return true; +} + +bool +HUSDimportSkinnedGeometry(GU_Detail &gdp, const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath, + const UT_StringHolder &shapeattrib) +{ + UsdSkelCache skelcache; + std::vector bindings; + if (!husdFindSkelBindings(readlock, skelrootpath, skelcache, bindings)) + return false; + + GT_RefineParms refine_parms; + refine_parms.set(GUSD_REFINE_ADDXFORMATTRIB, false); + + // Skip creating the usdpath attribute, which is random for stages from + // LOPs. This could be revisited if importing directly from a file is + // allowed. + refine_parms.set(GUSD_REFINE_ADDPATHATTRIB, false); + + for (const UsdSkelBinding &binding : bindings) + { + if (!GusdCoalesceAgentShapes( + gdp, binding, UsdTimeCode::EarliestTime(), /*lod*/ nullptr, + GusdPurposeSet(GUSD_PURPOSE_DEFAULT | GUSD_PURPOSE_PROXY), + UT_ERROR_WARNING, &refine_parms)) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Failed to load shapes."); + return false; + } + } + + // Convert to polysoups for reduced memory usage. + GEO_PolySoupParms psoup_parms; + gdp.polySoup(psoup_parms, &gdp); + + // Set up the shape name attribute, computed using the paths relative to + // the SkelRoot prim. + if (!GU_AttributeSwap::swapAttribute(&gdp, GU_AttributeSwap::METHOD_COPY, + GU_AttributeSwap::TYPEINFO_USE_SOURCE, + GA_ATTRIB_PRIMITIVE, + GUSD_PRIMPATH_ATTR, shapeattrib)) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Failed to create shape name attribute."); + return false; + } + + GA_RWHandleS shapeattrib_h( + gdp.findStringTuple(GA_ATTRIB_PRIMITIVE, shapeattrib, 1)); + UT_ASSERT(shapeattrib_h.isValid()); + + UT_StringArray strings; + UT_IntArray handles; + shapeattrib_h->extractStrings(strings, handles); + + const SdfPath root_path = HUSDgetSdfPath(skelrootpath); + for (exint i = 0, n = strings.size(); i < n; ++i) + { + SdfPath prim_path = HUSDgetSdfPath(strings[i]); + prim_path.MakeRelativePath(root_path); + + shapeattrib_h->replaceString( + GA_StringIndexType(handles[i]), + prim_path.MakeRelativePath(root_path).GetString()); + } + + // Bump all data ids since we've created new geometry. + gdp.bumpAllDataIds(); + + return true; +} + +bool +HUSDimportSkeleton(GU_Detail &gdp, const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath) +{ + UsdSkelCache skelcache; + std::vector bindings; + if (!husdFindSkelBindings(readlock, skelrootpath, skelcache, bindings)) + return false; + + GA_RWHandleS name_attrib = + gdp.addStringTuple(GA_ATTRIB_POINT, GA_Names::name, 1); + + GA_RWHandleM3D xform_attrib = + gdp.addFloatTuple(GA_ATTRIB_POINT, GA_Names::transform, 9); + xform_attrib->setTypeInfo(GA_TypeInfo::GA_TYPE_TRANSFORM); + + // TODO - create attributes to identify the source path of the skeleton. + + for (const UsdSkelBinding &binding : bindings) + { + const UsdSkelSkeleton &skel = binding.GetSkeleton(); + UsdSkelSkeletonQuery skelquery = skelcache.GetSkelQuery(skel); + if (!skelquery.IsValid()) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Invalid skeleton query."); + return false; + } + + const UsdSkelTopology &topology = skelquery.GetTopology(); + + VtTokenArray joints; + if (!skel.GetJointsAttr().Get(&joints)) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "'joints' attribute is invalid."); + return false; + } + + // Prefer the jointNames attribute if it was authored, since it + // provides nicer unique names than the full paths. + VtTokenArray joint_names; + if (skel.GetJointNamesAttr().Get(&joint_names)) + { + if (joint_names.size() != joints.size()) + { + HUSD_ErrorScope::addError( + HUSD_ERR_STRING, "'jointNames' attribute does not match " + "the size of the 'joints' attribute."); + return false; + } + } + else + joint_names = joints; + + // Create a point for each joint, and connect each point to its parent + // with a polygon. + GA_Offset start_ptoff = gdp.appendPointBlock(topology.GetNumJoints()); + UT_Array poly_ptnums; + for (exint i = 0, n = topology.GetNumJoints(); i < n; ++i) + { + GA_Offset ptoff = start_ptoff + i; + name_attrib.set(ptoff, + GusdUSD_Utils::TokenToStringHolder(joint_names[i])); + + if (!topology.IsRoot(i)) + { + int parent = topology.GetParent(i); + poly_ptnums.append(parent); + poly_ptnums.append(i); + } + } + + GEO_PolyCounts poly_sizes; + poly_sizes.append(2, poly_ptnums.size() / 2); + GEO_PrimPoly::buildBlock(&gdp, start_ptoff, topology.GetNumJoints(), + poly_sizes, poly_ptnums.data(), + /* closed */ false); + } + + // Bump all data ids since new geometry was generated. + gdp.bumpAllDataIds(); + + return true; +} + +static bool +husdComputeWorldTransforms(const UsdSkelSkeleton &skel, + const UsdSkelTopology &topology, + const UsdTimeCode &timecode, + const VtMatrix4dArray &local_xforms, + VtMatrix4dArray &world_xforms) +{ + const GfMatrix4d root_xform = skel.ComputeLocalToWorldTransform(timecode); + + world_xforms.resize(local_xforms.size()); + if (!UsdSkelConcatJointTransforms(topology, local_xforms, world_xforms, + &root_xform)) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Failed to compute world transforms."); + return false; + } + + return true; +} + +bool +HUSDimportSkeletonPose(GU_Detail &gdp, const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath, + HUSD_SkeletonPoseType pose_type, fpreal time) +{ + UsdSkelCache skelcache; + std::vector bindings; + if (!husdFindSkelBindings(readlock, skelrootpath, skelcache, bindings)) + return false; + + GA_RWHandleM3D xform_attrib = + gdp.findFloatTuple(GA_ATTRIB_POINT, GA_Names::transform, 9); + UT_ASSERT(xform_attrib.isValid()); + + GA_Index ptidx = 0; + for (const UsdSkelBinding &binding : bindings) + { + const UsdSkelSkeleton &skel = binding.GetSkeleton(); + UsdSkelSkeletonQuery skelquery = skelcache.GetSkelQuery(skel); + if (!skelquery.IsValid()) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Invalid skeleton query."); + return false; + } + + const UsdSkelTopology &topology = skelquery.GetTopology(); + + VtMatrix4dArray world_xforms; + switch (pose_type) + { + case HUSD_SkeletonPoseType::Animation: + { + const UsdSkelAnimQuery &animquery = skelquery.GetAnimQuery(); + if (!animquery.IsValid()) + { + HUSD_ErrorScope::addError(HUSD_ERR_STRING, + "Invalid animation query."); + return false; + } + + VtMatrix4dArray local_xforms; + const UsdTimeCode timecode = + HUSDgetUsdTimeCode(HUSD_TimeCode(time, HUSD_TimeCode::TIME)); + if (!animquery.ComputeJointLocalTransforms(&local_xforms, timecode)) + { + HUSD_ErrorScope::addError( + HUSD_ERR_STRING, "Failed to compute local transforms."); + return false; + } + + if (!husdComputeWorldTransforms(skel, topology, timecode, + local_xforms, world_xforms)) + { + return false; + } + + // TODO - output time range detail attribute. + } + break; + + case HUSD_SkeletonPoseType::BindPose: + { + if (!skel.GetBindTransformsAttr().Get(&world_xforms)) + { + HUSD_ErrorScope::addError( + HUSD_ERR_STRING, "'bindTransforms' attribute is invalid"); + return false; + } + else if (world_xforms.size() != topology.GetNumJoints()) + { + HUSD_ErrorScope::addError( + HUSD_ERR_STRING, + "'bindTransforms' attribute does not match " + "the size of the 'joints' attribute."); + return false; + } + } + break; + + case HUSD_SkeletonPoseType::RestPose: + { + VtMatrix4dArray local_xforms; + if (!skel.GetRestTransformsAttr().Get(&local_xforms)) + { + HUSD_ErrorScope::addError( + HUSD_ERR_STRING, "'restTransforms' attribute is invalid"); + return false; + } + else if (local_xforms.size() != topology.GetNumJoints()) + { + HUSD_ErrorScope::addError( + HUSD_ERR_STRING, + "'restTransforms' attribute does not match " + "the size of the 'joints' attribute."); + return false; + } + + const UsdTimeCode timecode = + HUSDgetUsdTimeCode(HUSD_TimeCode(time, HUSD_TimeCode::TIME)); + if (!husdComputeWorldTransforms(skel, topology, timecode, + local_xforms, world_xforms)) + { + return false; + } + } + break; + } + + UT_ASSERT(ptidx + topology.GetNumJoints() <= gdp.getNumPoints()); + UT_ASSERT(world_xforms.size() == topology.GetNumJoints()); + for (exint i = 0, n = topology.GetNumJoints(); i < n; ++i, ++ptidx) + { + GA_Offset ptoff = gdp.pointOffset(ptidx); + + const UT_Matrix4D &xform = GusdUT_Gf::Cast(world_xforms[i]); + xform_attrib.set(ptoff, UT_Matrix3D(xform)); + + UT_Vector3D t; + xform.getTranslates(t); + gdp.setPos3(ptoff, t); + } + } + + gdp.getP()->bumpDataId(); + xform_attrib.bumpDataId(); + + return true; +} diff --git a/src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.h b/src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.h new file mode 100644 index 00000000..61fa1a18 --- /dev/null +++ b/src/houdini/lib/H_USD/HUSD/HUSD_Skeleton.h @@ -0,0 +1,46 @@ +/* + * PROPRIETARY INFORMATION. This software is proprietary to + * Side Effects Software Inc., and is not to be reproduced, + * transmitted, or disclosed in any way without written permission. +*/ + +#ifndef __HUSD_Skeleton_h__ +#define __HUSD_Skeleton_h__ + +#include "HUSD_API.h" + +#include + +class GU_Detail; +class HUSD_AutoReadLock; +class UT_StringHolder; +class UT_StringRef; + +/// Imports all skinnable primitives underneath the provided SkelRoot prim. +HUSD_API bool +HUSDimportSkinnedGeometry(GU_Detail &gdp, const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath, + const UT_StringHolder &shapeattrib); + +/// Imports all Skeleton primitives underneath the provided SkelRoot prim. +/// A point is created for each joint, and joints are connected to their +/// parents by polyline primitives. +/// Use HUSDimportSkeletonPose() to set the skeleton's transforms. +HUSD_API bool +HUSDimportSkeleton(GU_Detail &gdp, const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath); + +enum class HUSD_SkeletonPoseType +{ + Animation, + BindPose, + RestPose +}; + +/// Updates the pose for the skeleton geometry created by HUSDimportSkeleton(). +HUSD_API bool +HUSDimportSkeletonPose(GU_Detail &gdp, const HUSD_AutoReadLock &readlock, + const UT_StringRef &skelrootpath, + HUSD_SkeletonPoseType pose_type, fpreal time); + +#endif diff --git a/src/houdini/lib/H_USD/gusd/GU_PackedUSD.cpp b/src/houdini/lib/H_USD/gusd/GU_PackedUSD.cpp index f85e7407..d8df61e6 100644 --- a/src/houdini/lib/H_USD/gusd/GU_PackedUSD.cpp +++ b/src/houdini/lib/H_USD/gusd/GU_PackedUSD.cpp @@ -308,8 +308,9 @@ GusdGU_PackedUSD::Build( GusdPurposeSet purposes, const UT_Matrix4D* xform ) { - // TODO: Should we pull the identifier from the root layer as the file name? - return GusdGU_PackedUSD::Build(detail, /*fileName*/ UT_StringHolder(), + const std::string &filename = + prim.GetStage()->GetRootLayer()->GetIdentifier(); + return GusdGU_PackedUSD::Build(detail, filename, prim.GetPath(), frame, lod, purposes, prim, xform); } @@ -1016,7 +1017,7 @@ GusdGU_PackedUSD::unpackPrim( GT_Util::makeGEO(details, gtPrim, &rparms); UT_String non_transforming_primvars; - rparms.import("usd:nonTransformingPrimvarPattern", + rparms.import(GUSD_REFINE_NONTRANSFORMINGPATTERN, non_transforming_primvars); Gusd_MarkNonTransformingAttribs(details, non_transforming_primvars); @@ -1039,46 +1040,55 @@ GusdGU_PackedUSD::unpackPrim( delete details(i); } - if( GT_RefineParms::getBool(&rparms, "usd:addPathAttributes", true) ) { - // Add usdpath and usdprimpath attributes to unpacked geometry. + // Add usdpath and usdprimpath attributes to unpacked geometry. + if (GT_RefineParms::getBool(&rparms, GUSD_REFINE_ADDPATHATTRIB, true) && + primmarker.getBegin() != primmarker.getEnd()) + { + GA_RWHandleS pathAttr( + destgdp.addStringTuple(GA_ATTRIB_PRIMITIVE, GUSD_PATH_ATTR, 1)); + + const GA_Range range = primmarker.getRange(); - if (primmarker.getBegin() != primmarker.getEnd()) + if (const GA_AIFSharedStringTuple *tuple = + pathAttr.getAttribute()->getAIFSharedStringTuple()) { - GA_RWHandleS primPathAttr( - destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PRIMPATH_ATTR, 1 )); - GA_RWHandleS pathAttr( - destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PATH_ATTR, 1 )); - - const GA_Range range = primmarker.getRange(); - - if (const GA_AIFSharedStringTuple* tuple = - primPathAttr.getAttribute()->getAIFSharedStringTuple()) { - tuple->setString(primPathAttr.getAttribute(), range, - prim.GetPath().GetText(), 0); - } - if (const GA_AIFSharedStringTuple* tuple = - pathAttr.getAttribute()->getAIFSharedStringTuple()) { - tuple->setString(pathAttr.getAttribute(), range, - fileName().c_str(), 0); - } + tuple->setString(pathAttr.getAttribute(), range, + fileName().c_str(), 0); } + } + + if (GT_RefineParms::getBool(&rparms, GUSD_REFINE_ADDPRIMPATHATTRIB, + true) && + primmarker.getBegin() != primmarker.getEnd()) + { + GA_RWHandleS primPathAttr(destgdp.addStringTuple( + GA_ATTRIB_PRIMITIVE, GUSD_PRIMPATH_ATTR, 1)); + + const GA_Range range = primmarker.getRange(); - // Add usdconfigconstantattribs attribute to unpacked geometry. - if (constant_attribs_pattern.isstring()) + if (const GA_AIFSharedStringTuple *tuple = + primPathAttr.getAttribute()->getAIFSharedStringTuple()) { - GA_RWHandleS constant_attribs = destgdp.addStringTuple( - GA_ATTRIB_DETAIL, theConstantAttribsName.asHolder(), 1); - constant_attribs.set(GA_DETAIL_OFFSET, constant_attribs_pattern); + tuple->setString(primPathAttr.getAttribute(), range, + prim.GetPath().GetText(), 0); } } - if (GT_RefineParms::getBool(&rparms, "usd:addXformAttribute", true) && + // Add usdconfigconstantattribs attribute to unpacked geometry. + if (constant_attribs_pattern.isstring()) + { + GA_RWHandleS constant_attribs = destgdp.addStringTuple( + GA_ATTRIB_DETAIL, theConstantAttribsName.asHolder(), 1); + constant_attribs.set(GA_DETAIL_OFFSET, constant_attribs_pattern); + } + + if (GT_RefineParms::getBool(&rparms, GUSD_REFINE_ADDXFORMATTRIB, true) && ptmarker.getBegin() != ptmarker.getEnd()) { Gusd_RecordXformAttrib(destgdp, ptmarker.getRange(), xform); } - if (GT_RefineParms::getBool(&rparms, "usd:addVisibilityAttribute", + if (GT_RefineParms::getBool(&rparms, GUSD_REFINE_ADDVISIBILITYATTRIB, true) && primmarker.getBegin() != primmarker.getEnd()) { @@ -1128,11 +1138,11 @@ GusdGU_PackedUSD::unpackGeometry( // Need to manually force polysoup to be turned off. rparms.setAllowPolySoup( false ); - rparms.set("usd:nonTransformingPrimvarPattern", + rparms.set(GUSD_REFINE_NONTRANSFORMINGPATTERN, nonTransformingPrimvarPattern); - rparms.set("usd:translateSTtoUV", translateSTtoUV); + rparms.set(GUSD_REFINE_TRANSLATESTTOUV, translateSTtoUV); if (primvarPattern) { - rparms.set("usd:primvarPattern", primvarPattern); + rparms.set(GUSD_REFINE_PRIMVARPATTERN, primvarPattern); } DBG( cerr << "GusdGU_PackedUSD::unpackGeometry: " << usdPrim.GetTypeName() << ", " << usdPrim.GetPath() << endl; ) diff --git a/src/houdini/lib/H_USD/gusd/GU_USD.h b/src/houdini/lib/H_USD/gusd/GU_USD.h index fee05ac1..a758d6ec 100644 --- a/src/houdini/lib/H_USD/gusd/GU_USD.h +++ b/src/houdini/lib/H_USD/gusd/GU_USD.h @@ -66,6 +66,16 @@ PXR_NAMESPACE_OPEN_SCOPE #define GUSD_WRITESTATICGEO_ATTR "usdwritestaticgeo" /** @} */ +/** USD-related options for GT_RefineParms. + @{ */ +#define GUSD_REFINE_ADDPATHATTRIB "usd:addPathAttribute" +#define GUSD_REFINE_ADDPRIMPATHATTRIB "usd:addPrimPathAttribute" +#define GUSD_REFINE_ADDVISIBILITYATTRIB "usd:addVisibilityAttribute" +#define GUSD_REFINE_ADDXFORMATTRIB "usd:addXformAttribute" +#define GUSD_REFINE_NONTRANSFORMINGPATTERN "usd:nonTransformingPrimvarPattern" +#define GUSD_REFINE_PRIMVARPATTERN "usd:primvarPattern" +#define GUSD_REFINE_TRANSLATESTTOUV "usd:translateSTtoUV" +/** @} */ /** Set of helpers for working with ranges of prims/points, etc.*/ class GUSD_API GusdGU_USD diff --git a/src/houdini/lib/H_USD/gusd/agentUtils.cpp b/src/houdini/lib/H_USD/gusd/agentUtils.cpp index 99ec300a..d547f0cd 100644 --- a/src/houdini/lib/H_USD/gusd/agentUtils.cpp +++ b/src/houdini/lib/H_USD/gusd/agentUtils.cpp @@ -47,10 +47,12 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -59,8 +61,10 @@ PXR_NAMESPACE_OPEN_SCOPE // TODO: Encoding of namespaced properties is subject to change in // future releases. -#define GUSD_SKEL_JOINTINDICES_ATTR "skel_jointIndices"_UTsh -#define GUSD_SKEL_JOINTWEIGHTS_ATTR "skel_jointWeights"_UTsh +static const UT_StringHolder GUSD_SKEL_JOINTINDICES_ATTR = + UT_VarEncode::encodeAttrib("skel:jointIndices"_UTsh); +static const UT_StringHolder GUSD_SKEL_JOINTWEIGHTS_ATTR = + UT_VarEncode::encodeAttrib("skel:jointWeights"_UTsh); namespace { @@ -286,6 +290,7 @@ Gusd_CreateCaptureAttributes( // imported onto the detail. We could query them from USD ourselves, // but then we would need to worry about things like winding order, etc. + const GA_Offset constant_offset = gd.primitiveOffset(0); GA_ROHandleI jointIndicesHnd(&gd, GA_ATTRIB_POINT, GUSD_SKEL_JOINTINDICES_ATTR); @@ -294,8 +299,11 @@ Gusd_CreateCaptureAttributes( if (jointIndicesHnd.isInvalid()) { // If the influences were stored with 'constant' interpolation, - // they may be defined as a detail attrib instead. - jointIndicesHnd.bind(&gd, GA_ATTRIB_DETAIL, + // they may be defined as a primitive attrib instead + // (GusdPrimWrapper::convertPrimvarData() promotes constant primvars to + // primitive attributes to ensure that the results are consistent when + // merging) + jointIndicesHnd.bind(&gd, GA_ATTRIB_PRIMITIVE, GUSD_SKEL_JOINTINDICES_ATTR); if (jointIndicesHnd.isValid()) { perPointJointIndices = false; @@ -312,7 +320,7 @@ Gusd_CreateCaptureAttributes( // If the influences were stored with 'constant' interpolation, // they may be defined as a detail attrib instead. - jointWeightsHnd.bind(&gd, GA_ATTRIB_DETAIL, + jointWeightsHnd.bind(&gd, GA_ATTRIB_PRIMITIVE, GUSD_SKEL_JOINTWEIGHTS_ATTR); if (jointWeightsHnd.isValid()) { perPointJointWeights = false; @@ -390,10 +398,10 @@ Gusd_CreateCaptureAttributes( for ( ; o < end; ++o) { if (jointIndicesTuple->get(jointIndicesHnd.getAttribute(), - perPointJointIndices ? o : GA_Offset(0), + perPointJointIndices ? o : constant_offset, indices.data(), tupleSize) && jointWeightsTuple->get(jointWeightsHnd.getAttribute(), - perPointJointWeights ? o : GA_Offset(0), + perPointJointWeights ? o : constant_offset, weights.data(), tupleSize)) { // Joint influences are required to be stored @@ -682,20 +690,20 @@ namespace { // TODO: This is the bottle neck in import. bool -_CoalesceShapes(GEO_Detail& coalescedGd, - const UT_Array& details) +_CoalesceShapes(GU_Detail& coalescedGd, + UT_Array& details) { UT_AutoInterrupt task("Coalesce shapes"); - for (const auto& gdh : details) { - if (task.wasInterrupted()) - return false; - - const GU_DetailHandleAutoReadLock gdl(gdh); - if (const GU_Detail* gdp = gdl.getGdp()) { - coalescedGd.merge(*gdp); - } + UT_Array gdps; + for (GU_DetailHandle &gdh : details) + { + if (gdh.isValid()) + gdps.append(gdh.gdpNC()); } + + GUmatchAttributesAndMerge(coalescedGd, gdps); + return !task.wasInterrupted(); } @@ -703,7 +711,7 @@ _CoalesceShapes(GEO_Detail& coalescedGd, bool -GusdCoalesceAgentShapes(GEO_Detail& gd, +GusdCoalesceAgentShapes(GU_Detail& gd, const UsdSkelBinding& binding, UsdTimeCode time, const char* lod, diff --git a/src/houdini/lib/H_USD/gusd/agentUtils.h b/src/houdini/lib/H_USD/gusd/agentUtils.h index 04ac00c4..8d1d4ec6 100644 --- a/src/houdini/lib/H_USD/gusd/agentUtils.h +++ b/src/houdini/lib/H_USD/gusd/agentUtils.h @@ -92,7 +92,7 @@ GusdCreateAgentShapeLib(const UsdSkelBinding& binding, /// skipped. Otherwise, creation of the coalesced detail fails if errors are /// produced processing any shapes. GUSD_API bool -GusdCoalesceAgentShapes(GEO_Detail& gd, +GusdCoalesceAgentShapes(GU_Detail& gd, const UsdSkelBinding& binding, UsdTimeCode time=UsdTimeCode::EarliestTime(), const char* lod=nullptr, diff --git a/src/houdini/lib/H_USD/gusd/meshWrapper.cpp b/src/houdini/lib/H_USD/gusd/meshWrapper.cpp index 5d802a35..9bed87f2 100644 --- a/src/houdini/lib/H_USD/gusd/meshWrapper.cpp +++ b/src/houdini/lib/H_USD/gusd/meshWrapper.cpp @@ -25,6 +25,7 @@ #include "context.h" #include "GT_VtArray.h" +#include "GU_USD.h" #include "tokens.h" #include "USD_XformCache.h" #include "UT_Gf.h" @@ -300,7 +301,7 @@ _convertGeomSubsetsToPartitionAttribs(const UsdGeomImageable &mesh, UT_String attribPatternStr; if (parms) - parms->import("usd:primvarPattern", attribPatternStr); + parms->import(GUSD_REFINE_PRIMVARPATTERN, attribPatternStr); UT_StringMMPattern attribPattern; if (attribPatternStr) diff --git a/src/houdini/lib/H_USD/gusd/primWrapper.cpp b/src/houdini/lib/H_USD/gusd/primWrapper.cpp index 441a0867..6653dbd0 100644 --- a/src/houdini/lib/H_USD/gusd/primWrapper.cpp +++ b/src/houdini/lib/H_USD/gusd/primWrapper.cpp @@ -1157,7 +1157,7 @@ GusdPrimWrapper::loadPrimvars( UT_String primvarPatternStr(Cd); if (rparms) { - rparms->import("usd:primvarPattern", primvarPatternStr); + rparms->import(GUSD_REFINE_PRIMVARPATTERN, primvarPatternStr); } UT_StringMMPattern primvarPattern; @@ -1171,7 +1171,7 @@ GusdPrimWrapper::loadPrimvars( const TfToken stName = UsdUtilsGetPrimaryUVSetName(); bool translateSTtoUV = true; if (rparms) { - rparms->import("usd:translateSTtoUV", translateSTtoUV); + rparms->import(GUSD_REFINE_TRANSLATESTTOUV, translateSTtoUV); } {