Exemplo n.º 1
0
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();
}
Exemplo n.º 2
0
OP_ERROR
GusdSOP_usdimport::_CreateNewPrims(OP_Context& ctx,
                                   const GusdUSD_Traverse* traverse,
                                   GusdUT_ErrorContext& err)
{
    fpreal t = ctx.getTime();

    UT_String file, primPath;
    evalString(file, "import_file", 0, t);
    evalString(primPath, "import_primpath", 0, t);
    if(!file.isstring() || !primPath.isstring()) {
        // Nothing to do.
        return UT_ERROR_NONE;
    }

    /* The prim path may be a list of prims.
       Additionally, those prim paths may include variants
       (eg., /some/model{variant=sel}/subscope ).
       Including multiple variants may mean that we need to access
       multiple stages. 

       Resolve the actual set of prims and variants first.*/

    UT_Array<SdfPath> primPaths, variants;
    if(!GusdUSD_Utils::GetPrimAndVariantPathsFromPathList(
           primPath, primPaths, variants, &err))
        return err();

    GusdDefaultArray<UT_StringHolder> filePaths;
    filePaths.SetConstant(file);

    // Get stage edits applying any of our variants.
    GusdDefaultArray<GusdStageEditPtr> edits;
    edits.GetArray().setSize(variants.size());
    for(exint i = 0; i < variants.size(); ++i) {
        if(!variants(i).IsEmpty()) {
            GusdStageBasicEdit* edit = new GusdStageBasicEdit;
            edit->GetVariants().append(variants(i));
            edits.GetArray()(i).reset(edit);
        }
    }
    
    // Load the root prims.
    UT_Array<UsdPrim> rootPrims;
    {
        rootPrims.setSize(primPaths.size());

        GusdStageCacheReader cache;
        if(!cache.GetPrims(filePaths, primPaths, edits,
                           rootPrims.data(),
                           GusdStageOpts::LoadAll(), &err))
            return err();
    }

    GusdDefaultArray<UsdTimeCode> times;
    times.SetConstant(evalFloat("import_time", 0, t));

    UT_String purpose;
    evalString(purpose, "purpose", 0, t);

    GusdDefaultArray<GusdPurposeSet> purposes;
    purposes.SetConstant(GusdPurposeSet(
                             GusdPurposeSetFromMask(purpose)|
                             GUSD_PURPOSE_DEFAULT));

    UT_Array<UsdPrim> prims;
    if(traverse) {
        // Before traversal, make a copy of the variants list.
        const UT_Array<SdfPath> variantsPreTraverse(variants);

        UT_Array<GusdUSD_Traverse::PrimIndexPair> primIndexPairs;

        UT_UniquePtr<GusdUSD_Traverse::Opts> opts(traverse->CreateOpts());
        if(opts) {
            if(!opts->Configure(*this, t))
                return err();
        }

        if(!traverse->FindPrims(rootPrims, times, purposes, primIndexPairs,
                                /*skip root*/ false, opts.get())) {
            return err();
        }

        // Resize the prims and variants lists to match the size of
        // primIndexPairs.
        exint size = primIndexPairs.size();
        prims.setSize(size);
        variants.setSize(size);

        // Now iterate through primIndexPairs to populate the prims
        // and variants lists.
        for (exint i = 0; i < size; i++) {
            prims(i) = primIndexPairs(i).first;
            exint index = primIndexPairs(i).second;

            variants(i) = index < variantsPreTraverse.size() ?
                          variantsPreTraverse(index) : SdfPath();
        }

    } else {
        std::swap(prims, rootPrims);
    }

    /* Have the resolved set of USD prims.
       Now create prims or points on the detail.*/

    bool packedPrims = !evalInt("import_class", 0, t);
    if(packedPrims) {
        UT_String vpLOD;
        evalString(vpLOD, "viewportlod", 0, t);


        GusdDefaultArray<UT_StringHolder> lods;
        lods.SetConstant(vpLOD);

        GusdGU_USD::AppendPackedPrims(*gdp, prims, variants,
                                      times, lods, purposes, &err);
    } else {
        GusdGU_USD::AppendRefPoints(*gdp, prims, GUSD_PATH_ATTR,
                                    GUSD_PRIMPATH_ATTR, &err);
    }
    return err();
}
Exemplo n.º 3
0
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 );
    }
}