UsdGeomCamera GusdOBJ_usdcamera::_LoadCamera(fpreal t, int thread) { /* XXX: Disallow camera loading until the scene has finished loading. What happens otherwise is that some parm values are pulled on during loading, causing a _LoadCamera request. If this happens before the node's parm values have been loaded, then we'll end up loading the camera using defaults (which reference the shot conversion). So if we don't block this, we end up always loading the shot conversion, even if we don't need it! */ if(_isLoading) return UsdGeomCamera(); /* Always return a null camera while saving. This is to prevent load errors from prematurely interrupting saves, which can lead to corrupt files.*/ if(GusdUTverify_ptr(OPgetDirector())->getIsDoingExplicitSave()) return UsdGeomCamera(); { UT_AutoReadLock readLock(_lock); if(!_camParmsMicroNode.requiresUpdate(t)) return _cam; } UT_AutoWriteLock writeLock(_lock); /* Other thread may already have loaded the cam, so only update if needed.*/ if(_camParmsMicroNode.updateIfNeeded(t, thread)) { _errors.clearAndDestroyErrors(); _cam = UsdGeomCamera(); GusdPRM_Shared prmShared; UT_String usdPath, primPath; evalStringT(usdPath, prmShared->filePathName.getToken(), 0, t, thread); evalStringT(primPath, prmShared->primPathName.getToken(), 0, t, thread); GusdUT_ErrorManager errMgr(_errors); GusdUT_ErrorContext err(errMgr); GusdStageCacheReader cache; if(UsdPrim prim = cache.GetPrimWithVariants( usdPath, primPath, GusdStageOpts::LoadAll(), &err).first) { // Track changes to the stage (eg., reloads) DEP_MicroNode* stageMicroNode = cache.GetStageMicroNode(prim.GetStage()); UT_ASSERT_P(stageMicroNode); _camParmsMicroNode.addExplicitInput(*stageMicroNode); _cam = GusdUSD_Utils::MakeSchemaObj<UsdGeomCamera>(prim, &err); return _cam; } } return UsdGeomCamera(); }
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 ); } }