/* static */ bool GusdWriteCtrlFlags::getBoolAttr( const GT_PrimitiveHandle& prim, const char *attrName, bool defaultValue ) { if( prim ) { GT_DataArrayHandle data; if( prim->getPrimitiveType() == GT_GEO_PACKED ) { GT_AttributeListHandle instAttrs = UTverify_cast<const GT_GEOPrimPacked*>(prim.get())->getInstanceAttributes(); if( instAttrs ) { data = instAttrs->get( attrName ); } } if( !data ) { GT_Owner own; data = prim->findAttribute( attrName, own, 0 ); } if( data ) { return bool( data->getI32(0) ); } } return defaultValue; }
bool GusdPrimWrapper::updatePrimvarFromGTPrim( const GT_AttributeListHandle& gtAttrs, const GusdGT_AttrFilter& primvarFilter, const TfToken& interpolation, UsdTimeCode time ) { UsdGeomImageable prim( getUsdPrimForWrite() ); const GT_AttributeMapHandle attrMapHandle = gtAttrs->getMap(); for(GT_AttributeMap::const_names_iterator mapIt=attrMapHandle->begin(); !mapIt.atEnd(); ++mapIt) { if(!primvarFilter.matches(mapIt.name())) continue; const int attrIndex = attrMapHandle->get(mapIt.name()); const GT_Owner owner = attrMapHandle->getOriginalOwner(attrIndex); GT_DataArrayHandle attrData = gtAttrs->get(attrIndex); TfToken name( mapIt.name() ); updatePrimvarFromGTPrim( TfToken( name ), owner, interpolation, time, attrData ); } return true; }
bool GusdPrimWrapper::updatePrimvarFromGTPrim( const GT_AttributeListHandle& gtAttrs, const GusdGT_AttrFilter& primvarFilter, const TfToken& interpolation, UsdTimeCode time ) { UsdGeomImageable prim( getUsdPrim() ); const GT_AttributeMapHandle attrMapHandle = gtAttrs->getMap(); for(GT_AttributeMap::const_names_iterator mapIt=attrMapHandle->begin(); !mapIt.atEnd(); ++mapIt) { #if SYS_VERSION_FULL_INT < 0x11000000 string attrname = mapIt.name(); #else string attrname = mapIt->first.toStdString(); #endif if(!primvarFilter.matches(attrname)) continue; const int attrIndex = attrMapHandle->get(attrname); const GT_Owner owner = attrMapHandle->getOriginalOwner(attrIndex); GT_DataArrayHandle attrData = gtAttrs->get(attrIndex); #if SYS_VERSION_FULL_INT >= 0x11050000 // Decode Houdini geometry attribute names to get back the original // USD primvar name. This allows round tripping of namespaced // primvars from USD -> Houdini -> USD. UT_StringHolder name = UT_VarEncode::decode(attrname); #else UT_StringHolder name = attrname; #endif updatePrimvarFromGTPrim( TfToken( name.toStdString() ), owner, interpolation, time, attrData ); } return true; }
void GusdRefinerCollector::finish( GusdRefiner& refiner ) { // If we are building a point instancer, as packed prims are added they // have been collected into m_instancePrims sorted by "srcPrimPath". // Build a GT_PointPrimMesh for each entry in this map. for( auto const & instancerMapIt : m_instancePrims ) { const SdfPath &instancerPrimPath = instancerMapIt.first; const vector<InstPrimEntry>& primArray = instancerMapIt.second; size_t nprims = primArray.size(); DBG( cerr << "Create point instancers for \"" << instancerPrimPath << "\" with " << nprims << " entries" << endl); GT_AttributeListHandle pAttrs = new GT_AttributeList( new GT_AttributeMap() ); // Allocate storage for all the attributes we want to copy. // Assume all entries in the primArray have the same set of attributes. // (They all came from the same detail). const GT_PrimitiveHandle& prim = primArray[0].prim; auto instPtAttrs = prim->getPointAttributes(); GT_Real32Array* pivotArray = nullptr; if( instPtAttrs ) { for( size_t j = 0; j < instPtAttrs->entries(); ++j ) { // Filter attributes that begin with an underscore const char *n = instPtAttrs->getName(j); if( !n || strlen( n ) < 1 || n[0] == '_' ) { continue; } GT_Storage storage = instPtAttrs->get( j )->getStorage(); GT_Size tupleSize = instPtAttrs->get( j )->getTupleSize(); GT_Type typeInfo = instPtAttrs->get( j )->getTypeInfo(); pAttrs = pAttrs->addAttribute( n, newDataArray( storage, nprims, tupleSize, typeInfo ), true ); } } bool hasInstanceIndices = false; if(auto packedUSD = dynamic_cast<const GusdGT_PackedUSD*>( prim.get() )) { if (packedUSD->getInstanceIndex() >= 0) { hasInstanceIndices = true; } } if( auto instUniAttrs = prim->getUniformAttributes() ) { for( size_t j = 0; j < instUniAttrs->entries(); ++j ) { // Filter out attributes that begin with an underscore and // usdprimpath (usdprimpath on instances will confuse the // instancerWrapper). const char *n = instUniAttrs->getName(j); if( !n || strlen( n ) < 1 || n[0] == '_' || string( n ) == GUSD_PRIMPATH_ATTR ) { continue; } if( !pAttrs->hasName( n ) ) { GT_Storage storage = instUniAttrs->get( j )->getStorage(); GT_Size tupleSize = instUniAttrs->get( j )->getTupleSize(); GT_Type typeInfo = instUniAttrs->get( j )->getTypeInfo(); pAttrs = pAttrs->addAttribute( n, newDataArray( storage, nprims, tupleSize, typeInfo ), true ); } } } // Allocate xform attribute used to communicate about the instances // with the instancerWrapper. GT_Real64Array* xformArray = new GT_Real64Array(nprims, 16); bool foundValidTransform = false; GT_Int64Array* instanceIndices = hasInstanceIndices ? new GT_Int64Array(nprims, 1) : NULL; for( size_t primIndex = 0; primIndex < nprims; ++primIndex ) { const GT_PrimitiveHandle& prim = primArray[primIndex].prim; // copy point attribute data from the src prims into prims for // the point instancer. auto instPtAttrs = prim->getPointAttributes(); if( instPtAttrs ) { for( size_t attrIndex = 0; attrIndex < instPtAttrs->entries(); ++attrIndex ) { const char *n = instPtAttrs->getName(attrIndex); if( !n || strlen( n ) < 1 || n[0] == '_' ) { continue; } auto srcData = instPtAttrs->get( attrIndex ); if( auto dstData = pAttrs->get( n ) ) { copyDataArrayItem( dstData, srcData, primIndex, primArray[primIndex].index ); } } if( pivotArray ) { if( auto pos = instPtAttrs->get( "P" ) ) { pivotArray->set( pos->getF32( 0, 0 ), primIndex, 0 ); pivotArray->set( pos->getF32( 0, 1 ), primIndex, 1 ); pivotArray->set( pos->getF32( 0, 2 ), primIndex, 2 ); } } if (hasInstanceIndices) { if(auto packedUSD = dynamic_cast<const GusdGT_PackedUSD*>( prim.get() )) { exint index = packedUSD->getInstanceIndex(); if (index >= 0) { instanceIndices->setTuple(&index, primIndex); } } } } // copy uniform attribute data from the src prims into prims for // the point instancer. auto instUniAttrs = prim->getUniformAttributes(); if( instUniAttrs ) { for( size_t attrIndex = 0; attrIndex < instUniAttrs->entries(); ++attrIndex ) { const char *n = instUniAttrs->getName(attrIndex); if( !n || strlen( n ) < 1 || n[0] == '_' || string(n) == GUSD_PRIMPATH_ATTR ) { continue; } auto srcData = instUniAttrs->get( attrIndex ); if( auto dstData = pAttrs->get( n ) ) { copyDataArrayItem( dstData, srcData, primIndex, primArray[primIndex].index ); } } } // For USD packed prims or geometry packed prims with a usdprimpath // attributes, get the transforms and stuff them into arrays that // can be passed as attributes to the instancerWrapper. if( auto packedUSD = dynamic_cast<const GusdGT_PackedUSD *>( prim.get() )) { const SdfPath primpath(packedUSD->getPrimPath()); UT_Matrix4D xform; packedUSD->getPrimitiveTransform()->getMatrix(xform); xformArray->setTuple(xform.data(), primIndex ); foundValidTransform = true; } else if( auto instance = dynamic_cast<const GT_PrimInstance *>( prim.get() )) { UT_Matrix4D xform; instance->transforms()->get(primArray[primIndex].index)->getMatrix( xform ); xformArray->setTuple(xform.data(), primIndex ); foundValidTransform = true; } } if( foundValidTransform ) { pAttrs = pAttrs->addAttribute( "__instancetransform", xformArray, true ); } if ( hasInstanceIndices ) { pAttrs = pAttrs->addAttribute( "__instanceindex", instanceIndices, true ); } // If the instance prims have a "srcPrimPath" intrinsic (typically // because we are doing an overlay), set the "usdprimpath" attribute on // the point mesh prim so that the point instancer prim gets named properly. GT_AttributeListHandle uniformAttrs; if( !instancerPrimPath.IsEmpty() ) { uniformAttrs = new GT_AttributeList( new GT_AttributeMap() ); auto primPathArray = new GT_DAIndexedString(1); primPathArray->setString( 0, 0, instancerPrimPath.GetText() ); uniformAttrs = uniformAttrs->addAttribute( GUSD_PRIMPATH_ATTR, primPathArray, true ); } // Check for the usdprototypespath attribute in case it is not // a point or primitivie attribute. uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypespath", prim); // Find and add a custom prototype scope attribute. uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypesscope", prim); // Add the refined point instancer. If we are overlaying an old point // instancer make sure to use the old type (temporary). if (refiner.m_pointInstancerType == _tokens->PxPointInstancer) { refiner.addPrimitive( new GusdGT_OldPointInstancer( pAttrs, uniformAttrs ) ); } else { refiner.addPrimitive( new GusdGT_PointInstancer( pAttrs, uniformAttrs ) ); } } }
void GusdRefiner::addPrimitive( const GT_PrimitiveHandle& gtPrimIn ) { if(!gtPrimIn) { std::cout << "Attempting to add invalid prim" << std::endl; return; } GT_PrimitiveHandle gtPrim = gtPrimIn; // copy to a non-const handle int primType = gtPrim->getPrimitiveType(); DBG( cerr << "GusdRefiner::addPrimitive, " << gtPrim->className() << endl ); string primName; // Types can register a function to provide a prim name. // Volumes do this to return a name stored in the f3d file. This is // important for consistant cluster naming. string n; if( GusdPrimWrapper::getPrimName( gtPrim, n )) { primName = n; } bool refinePackedPrims = m_refinePackedPrims; bool primHasNameAttr = false; if( primName.empty() ) { GT_AttributeListHandle primAttrs; if( primType == GT_GEO_PACKED ) { primAttrs = UTverify_cast<const GT_GEOPrimPacked*>(gtPrim.get())->getInstanceAttributes(); } if( !primAttrs ) { primAttrs = gtPrim->getUniformAttributes(); } if( !primAttrs ) { primAttrs = gtPrim->getDetailAttributes(); } GT_DataArrayHandle dah; if( primAttrs ) { dah = primAttrs->get( m_pathAttrName.c_str() ); } if( dah && dah->isValid() ) { const char *s = dah->getS(0); if( s != NULL ) { primName = s; primHasNameAttr = true; } } if( primAttrs ) { GT_DataArrayHandle overXformsAttr = primAttrs->get( GUSD_OVERTRANSFORMS_ATTR ); if( overXformsAttr ) { if( overXformsAttr->getI32(0) != 0 ) { refinePackedPrims = false; } } } } // The following is only necessary for point instancers. Prototypes // can't be point instancers. if (!m_buildPrototypes) { // Check per prim if we are building a point instancer. This may cause // problems for point instancers with discontiguous packed prims. bool localBuildPointInstancer = false; // If we have imported USD geometry get the type to see if it is a // point instancer we need to overlay. if(auto packedUSD = dynamic_cast<const GusdGT_PackedUSD*>( gtPrim.get() )) { if(packedUSD->getFileName()) { // Get the usd src prim path used for point instancers const SdfPath& instancerPrimPath = packedUSD->getSrcPrimPath(); GusdStageCacheReader cache; if(UsdPrim prim = cache.GetPrimWithVariants( packedUSD->getFileName(), instancerPrimPath).first) { // Get the type name of the usd file to overlay m_pointInstancerType = prim.GetTypeName(); // Make sure to set buildPointInstancer to true if we are overlaying a // point instancer if (m_pointInstancerType == _tokens->PointInstancer || m_pointInstancerType == _tokens->PxPointInstancer) { localBuildPointInstancer = true; } } } } // If we find either an instancepath or usdinstancepath attribute, build a // point instancer. GT_Owner owner; if(gtPrim->findAttribute("instancepath", owner, 0) || gtPrim->findAttribute("usdinstancepath", owner, 0) ) { localBuildPointInstancer = true; } if (m_buildPointInstancer || localBuildPointInstancer) { // If we are building point instancer, stash prims that can be // point instanced. Build the point instancer in the finish method. // If given a prim path, pass it to the collector for a custom // usd scope. Otherwise pass an empty SdfPath. SdfPath instancerPrimPath; if( !primName.empty() ) { instancerPrimPath = SdfPath(createPrimPath(primName)); } if( auto packedUSD = dynamic_cast<const GusdGT_PackedUSD*>( gtPrim.get() )) { // Point instancer from packed usd instancerPrimPath = instancerPrimPath.IsEmpty() ? packedUSD->getSrcPrimPath() : instancerPrimPath; m_collector.addInstPrim( instancerPrimPath, gtPrim ); return; } else if( gtPrim->getPrimitiveType() == GT_PRIM_INSTANCE ) { // Point instancer from packed primitives // A GT_PrimInstance can container more than one instance. Create // an entry for each. auto instPrim = UTverify_cast<const GT_PrimInstance*>( gtPrim.get() ); // TODO: If we put all geometry packed prims here, then we break // grouping prims for purpose for( size_t i = 0; i < instPrim->entries(); ++i ) { m_collector.addInstPrim( instancerPrimPath, gtPrim, i ); } return; } if( primType == GT_PRIM_PARTICLE || primType == GT_PRIM_POINT_MESH ) { // Point instancer from points with instancepath attribute // Check for the usdprototypespath attribute in case it is not // a point or primitivie attribute. GT_AttributeListHandle uniformAttrs = gtPrim->getUniformAttributes(); uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypespath", gtPrim); // Find and add a custom prototype scope attribute. uniformAttrs = findAndAddStringAttribute(uniformAttrs, "usdprototypesscope", gtPrim); gtPrim = new GusdGT_PointInstancer( gtPrim->getPointAttributes(), uniformAttrs ); primType = gtPrim->getPrimitiveType(); } } } // We must refine packed prims that don't have a name if( !primHasNameAttr && !refinePackedPrims ) { refinePackedPrims = true; } if( primName.empty() && gtPrim->getPrimitiveType() == GusdGT_PackedUSD::getStaticPrimitiveType() ) { auto packedUsdPrim = UTverify_cast<const GusdGT_PackedUSD *>(gtPrim.get()); SdfPath path = packedUsdPrim->getPrimPath().StripAllVariantSelections(); if( m_useUSDIntrinsicNames ) { primName = path.GetString(); } else { primName = path.GetName(); } // We want prototypes to be children of the point instancer, so we make // the usd path a relative scope of just the usd prim name if ( m_buildPrototypes && !primName.empty() && primName[0] == '/' ) { size_t idx = primName.find_last_of("/"); primName = primName.substr(idx+1); } } // If the prim path was not explicitly set, try to come up with a reasonable // default. bool addNumericSuffix = false; if( primName.empty() ) { int t = gtPrim->getPrimitiveType(); if( t == GT_PRIM_POINT_MESH || t == GT_PRIM_PARTICLE ) primName = "points"; else if( t == GT_PRIM_POLYGON_MESH || t == GT_PRIM_SUBDIVISION_MESH ) primName = "mesh"; else if( t == GT_PRIM_CURVE_MESH ) primName = "curve"; else if( t == GusdGT_PointInstancer::getStaticPrimitiveType() ) primName = "instances"; else if(const char *n = GusdPrimWrapper::getUsdName( t )) primName = n; else primName = "obj"; if( !primName.empty() ) { addNumericSuffix = true; } } string primPath = createPrimPath(primName); TfToken purpose = UsdGeomTokens->default_; { GT_Owner own = GT_OWNER_PRIMITIVE; GT_DataArrayHandle dah = gtPrim->findAttribute( GUSD_PURPOSE_ATTR, own, 0 ); if( dah && dah->isValid() ) { purpose = TfToken(dah->getS(0)); } } if( primType == GT_PRIM_INSTANCE ) { auto inst = UTverify_cast<const GT_PrimInstance*>(gtPrim.get()); const GT_PrimitiveHandle geometry = inst->geometry(); if ( geometry->getPrimitiveType() == GT_GEO_PACKED ) { // If we find a packed prim that has a name, this become a group (xform) in // USD. If it doesn't have a name, we just accumulate the transform and recurse. auto packedGeo = UTverify_cast<const GT_GEOPrimPacked*>(geometry.get()); for( GT_Size i = 0; i < inst->transforms()->entries(); ++i ) { UT_Matrix4D m; inst->transforms()->get(i)->getMatrix(m); UT_Matrix4D newCtm = m_localToWorldXform; newCtm = m* m_localToWorldXform; SdfPath newPath = m_pathPrefix; bool recurse = true; if( primHasNameAttr || ( m_forceGroupTopPackedPrim && m_isTopLevel )) { // m_forceGroupTopPackedPrim is used when we are writing instance // prototypes. We need to add instance id attributes to the top // level group. Here we make sure that we create that group, even // if the user hasn't named it. newPath = m_collector.add( SdfPath(primPath), addNumericSuffix, gtPrim, newCtm, purpose, m_writeCtrlFlags ); // If we are just writing transforms and encounter a packed prim, we // just want to write it's transform and not refine it further. recurse = refinePackedPrims; } if( recurse ) { GusdRefiner childRefiner( m_collector, newPath, m_pathAttrName, newCtm ); childRefiner.m_refinePackedPrims = refinePackedPrims; childRefiner.m_forceGroupTopPackedPrim = m_forceGroupTopPackedPrim; childRefiner.m_isTopLevel = false; childRefiner.m_writeCtrlFlags = m_writeCtrlFlags; childRefiner.m_writeCtrlFlags.update( geometry ); #if UT_MAJOR_VERSION_INT >= 16 childRefiner.refineDetail( packedGeo->getPackedDetail(), m_refineParms ); #else childRefiner.refineDetail( packedGeo->getPrim()->getPackedDetail(), m_refineParms ); #endif } } return; } } if( (primType != GT_GEO_PACKED || !refinePackedPrims) && GusdPrimWrapper::isGTPrimSupported(gtPrim) ) { UT_Matrix4D m; if( primType == GT_GEO_PACKED ) { // packed fragment UTverify_cast<const GT_GEOPrimPacked*>(gtPrim.get())->getFullTransform()->getMatrix(m); } else { gtPrim->getPrimitiveTransform()->getMatrix(m); } UT_Matrix4D newCtm = m_localToWorldXform; newCtm = m* m_localToWorldXform; m_collector.add( SdfPath(primPath), addNumericSuffix, gtPrim, newCtm, purpose, m_writeCtrlFlags ); } else { gtPrim->refine( *this, &m_refineParms ); } }