GT_PrimitiveHandle GusdPrimWrapper:: defineForRead( const GusdUSD_StageProxyHandle& stage, const UsdGeomImageable& sourcePrim, const UsdTimeCode& time, const GusdPurposeSet& purposes ) { GT_PrimitiveHandle gtUsdPrimHandle; GusdUSD_ImageableHolder::ScopedLock lock; GusdUSD_ImageableHolder holder( sourcePrim, stage->GetLock() ); lock.Acquire( holder, /*write*/false); UsdGeomImageable sourceImageable = *lock; // Find the function registered for the source prim's type // to define the prim from read and call that function. if(sourcePrim) { USDTypeToDefineFuncMap::const_iterator mapIt = s_usdTypeToFuncMap.find(sourceImageable.GetPrim().GetTypeName()); if(mapIt != s_usdTypeToFuncMap.end()) { gtUsdPrimHandle = mapIt->second(stage,sourcePrim,time,purposes); } } return gtUsdPrimHandle; }
bool MayaPrimWriter::writePrimAttrs(const MDagPath &dagT, const UsdTimeCode &usdTime, UsdGeomImageable &primSchema) { MStatus status; MFnDependencyNode depFn(getDagPath().node()); MFnDependencyNode depFn2(dagT.node()); // optionally also scan a shape's transform if merging transforms if (getArgs().exportVisibility) { bool isVisible = true; // if BOTH shape or xform is animated, then visible bool isAnimated = false; // if either shape or xform is animated, then animated PxrUsdMayaUtil::getPlugValue(depFn, "visibility", &isVisible, &isAnimated); if ( dagT.isValid() ) { bool isVis, isAnim; if (PxrUsdMayaUtil::getPlugValue(depFn2, "visibility", &isVis, &isAnim)){ isVisible = isVisible and isVis; isAnimated = isAnimated or isAnim; } } TfToken const &visibilityTok = (isVisible ? UsdGeomTokens->inherited : UsdGeomTokens->invisible); if (usdTime.IsDefault() != isAnimated ) { if (usdTime.IsDefault()) primSchema.CreateVisibilityAttr(VtValue(visibilityTok), true); else primSchema.CreateVisibilityAttr().Set(visibilityTok, usdTime); } } UsdPrim usdPrim = primSchema.GetPrim(); // There is no Gprim abstraction in this module, so process the few // gprim attrs here. UsdGeomGprim gprim = UsdGeomGprim(usdPrim); if (gprim and usdTime.IsDefault()){ PxrUsdMayaPrimWriterContext* unused = NULL; PxrUsdMayaTranslatorGprim::Write( getDagPath().node(), gprim, unused); } _writeUsdInfo(dagT, usdTime, usdPrim); // Write user-tagged export attributes. Write attributes on the transform // first, and then attributes on the shape node. This means that attribute // name collisions will always be handled by taking the shape node's value // if we're merging transforms and shapes. if (dagT.isValid() and !(dagT == getDagPath())) { PxrUsdMayaWriteUtil::WriteUserExportedAttributes(dagT, usdPrim, usdTime); } PxrUsdMayaWriteUtil::WriteUserExportedAttributes(getDagPath(), usdPrim, usdTime); return true; }
/* static */ UsdGeomPrimvar PxrUsdMayaWriteUtil::GetOrCreatePrimvar( const MPlug& attrPlug, UsdGeomImageable& imageable, const std::string& primvarName, const TfToken& interpolation, const int elementSize, const bool custom, const bool translateMayaDoubleToUsdSinglePrecision) { UsdGeomPrimvar primvar; if (!imageable) { return primvar; } MObject attrObj(attrPlug.attribute()); TfToken primvarNameToken(primvarName); if (primvarNameToken.IsEmpty()) { MGlobal::displayError( TfStringPrintf("Invalid primvar name '%s' for Maya plug '%s'", primvarName.c_str(), attrPlug.name().asChar()).c_str()); return primvar; } // See if the primvar already exists. If so, return it. primvar = imageable.GetPrimvar(primvarNameToken); if (primvar) { return primvar; } const SdfValueTypeName& typeName = PxrUsdMayaWriteUtil::GetUsdTypeName(attrPlug, translateMayaDoubleToUsdSinglePrecision); if (typeName) { primvar = imageable.CreatePrimvar(primvarNameToken, typeName, interpolation, elementSize, custom); } return primvar; }
GT_PrimitiveHandle GusdPrimWrapper:: defineForRead( const UsdGeomImageable& sourcePrim, UsdTimeCode time, GusdPurposeSet purposes ) { GT_PrimitiveHandle gtUsdPrimHandle; // Find the function registered for the source prim's type // to define the prim from read and call that function. if(sourcePrim) { const TfToken& typeName = sourcePrim.GetPrim().GetTypeName(); USDTypeToDefineFuncMap::const_accessor caccessor; if(s_usdTypeToFuncMap.find(caccessor, typeName)) { gtUsdPrimHandle = caccessor->second(sourcePrim,time,purposes); } else { // If no function is registered for the prim's type, try to // find a supported base type. const TfType& baseType = TfType::Find<UsdSchemaBase>(); const TfType& derivedType = baseType.FindDerivedByName(typeName.GetText()); vector<TfType> ancestorTypes; derivedType.GetAllAncestorTypes(&ancestorTypes); for(size_t i=1; i<ancestorTypes.size(); ++i) { const TfType& ancestorType = ancestorTypes[i]; vector<string> typeAliases = baseType.GetAliases(ancestorType); typeAliases.push_back(ancestorType.GetTypeName()); for(auto const& typeAlias : typeAliases) { if(s_usdTypeToFuncMap.find(caccessor, TfToken(typeAlias))) { gtUsdPrimHandle = caccessor->second(sourcePrim,time,purposes); USDTypeToDefineFuncMap::accessor accessor; s_usdTypeToFuncMap.insert(accessor, typeName); accessor->second = caccessor->second; TF_WARN("Type \"%s\" not registered, using base type \"%s\".", typeName.GetText(), typeAlias.c_str()); break; } } if(gtUsdPrimHandle) break; } if(!gtUsdPrimHandle) { // If we couldn't find a function for the prim's type or any // of it's base types, register a function which returns an // empty prim handle. registerPrimDefinitionFuncForRead(typeName, _nullPrimReadFunc); TF_WARN("Couldn't read unsupported USD prim type \"%s\".", typeName.GetText()); } } } return gtUsdPrimHandle; }
GT_PrimitiveHandle GusdXformWrapper:: defineForRead( const UsdGeomImageable& sourcePrim, UsdTimeCode time, GusdPurposeSet purposes ) { return new GusdXformWrapper( UsdGeomXform( sourcePrim.GetPrim() ), time, purposes ); }
GT_PrimitiveHandle GusdScopeWrapper:: defineForRead( const GusdUSD_StageProxyHandle& stage, const UsdGeomImageable& sourcePrim, const UsdTimeCode& time, const GusdPurposeSet& purposes ) { return new GusdScopeWrapper( stage, UsdGeomScope( sourcePrim.GetPrim() ), time, purposes ); }
void GusdPrimWrapper::loadPrimvars( UsdTimeCode time, const GT_RefineParms* rparms, int minUniform, int minPoint, int minVertex, const string& primPath, GT_AttributeListHandle* vertex, GT_AttributeListHandle* point, GT_AttributeListHandle* primitive, GT_AttributeListHandle* constant, const GT_DataArrayHandle& remapIndicies ) const { // Primvars will be loaded if they match a provided pattern. // By default, set the pattern to match only "Cd". Then write // over this pattern if there is one provided in rparms. const char* Cd = "Cd"; UT_String primvarPattern(Cd); if (rparms) { rparms->import("usd:primvarPattern", primvarPattern); } std::vector<UsdGeomPrimvar> authoredPrimvars; bool hasCdPrimvar = false; { UsdGeomImageable prim = getUsdPrimForRead(); UsdGeomPrimvar colorPrimvar = prim.GetPrimvar(GusdTokens->Cd); if (colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValueOpinion()) { hasCdPrimvar = true; } // It's common for "Cd" to be the only primvar to load. // In this case, avoid getting all other authored primvars. if (primvarPattern == Cd) { if (hasCdPrimvar) { authoredPrimvars.push_back(colorPrimvar); } else { // There is no authored "Cd" primvar. // Try to find "displayColor" instead. colorPrimvar = prim.GetPrimvar(UsdGeomTokens->primvarsDisplayColor); if (colorPrimvar && colorPrimvar.GetAttr().HasAuthoredValueOpinion()) { authoredPrimvars.push_back(colorPrimvar); } } } else if (primvarPattern != "") { authoredPrimvars = prim.GetAuthoredPrimvars(); } } // Is it better to sort the attributes and build the attributes all at once. for( const UsdGeomPrimvar &primvar : authoredPrimvars ) { DBG(cerr << "loadPrimvar " << primvar.GetPrimvarName() << "\t" << primvar.GetTypeName() << "\t" << primvar.GetInterpolation() << endl); UT_String name(primvar.GetPrimvarName()); // One special case we always handle here is to change // the name of the USD "displayColor" primvar to "Cd", // as long as there is not already a "Cd" primvar. if (!hasCdPrimvar && primvar.GetName() == UsdGeomTokens->primvarsDisplayColor) { name = Cd; } // If the name of this primvar doesn't // match the primvarPattern, skip it. if (!name.multiMatch(primvarPattern, 1, " ")) { continue; } GT_DataArrayHandle gtData = convertPrimvarData( primvar, time ); if( !gtData ) { TF_WARN( "Failed to convert primvar %s:%s %s.", primPath.c_str(), primvar.GetPrimvarName().GetText(), primvar.GetTypeName().GetAsToken().GetText() ); continue; } // usd vertex primvars are assigned to points if( primvar.GetInterpolation() == UsdGeomTokens->vertex ) { if( gtData->entries() < minPoint ) { TF_WARN( "Not enough values found for primvar: %s:%s. " "%zd values given for %d points.", primPath.c_str(), primvar.GetPrimvarName().GetText(), gtData->entries(), minPoint ); } else { if (remapIndicies) { gtData = new GT_DAIndirect( remapIndicies, gtData ); } if( point ) { *point = (*point)->addAttribute( name.c_str(), gtData, true ); } } } else if( primvar.GetInterpolation() == UsdGeomTokens->faceVarying ) { if( gtData->entries() < minVertex ) { TF_WARN( "Not enough values found for primvar: %s:%s. " "%zd values given for %d verticies.", primPath.c_str(), primvar.GetPrimvarName().GetText(), gtData->entries(), minVertex ); } else if( vertex ) { *vertex = (*vertex)->addAttribute( name.c_str(), gtData, true ); } } else if( primvar.GetInterpolation() == UsdGeomTokens->uniform ) { if( gtData->entries() < minUniform ) { TF_WARN( "Not enough values found for primvar: %s:%s. " "%zd values given for %d faces.", primPath.c_str(), primvar.GetPrimvarName().GetText(), gtData->entries(), minUniform ); } else if( primitive ) { *primitive = (*primitive)->addAttribute( name.c_str(), gtData, true ); } } else if( primvar.GetInterpolation() == UsdGeomTokens->constant ) { if( constant ) { *constant = (*constant)->addAttribute( name.c_str(), gtData, true ); } } } }
void GusdPrimWrapper::updateTransformFromGTPrim( const GfMatrix4d &xform, UsdTimeCode time, bool force ) { UsdGeomImageable usdGeom = getUsdPrimForWrite(); UsdGeomXformable prim( usdGeom ); // Determine if we need to clear previous transformations from a stronger // opinion on the stage before authoring ours. UsdStagePtr stage = usdGeom.GetPrim().GetStage(); UsdEditTarget currEditTarget = stage->GetEditTarget(); // If the edit target does no mapping, it is most likely the session // layer which means it is in the local layer stack and can overlay // any xformOps. if ( !currEditTarget.GetMapFunction().IsNull() && !currEditTarget.GetMapFunction().IsIdentity() ) { bool reset; std::vector<UsdGeomXformOp> xformVec = prim.GetOrderedXformOps(&reset); // The xformOps attribute is static so we only check if we haven't // changed anything yet. In addition nothing needs to be cleared if it // was previously empty. if (m_lastXformSet.IsDefault() && (int)xformVec.size() > 0) { // Load the root layer for temp, stronger opinion changes. stage->GetRootLayer()->SetPermissionToSave(false); stage->SetEditTarget(stage->GetRootLayer()); UsdGeomXformable stagePrim( getUsdPrimForWrite() ); // Clear the xformOps on the stronger layer, so our weaker edit // target (with mapping across a reference) can write out clean, // new transforms. stagePrim.ClearXformOpOrder(); stage->SetEditTarget(currEditTarget); } } if( !prim ) return; // Try to avoid setting the transform when we can. // If force it true, always write the transform (used when writting per frame) bool setKnot = true; if( !force ) { // Has the transform has been set at least once if( !m_lastXformSet.IsDefault() ) { // Is the transform at this frame the same as the last frame if( isClose(xform,m_xformCache) ) { setKnot = false; m_lastXformCompared = time; } else { // If the transform has been held for more than one frame, // set a knot on the last frame if( m_lastXformCompared != m_lastXformSet ) { prim.MakeMatrixXform().Set( m_xformCache, m_lastXformCompared ); } } } else { // If the transform is an identity, don't set it if( isClose(xform,GfMatrix4d( 1.0 ))) { setKnot = false; m_lastXformCompared = time; } else { // If the transform was identity and now isn't, set a knot on the last frame if( !m_lastXformCompared.IsDefault() ) { prim.MakeMatrixXform().Set( GfMatrix4d(1.0), m_lastXformCompared ); } } } } if( setKnot ) { prim.MakeMatrixXform().Set( xform, time ); m_xformCache = xform; m_lastXformSet = time; m_lastXformCompared = time; } }
bool GusdGU_PackedUSD::unpackPrim( GU_Detail& destgdp, UsdGeomImageable prim, const SdfPath& primPath, const UT_Matrix4D& xform, const GT_RefineParms& rparms, bool addPathAttributes ) const { GT_PrimitiveHandle gtPrim = GusdPrimWrapper::defineForRead( prim, m_frame, m_purposes ); if( !gtPrim ) { const TfToken &type = prim.GetPrim().GetTypeName(); if( type != "PxHairman" && type != "PxProcArgs" ) TF_WARN( "Can't convert prim for unpack. %s. Type = %s.", prim.GetPrim().GetPath().GetText(), type.GetText() ); return false; } GusdPrimWrapper* wrapper = UTverify_cast<GusdPrimWrapper*>(gtPrim.get()); if( !wrapper->unpack( destgdp, fileName(), primPath, xform, intrinsicFrame(), #if SYS_VERSION_FULL_INT < 0x10050000 intrinsicViewportLOD(), #else intrinsicViewportLOD( getPrim() ), #endif m_purposes )) { // If the wrapper prim does not do the unpack, do it here. UT_Array<GU_Detail *> details; if( prim.GetPrim().IsInMaster() ) { gtPrim->setPrimitiveTransform( new GT_Transform( &xform, 1 ) ); } GA_Size startIndex = destgdp.getNumPrimitives(); GT_Util::makeGEO(details, gtPrim, &rparms); for (exint i = 0; i < details.entries(); ++i) { copyPrimitiveGroups(*details(i), false); #if SYS_VERSION_FULL_INT < 0x11000000 unpackToDetail(destgdp, details(i), true); #else unpackToDetail(destgdp, details(i), &xform); #endif delete details(i); } if( addPathAttributes ) { // Add usdpath and usdprimpath attributes to unpacked geometry. GA_Size endIndex = destgdp.getNumPrimitives(); const char *path = prim.GetPrim().GetPath().GetString().c_str(); if( endIndex > startIndex ) { GA_RWHandleS primPathAttr( destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PRIMPATH_ATTR, 1 )); GA_RWHandleS pathAttr( destgdp.addStringTuple( GA_ATTRIB_PRIMITIVE, GUSD_PATH_ATTR, 1 )); for( GA_Size i = startIndex; i < endIndex; ++i ) { primPathAttr.set( destgdp.primitiveOffset( i ), 0, path ); pathAttr.set( destgdp.primitiveOffset( i ), 0, fileName().c_str() ); } } } } return true; }
/* static */ GU_PrimPacked* GusdGU_PackedUSD::Build( GU_Detail& detail, const UT_StringHolder& fileName, const SdfPath& primPath, UsdTimeCode frame, const char* lod, GusdPurposeSet purposes, const UsdPrim& prim, const UT_Matrix4D* xform ) { auto packedPrim = GU_PrimPacked::build( detail, k_typeName ); auto impl = UTverify_cast<GusdGU_PackedUSD *>(packedPrim->implementation()); impl->m_fileName = fileName; impl->m_primPath = primPath; impl->m_frame = frame; if( prim && !prim.IsA<UsdGeomBoundable>() ) { UsdGeomImageable geom = UsdGeomImageable(prim); std::vector<UsdGeomPrimvar> authoredPrimvars = geom.GetAuthoredPrimvars(); GT_DataArrayHandle buffer; for( const UsdGeomPrimvar &primvar : authoredPrimvars ) { // XXX This is temporary code, we need to factor the usd read code into GT_Utils.cpp // to avoid duplicates and read for types GfHalf,double,int,string ... GT_DataArrayHandle gtData = GusdPrimWrapper::convertPrimvarData( primvar, frame ); if (!gtData) continue; const UT_String name(primvar.GetPrimvarName()); const GT_Storage gtStorage = gtData->getStorage(); const GT_Size gtTupleSize = gtData->getTupleSize(); GA_Attribute *anAttr = detail.addTuple(GT_Util::getGAStorage(gtStorage), GA_ATTRIB_PRIMITIVE, name, gtTupleSize); if( !anAttr ) { // addTuple could fail for various reasons, like if there's a // non-alphanumeric character in the primvar name. continue; } if( const GA_AIFTuple *aIFTuple = anAttr->getAIFTuple()) { const float* flatArray = gtData->getF32Array( buffer ); aIFTuple->set( anAttr, packedPrim->getMapOffset(), flatArray, gtTupleSize ); } else { //TF_WARN( "Unsupported primvar type: %s, %s, tupleSize = %zd", // GT_String( name ), GTstorage( gtStorage ), gtTupleSize ); } } } if( lod ) { #if SYS_VERSION_FULL_INT < 0x10050000 impl->intrinsicSetViewportLOD( lod ); #else impl->intrinsicSetViewportLOD( packedPrim, lod ); #endif } impl->setPurposes( purposes ); // It seems that Houdini may reuse memory for packed implementations with // out calling the constructor to initialize data. impl->resetCaches(); // If a UsdPrim was passed in, make sure it is used. impl->m_usdPrim = prim; if (xform) { impl->setTransform(*xform); } else { impl->updateTransform(); } return packedPrim; }