Beispiel #1
0
bool
UsdRelationship::SetTargets(const SdfPathVector& targets) const
{
    SdfPathVector mappedPaths;
    mappedPaths.reserve(targets.size());
    for (const SdfPath &target: targets) {
        std::string errMsg;
        mappedPaths.push_back(_GetTargetForAuthoring(target, &errMsg));
        if (mappedPaths.back().IsEmpty()) {
            TF_CODING_ERROR("Cannot set target <%s> on relationship <%s>: %s",
                            target.GetText(), GetPath().GetText(), 
                            errMsg.c_str());
            return false;
        }
    }

    // NOTE! Do not insert any code that modifies scene description between the
    // changeblock and the call to _CreateSpec!  Explanation: _CreateSpec calls
    // code that inspects the composition graph and then does some authoring.
    // We want that authoring to be inside the change block, but if any scene
    // description changes are made after the block is created but before we
    // call _CreateSpec, the composition structure may be invalidated.
    SdfChangeBlock block;
    SdfRelationshipSpecHandle relSpec = _CreateSpec();

    if (!relSpec)
        return false;

    relSpec->GetTargetPathList().ClearEditsAndMakeExplicit();
    for (const SdfPath &path: mappedPaths) {
        relSpec->GetTargetPathList().Add(path);
    }

    return true;
}
Beispiel #2
0
bool 
UsdGeomCollectionAPI::AppendTarget(
    const SdfPath &target, 
    const VtIntArray &faceIndices /* =VtIntArray() */,
    const UsdTimeCode &time /* =UsdTimeCode::Default() */) const
{
    if (target.IsEmpty()) {
        TF_CODING_ERROR("Cannot add empty target to collection '%s' on "
            "prim <%s>.", _name.GetText(), GetPath().GetText());
        return false;
    }

    bool hasFaceCountsAtTime = true;
    if (time != UsdTimeCode::Default()) {
        UsdAttribute targetFaceCountsAttr = GetTargetFaceCountsAttr();
        double lower=0., upper=0.;
        bool hasTimeSamples=false;
        if (targetFaceCountsAttr.GetBracketingTimeSamples(time.GetValue(),
            &lower, &upper, &hasTimeSamples)) 
        {
            hasFaceCountsAtTime = (lower==upper && lower==time.GetValue());
        }
    }

    VtIntArray targetFaceCounts, targetFaceIndices;
    if (hasFaceCountsAtTime) {
        GetTargetFaceCounts(&targetFaceCounts, time);
        GetTargetFaceIndices(&targetFaceIndices, time);
    }

    SdfPathVector targets;
    GetTargets(&targets);

    // If there are no existing face restrictions and no face-restriction is 
    // specified on the current target, simly add the target and return.
    if (targetFaceCounts.empty() && targetFaceIndices.empty() &&
        faceIndices.empty()) 
    {
        // We can simply add the target here to the relationship here since 
        // there are no companion non-list-edited integer arrays.
        return CreateTargetsRel().AppendTarget(target);
    }

    if (targetFaceCounts.empty() && !targetFaceIndices.empty()) {
        TF_CODING_ERROR("targetFaceCounts is empty, but targetFaceIndices "
            "is not, for the collection '%s' belonging to prim <%s>.",
            _name.GetText(), GetPath().GetText());
        return false;
    }

    if (targetFaceCounts.empty() && !faceIndices.empty()) {
        for (size_t i = 0 ; i < targets.size(); i++)
            targetFaceCounts.push_back(0);
    }

    targetFaceCounts.push_back(faceIndices.size()); 
    targetFaceIndices.reserve(targetFaceIndices.size() + faceIndices.size());
    TF_FOR_ALL(it, faceIndices) {
        targetFaceIndices.push_back(*it);
    }
Beispiel #3
0
UsdVolVolume::FieldMap
UsdVolVolume::GetFieldPaths() const
{
    std::map<TfToken, SdfPath> fieldMap;
    const UsdPrim &prim = GetPrim();

    if (prim) {
        std::vector<UsdProperty> fieldProps =
            prim.GetPropertiesInNamespace(_tokens->fieldPrefix);
        for (const UsdProperty &fieldProp : fieldProps) {
            UsdRelationship fieldRel = fieldProp.As<UsdRelationship>();
            SdfPathVector targets;

            // All relationships starting with "field:" should point to
            // UsdVolFieldBase primitives.
            if (fieldRel && fieldRel.GetForwardedTargets(&targets)) {
                if (targets.size() == 1 && 
                    targets.front().IsPrimPath()) {
                    fieldMap.emplace(fieldRel.GetBaseName(), targets.front());
                }
            }
        }
    }

    return fieldMap;
}
Beispiel #4
0
bool 
UsdGeomCollectionAPI::IsEmpty() const
{
    UsdRelationship targetsRel = _GetTargetsRel();
    if (targetsRel) {
        SdfPathVector targets;
        targetsRel.GetTargets(&targets);
        return targets.empty();
    }
    return true;
}
Beispiel #5
0
SdfPath
UsdVolVolume::GetFieldPath(const TfToken &name) const
{
    UsdRelationship fieldRel =  GetPrim().GetRelationship(_MakeNamespaced(name));
    SdfPathVector targets;
    
    if (fieldRel && fieldRel.GetForwardedTargets(&targets)) {
        if (targets.size() == 1 && 
            targets.front().IsPrimPath()) {
            return targets.front();
        }
    }

    return SdfPath::EmptyPath();
}
Beispiel #6
0
bool
UsdRelationship::SetTargets(const SdfPathVector& targets) const
{
    SdfPathVector mappedPaths;
    mappedPaths.reserve(targets.size());
    BOOST_FOREACH(const SdfPath &target, targets) {
        std::string errMsg;
        mappedPaths.push_back(_GetTargetForAuthoring(target, &errMsg));
        if (mappedPaths.back().IsEmpty()) {
            TF_CODING_ERROR("Cannot set target <%s> on relationship <%s>: %s",
                            target.GetText(), GetPath().GetText(), 
                            errMsg.c_str());
            return false;
        }
    }
Beispiel #7
0
SdfPathVector 
Sdf_MarkerUtils<Spec>::GetMarkerPaths(const Spec& owner)
{
    SdfPathVector paths;

    const SdfLayerHandle layer = owner.GetLayer();
    const SdfPathVector children = owner.template GetFieldAs<SdfPathVector>(
        _MarkerPolicy::GetChildFieldKey());

    TF_FOR_ALL(path, children) {
        const SdfPath targetSpecPath = owner.GetPath().AppendTarget(*path);
        if (layer->HasField(targetSpecPath, SdfFieldKeys->Marker)) {
            paths.push_back(*path);
        }
    }

    return paths;
}
Beispiel #8
0
bool
UsdGeomPrimvar::SetIdTarget(
        const SdfPath& path) const
{
    if (_idTargetRelName.IsEmpty()) {
        TF_CODING_ERROR("Can only set ID Target for string or string[] typed"
                        " primvars (primvar type is '%s')",
                        _attr.GetTypeName().GetAsToken().GetText());
        return false;
    }

    if (UsdRelationship rel = _GetIdTargetRel(true)) {
        SdfPathVector targets;
        targets.push_back(path.IsEmpty() ? _attr.GetPrimPath() : 
                path);
        return rel.SetTargets(targets);
    }
    return false;
}
Beispiel #9
0
bool
UsdGeomPrimvar::Get(
        std::string* value,
        UsdTimeCode time) const
{
    // check if there is a relationship and if so use the target path string to
    // get the string value.
    if (!_idTargetRelName.IsEmpty()) {
        if (UsdRelationship rel = _GetIdTargetRel(false)) {
            SdfPathVector targets;
            if (rel.GetForwardedTargets(&targets) && 
                    targets.size() == 1) {
                *value = targets[0].GetString();
                return true;
            }
            return false;
        }
    }

    return _attr.Get(value, time);
}
Beispiel #10
0
 void _VisitImpl(SdfPathVector const &paths) {
     if (!paths.empty()) {
         for (SdfPath const &p: paths) {
             _workQueue.push(p);
         }
         _consumerTask.Wake();
     }
     
     if (_recurse) {
         WorkParallelForEach(
             paths.begin(), paths.end(),
             [this](SdfPath const &path) {
                 if (!path.HasPrefix(_prim.GetPath())) {
                     if (UsdPrim owningPrim = _prim.GetStage()->
                         GetPrimAtPath(path.GetPrimPath())) {
                         _VisitSubtree(owningPrim);
                     }
                 }
             });
     }
 }    
Beispiel #11
0
static
UsdImagingEngine* _InitEngine(const SdfPath& rootPath,
                              const SdfPathVector& excludedPaths,
                              const SdfPathVector& invisedPaths,
                              const SdfPath& sharedId =
                                        SdfPath::AbsoluteRootPath(),
                              const UsdImagingEngineSharedPtr& sharedEngine =
                                        UsdImagingEngineSharedPtr())
{
    if (UsdImagingGL::IsEnabledHydra()) {
        return new UsdImagingHdEngine(rootPath, excludedPaths, invisedPaths, 
            sharedId, 
            boost::dynamic_pointer_cast<UsdImagingHdEngine>(sharedEngine));
    } else {
        // In the refEngine, both excluded paths and invised paths are treated
        // the same way.
        SdfPathVector pathsToExclude = excludedPaths;
        pathsToExclude.insert(pathsToExclude.end(), 
            invisedPaths.begin(), invisedPaths.end());
        return new UsdImagingRefEngine(pathsToExclude);
    }
}
Beispiel #12
0
bool
UsdGeomPrimvar::Get(
        VtStringArray* value,
        UsdTimeCode time) const
{
    // check if there is a relationship and if so use the target path string to
    // get the string value... Just take the first target, for now.
    if (!_idTargetRelName.IsEmpty()) {
        if (UsdRelationship rel = _GetIdTargetRel(false)) {
            value->clear();
            SdfPathVector targets;
            if (rel.GetForwardedTargets(&targets) && 
                    targets.size() > 1) {
                value->push_back(targets[0].GetString());
                return true;
            }
            return false;
        }
    }

    return _attr.Get(value, time);
}
Beispiel #13
0
PXR_NAMESPACE_OPEN_SCOPE


// TODO: We should centralize this logic in a UsdImaging ShaderAdapter.

/*static*/
UsdPrim
UsdImaging_MaterialStrategy::GetTargetedShader(UsdPrim const& materialPrim,
                                        UsdRelationship const& materialRel)
{
    SdfPathVector targets;
    if (!materialRel.GetForwardedTargets(&targets))
        return UsdPrim();

    if (targets.size() != 1) {
        // XXX: This should really be a validation error once USD gets that
        // feature.
        TF_WARN("We expect only one target on relationship %s of prim <%s>, "
                "but got %zu.",
                materialRel.GetName().GetText(),
                materialPrim.GetPath().GetText(),
                targets.size());
        return UsdPrim();
    }

    if (!targets[0].IsPrimPath()) {
        // XXX: This should really be a validation error once USD gets that
        // feature.
        TF_WARN("We expect the target of the relationship %s of prim <%s> "
                "to be a prim, instead it is <%s>.",
                materialRel.GetName().GetText(),
                materialPrim.GetPath().GetText(),
                targets[0].GetText());
        return UsdPrim();
    }

    return materialPrim.GetStage()->GetPrimAtPath(targets[0]);
}
Beispiel #14
0
void
SdfAttributeSpec::ChangeMapperPath(
    const SdfPath& oldPath, const SdfPath& newPath)
{
    if (not PermissionToEdit()) {
        TF_CODING_ERROR("Change mapper path: Permission denied.");
        return;
    }

    const SdfPath& attrPath = GetPath();

    // Absolutize.
    SdfPath oldAbsPath = oldPath.MakeAbsolutePath(attrPath.GetPrimPath());
    SdfPath newAbsPath = newPath.MakeAbsolutePath(attrPath.GetPrimPath());

    // Validate.
    if (oldAbsPath == newAbsPath) {
        // Nothing to do.
        return;
    }
    if (not newAbsPath.IsPropertyPath()) {
        TF_CODING_ERROR("cannot change connection path for attribute %s's "
                        "mapper at connection path <%s> to <%s> because it's "
                        "not a property path",
                        attrPath.GetString().c_str(),
                        oldAbsPath.GetString().c_str(),
                        newAbsPath.GetString().c_str());
        return;
    }
    
    SdfPathVector mapperPaths = 
        GetFieldAs<SdfPathVector>(SdfChildrenKeys->MapperChildren);

    // Check that a mapper actually exists at the old path.
    SdfPathVector::iterator mapperIt = 
        std::find(mapperPaths.begin(), mapperPaths.end(), oldAbsPath);
    if (mapperIt == mapperPaths.end()) {
        TF_CODING_ERROR("Change mapper path: No mapper exists for "
            "connection path <%s>.", oldAbsPath.GetText());
        return;
    }

    // Check that no mapper already exists at the new path.
    const bool mapperExistsAtNewPath = 
        (std::find(mapperPaths.begin(), mapperPaths.end(), newAbsPath) != 
            mapperPaths.end());
    if (mapperExistsAtNewPath) {
        TF_CODING_ERROR("Change mapper path: Mapper already exists for "
            "connection path <%s>.", newAbsPath.GetText());
        return;
    }

    // Things look OK -- let's go ahead and move the mapper over to the
    // new path.
    SdfChangeBlock block;
        
    const SdfPath oldMapperSpecPath = attrPath.AppendMapper(oldAbsPath);
    const SdfPath newMapperSpecPath = attrPath.AppendMapper(newAbsPath);
    _MoveSpec(oldMapperSpecPath, newMapperSpecPath);

    *mapperIt = newAbsPath;
    SetField(SdfChildrenKeys->MapperChildren, VtValue(mapperPaths));

}
Beispiel #15
0
void
PxrUsdKatanaReadPointInstancer(
        const UsdGeomPointInstancer& instancer,
        const PxrUsdKatanaUsdInPrivateData& data,
        PxrUsdKatanaAttrMap& instancerAttrMap,
        PxrUsdKatanaAttrMap& sourcesAttrMap,
        PxrUsdKatanaAttrMap& instancesAttrMap,
        PxrUsdKatanaAttrMap& inputAttrMap)
{
    const double currentTime = data.GetCurrentTime();

    PxrUsdKatanaReadXformable(instancer, data, instancerAttrMap);

    // Get primvars for setting later. Unfortunatley, the only way to get them
    // out of the attr map is to build it, which will cause its contents to be
    // cleared. We'll need to restore its contents before continuing.
    //
    FnKat::GroupAttribute instancerAttrs = instancerAttrMap.build();
    FnKat::GroupAttribute primvarAttrs =
            instancerAttrs.getChildByName("geometry.arbitrary");
    for (int64_t i = 0; i < instancerAttrs.getNumberOfChildren(); ++i)
    {
        instancerAttrMap.set(instancerAttrs.getChildName(i),
                instancerAttrs.getChildByIndex(i));
    }

    instancerAttrMap.set("type", FnKat::StringAttribute("usd point instancer"));

    const std::string fileName = data.GetUsdInArgs()->GetFileName();
    instancerAttrMap.set("info.usd.fileName", FnKat::StringAttribute(fileName));

    FnKat::GroupAttribute inputAttrs = inputAttrMap.build();

    const std::string katOutputPath = FnKat::StringAttribute(
            inputAttrs.getChildByName("outputLocationPath")).getValue("", false);
    if (katOutputPath.empty())
    {
        _LogAndSetError(instancerAttrMap, "No output location path specified");
        return;
    }

    //
    // Validate instancer data.
    //

    const std::string instancerPath = instancer.GetPath().GetString();

    UsdStageWeakPtr stage = instancer.GetPrim().GetStage();

    // Prototypes (required)
    //
    SdfPathVector protoPaths;
    instancer.GetPrototypesRel().GetTargets(&protoPaths);
    if (protoPaths.empty())
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no prototypes");
        return;
    }

    _PathToPrimMap primCache;
    for (auto protoPath : protoPaths) {
        const UsdPrim &protoPrim = stage->GetPrimAtPath(protoPath);
        primCache[protoPath] = protoPrim;
    }

    // Indices (required)
    //
    VtIntArray protoIndices;
    if (!instancer.GetProtoIndicesAttr().Get(&protoIndices, currentTime))
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no prototype indices");
        return;
    }
    const size_t numInstances = protoIndices.size();
    if (numInstances == 0)
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no prototype indices");
        return;
    }
    for (auto protoIndex : protoIndices)
    {
        if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size())
        {
            _LogAndSetError(instancerAttrMap, TfStringPrintf(
                    "Out of range prototype index %d", protoIndex));
            return;
        }
    }

    // Mask (optional)
    //
    std::vector<bool> pruneMaskValues =
            instancer.ComputeMaskAtTime(currentTime);
    if (!pruneMaskValues.empty() and pruneMaskValues.size() != numInstances)
    {
        _LogAndSetError(instancerAttrMap,
                "Mismatch in length of indices and mask");
        return;
    }

    // Positions (required)
    //
    UsdAttribute positionsAttr = instancer.GetPositionsAttr();
    if (!positionsAttr.HasValue())
    {
        _LogAndSetError(instancerAttrMap, "Instancer has no positions");
        return;
    }

    //
    // Compute instance transform matrices.
    //

    const double timeCodesPerSecond = stage->GetTimeCodesPerSecond();

    // Gather frame-relative sample times and add them to the current time to
    // generate absolute sample times.
    //
    const std::vector<double> &motionSampleTimes =
        data.GetMotionSampleTimes(positionsAttr);
    const size_t sampleCount = motionSampleTimes.size();
    std::vector<UsdTimeCode> sampleTimes(sampleCount);
    for (size_t a = 0; a < sampleCount; ++a)
    {
        sampleTimes[a] = UsdTimeCode(currentTime + motionSampleTimes[a]);
    }

    // Get velocityScale from the opArgs.
    //
    float velocityScale = FnKat::FloatAttribute(
        inputAttrs.getChildByName("opArgs.velocityScale")).getValue(1.0f, false);

    // XXX Replace with UsdGeomPointInstancer::ComputeInstanceTransformsAtTime.
    //
    std::vector<std::vector<GfMatrix4d>> xformSamples(sampleCount);
    const size_t numXformSamples =
        _ComputeInstanceTransformsAtTime(xformSamples, instancer, sampleTimes,
            UsdTimeCode(currentTime), timeCodesPerSecond, numInstances,
            positionsAttr, velocityScale);
    if (numXformSamples == 0) {
        _LogAndSetError(instancerAttrMap, "Could not compute "
                                          "sample/topology-invarying instance "
                                          "transform matrix");
        return;
    }

    //
    // Compute prototype bounds.
    //

    bool aggregateBoundsValid = false;
    std::vector<double> aggregateBounds;

    // XXX Replace with UsdGeomPointInstancer::ComputeExtentAtTime.
    //
    VtVec3fArray aggregateExtent;
    if (_ComputeExtentAtTime(
            aggregateExtent, data.GetUsdInArgs(), xformSamples,
            motionSampleTimes, protoIndices, protoPaths, primCache,
            pruneMaskValues)) {
        aggregateBoundsValid = true;
        aggregateBounds.resize(6);
        aggregateBounds[0] = aggregateExtent[0][0]; // min x
        aggregateBounds[1] = aggregateExtent[1][0]; // max x
        aggregateBounds[2] = aggregateExtent[0][1]; // min y
        aggregateBounds[3] = aggregateExtent[1][1]; // max y
        aggregateBounds[4] = aggregateExtent[0][2]; // min z
        aggregateBounds[5] = aggregateExtent[1][2]; // max z
    }

    //
    // Build sources. Keep track of which instances use them.
    //

    FnGeolibServices::StaticSceneCreateOpArgsBuilder sourcesBldr(false);

    std::vector<int> instanceIndices;
    instanceIndices.reserve(numInstances);

    std::vector<std::string> instanceSources;
    instanceSources.reserve(protoPaths.size());

    std::map<std::string, int> instanceSourceIndexMap;

    std::vector<int> omitList;
    omitList.reserve(numInstances);

    std::map<SdfPath, std::string> protoPathsToKatPaths;

    for (size_t i = 0; i < numInstances; ++i)
    {
        int index = protoIndices[i];

        // Check to see if we are pruned.
        //
        bool isPruned = (!pruneMaskValues.empty() and
                         pruneMaskValues[i] == false);
        if (isPruned)
        {
            omitList.push_back(i);
        }

        const SdfPath &protoPath = protoPaths[index];

        // Compute the full (Katana) path to this prototype.
        //
        std::string fullProtoPath;
        std::map<SdfPath, std::string>::const_iterator pptkpIt =
                protoPathsToKatPaths.find(protoPath);
        if (pptkpIt != protoPathsToKatPaths.end())
        {
            fullProtoPath = pptkpIt->second;
        }
        else
        {
            _PathToPrimMap::const_iterator pcIt = primCache.find(protoPath);
            const UsdPrim &protoPrim = pcIt->second;
            if (!protoPrim) {
                continue;
            }

            // Determine where (what path) to start building the prototype prim
            // such that its material bindings will be preserved. This could be
            // the prototype path itself or an ancestor path.
            //
            SdfPathVector commonPrefixes;

            UsdRelationship materialBindingsRel =
                    UsdShadeMaterial::GetBindingRel(protoPrim);

            auto assetAPI = UsdModelAPI(protoPrim);
            std::string assetName;
            bool isReferencedModelPrim =
                    assetAPI.IsModel() and assetAPI.GetAssetName(&assetName);

            if (!materialBindingsRel or isReferencedModelPrim)
            {
                // The prim has no material bindings or is a referenced model
                // prim (meaning that materials are defined below it); start
                // building at the prototype path.
                //
                commonPrefixes.push_back(protoPath);
            }
            else
            {
                SdfPathVector materialPaths;
                materialBindingsRel.GetForwardedTargets(&materialPaths);
                for (auto materialPath : materialPaths)
                {
                    const SdfPath &commonPrefix =
                            protoPath.GetCommonPrefix(materialPath);
                    if (commonPrefix.GetString() == "/")
                    {
                        // XXX Unhandled case.
                        // The prototype prim and its material are not under the
                        // same parent; start building at the prototype path
                        // (although it is likely that bindings will be broken).
                        //
                        commonPrefixes.push_back(protoPath);
                    }
                    else
                    {
                        // Start building at the common ancestor between the
                        // prototype prim and its material.
                        //
                        commonPrefixes.push_back(commonPrefix);
                    }
                }
            }

            // XXX Unhandled case.
            // We'll use the first common ancestor even if there is more than
            // one (which shouldn't appen if the prototype prim and its bindings
            // are under the same parent).
            //
            SdfPath::RemoveDescendentPaths(&commonPrefixes);
            const std::string buildPath = commonPrefixes[0].GetString();

            // See if the path is a child of the point instancer. If so, we'll
            // match its hierarchy. If not, we'll put it under a 'prototypes'
            // group.
            //
            std::string relBuildPath;
            if (pystring::startswith(buildPath, instancerPath + "/"))
            {
                relBuildPath = pystring::replace(
                        buildPath, instancerPath + "/", "");
            }
            else
            {
                relBuildPath = "prototypes/" +
                        FnGeolibUtil::Path::GetLeafName(buildPath);
            }

            // Start generating the full path to the prototype.
            //
            fullProtoPath = katOutputPath + "/" + relBuildPath;

            // Make the common ancestor our instance source.
            //
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "type", FnKat::StringAttribute("instance source"));

            // Author a tracking attr.
            //
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "info.usd.sourceUsdPath",
                    FnKat::StringAttribute(buildPath));

            // Tell the BuildIntermediate op to start building at the common
            // ancestor.
            //
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "usdPrimPath", FnKat::StringAttribute(buildPath));
            sourcesBldr.setAttrAtLocation(relBuildPath,
                    "usdPrimName", FnKat::StringAttribute("geo"));

            if (protoPath.GetString() != buildPath)
            {
                // Finish generating the full path to the prototype.
                //
                fullProtoPath = fullProtoPath + "/geo" + pystring::replace(
                        protoPath.GetString(), buildPath, "");
            }

            // Create a mapping that will link the instance's index to its
            // prototype's full path.
            //
            instanceSourceIndexMap[fullProtoPath] = instanceSources.size();
            instanceSources.push_back(fullProtoPath);

            // Finally, store the full path in the map so we won't have to do
            // this work again.
            //
            protoPathsToKatPaths[protoPath] = fullProtoPath;
        }

        instanceIndices.push_back(instanceSourceIndexMap[fullProtoPath]);
    }

    //
    // Build instances.
    //

    FnGeolibServices::StaticSceneCreateOpArgsBuilder instancesBldr(false);

    instancesBldr.createEmptyLocation("instances", "instance array");

    instancesBldr.setAttrAtLocation("instances",
            "geometry.instanceSource",
                    FnKat::StringAttribute(instanceSources, 1));

    instancesBldr.setAttrAtLocation("instances",
            "geometry.instanceIndex",
                    FnKat::IntAttribute(&instanceIndices[0],
                            instanceIndices.size(), 1));

    FnKat::DoubleBuilder instanceMatrixBldr(16);
    for (size_t a = 0; a < numXformSamples; ++a) {

        double relSampleTime = motionSampleTimes[a];

        // Shove samples into the builder at the frame-relative sample time. If
        // motion is backwards, make sure to reverse time samples.
        std::vector<double> &matVec = instanceMatrixBldr.get(
            data.IsMotionBackward()
                ? PxrUsdKatanaUtils::ReverseTimeSample(relSampleTime)
                : relSampleTime);

        matVec.reserve(16 * numInstances);
        for (size_t i = 0; i < numInstances; ++i) {

            GfMatrix4d instanceXform = xformSamples[a][i];
            const double *matArray = instanceXform.GetArray();

            for (int j = 0; j < 16; ++j) {
                matVec.push_back(matArray[j]);
            }
        }
    }
    instancesBldr.setAttrAtLocation("instances",
            "geometry.instanceMatrix", instanceMatrixBldr.build());

    if (!omitList.empty())
    {
        instancesBldr.setAttrAtLocation("instances",
                "geometry.omitList",
                        FnKat::IntAttribute(&omitList[0], omitList.size(), 1));
    }

    instancesBldr.setAttrAtLocation("instances",
            "geometry.pointInstancerId",
                    FnKat::StringAttribute(katOutputPath));

    //
    // Transfer primvars.
    //

    FnKat::GroupBuilder instancerPrimvarsBldr;
    FnKat::GroupBuilder instancesPrimvarsBldr;
    for (int64_t i = 0; i < primvarAttrs.getNumberOfChildren(); ++i)
    {
        const std::string primvarName = primvarAttrs.getChildName(i);

        // Use "point" scope for the instancer.
        instancerPrimvarsBldr.set(primvarName, primvarAttrs.getChildByIndex(i));
        instancerPrimvarsBldr.set(primvarName + ".scope",
                FnKat::StringAttribute("point"));

        // User "primitive" scope for the instances.
        instancesPrimvarsBldr.set(primvarName, primvarAttrs.getChildByIndex(i));
        instancesPrimvarsBldr.set(primvarName + ".scope",
                FnKat::StringAttribute("primitive"));
    }
    instancerAttrMap.set("geometry.arbitrary", instancerPrimvarsBldr.build());
    instancesBldr.setAttrAtLocation("instances",
            "geometry.arbitrary", instancesPrimvarsBldr.build());

    //
    // Set the final aggregate bounds.
    //

    if (aggregateBoundsValid)
    {
        instancerAttrMap.set("bound", FnKat::DoubleAttribute(&aggregateBounds[0], 6, 2));
    }

    //
    // Set proxy attrs.
    //

    instancerAttrMap.set("proxies", PxrUsdKatanaUtils::GetViewerProxyAttr(data));

    //
    // Transfer builder results to our attr maps.
    //

    FnKat::GroupAttribute sourcesAttrs = sourcesBldr.build();
    for (int64_t i = 0; i < sourcesAttrs.getNumberOfChildren(); ++i)
    {
        sourcesAttrMap.set(
                sourcesAttrs.getChildName(i),
                sourcesAttrs.getChildByIndex(i));
    }

    FnKat::GroupAttribute instancesAttrs = instancesBldr.build();
    for (int64_t i = 0; i < instancesAttrs.getNumberOfChildren(); ++i)
    {
        instancesAttrMap.set(
                instancesAttrs.getChildName(i),
                instancesAttrs.getChildByIndex(i));
    }
}
Beispiel #16
0
bool
HdDirtyList::ApplyEdit(HdRprimCollection const& col)
{
    HD_TRACE_FUNCTION();

    // Don't attempt to transition dirty lists where the collection
    // fundamentally changed, we can't reused filtered paths in those cases.
    //
    // when repr changes, don't reuse the dirty list, since the required
    // DirtyBits may change.
    if (col.GetName() != _collection.GetName()
        || col.GetReprName() != _collection.GetReprName()
        || col.IsForcedRepr() != _collection.IsForcedRepr()
        || col.GetRenderTags() != _collection.GetRenderTags()) {
        return false;
    }

    // Also don't attempt to fix-up dirty lists when the collection is radically
    // different in terms of root paths; here a heuristic of 100 root paths is
    // used as a threshold for when we will stop attempting to fix the list.
    if (std::abs(int(col.GetRootPaths().size()) -
                 int(_collection.GetRootPaths().size())) > 100) {
        return false;
    }

    // If the either the old or new collection has Exclude paths do
    // the full rebuild.
    if (!col.GetExcludePaths().empty() ||
        !_collection.GetExcludePaths().empty()) {
        return false;
    }

    // If the varying state has changed - Rebuild the base list
    // before adding the new items
    HdChangeTracker &changeTracker = _renderIndex.GetChangeTracker();

    unsigned int currentVaryingStateVersion =
                                         changeTracker.GetVaryingStateVersion();

    if (_varyingStateVersion != currentVaryingStateVersion) {
           TF_DEBUG(HD_DIRTY_LIST).Msg("DirtyList(%p): varying state changed "
                   "(%s, %d -> %d)\n",
                   (void*)this,
                   _collection.GetName().GetText(),
                   _varyingStateVersion,
                   currentVaryingStateVersion);

           // populate only varying prims in the collection
           _UpdateIDs(&_dirtyIds, HdChangeTracker::Varying);
           _varyingStateVersion = currentVaryingStateVersion;
    }

    SdfPathVector added, removed;
    typedef SdfPathVector::const_iterator ITR;
    ITR newI = col.GetRootPaths().cbegin();
    ITR newEnd = col.GetRootPaths().cend();
    ITR oldI = _collection.GetRootPaths().cbegin();
    ITR oldEnd = _collection.GetRootPaths().cend();
    HdRenderIndex& index = _renderIndex;
    TfToken const & repr = col.GetReprName();

    TF_DEBUG(HD_DIRTY_LIST).Msg("DirtyList(%p): ApplyEdit\n", (void*)this);

    if (TfDebug::IsEnabled(HD_DIRTY_LIST)) {
        std::cout << "  Old Collection: " << std::endl;
        for (auto const& i : _collection.GetRootPaths()) {
            std::cout << "    " << i << std::endl;
        }
        std::cout << "  Old _dirtyIds: " << std::endl;
        for (auto const& i : _dirtyIds) {
            std::cout << "    " << i << std::endl;
        }
    }

    const SdfPathVector &paths = _renderIndex.GetRprimIds();

    while (newI != newEnd || oldI != oldEnd) {
        if (newI != newEnd && oldI != oldEnd && *newI == *oldI) {
            ++newI;
            ++oldI;
            continue;
        }
        // If any paths in the two sets are prefixed by one another, the logic
        // below doesn't work, since the subtree has to be fixed up (it's not
        // just a simple prefix scan). In these cases, we'll just rebuild the
        // entire list.
        if (newI != newEnd && oldI != oldEnd && newI->HasPrefix(*oldI)) {
            return false;          
        }
        if (newI != newEnd && oldI != oldEnd && oldI->HasPrefix(*newI)) {
            return false;          
        }
        if (newI != newEnd && (oldI == oldEnd || *newI < *oldI)) {
            HdPrimGather gather;

            SdfPathVector newPaths;
            gather.Subtree(paths, *newI, &newPaths);

            size_t numNewPaths = newPaths.size();
            for (size_t newPathNum = 0;
                        newPathNum < numNewPaths;
                      ++newPathNum) {
                const SdfPath &newPath = newPaths[newPathNum];

                if (col.HasRenderTag(index.GetRenderTag(newPath, repr))) {
                    _dirtyIds.push_back(newPath);
                    changeTracker.MarkRprimDirty(newPath,
                                                 HdChangeTracker::InitRepr);
                }
            }
            ++newI;
        } else if (oldI != oldEnd) { 
            // oldI < newI: Item removed in new list
            SdfPath const& oldPath = *oldI;
            _dirtyIds.erase(std::remove_if(_dirtyIds.begin(), _dirtyIds.end(), 
                  [&oldPath](SdfPath const& p){return p.HasPrefix(oldPath);}),
                  _dirtyIds.end());
            ++oldI;
        }
    }

    _collection = col;
    _collectionVersion
                    = changeTracker.GetCollectionVersion(_collection.GetName());


    // make sure the next GetDirtyRprims() picks up the updated list.
    _isEmpty = false;

    if (TfDebug::IsEnabled(HD_DIRTY_LIST)) {
        std::cout << "  New Collection: " << std::endl;
        for (auto const& i : _collection.GetRootPaths()) {
            std::cout << "    " << i << std::endl;
        }
        std::cout << "  New _dirtyIds: " << std::endl;
        for (auto const& i : _dirtyIds) {
            std::cout << "    " << i << std::endl;
        }
    }

    return true;
}
Beispiel #17
0
SdfPathVector
SdfPath::GetConciseRelativePaths(const SdfPathVector& paths) {

    SdfPathVector primPaths;
    SdfPathVector anchors;
    SdfPathVector labels;

    // initialize the vectors
    TF_FOR_ALL(iter, paths) {

        if(!iter->IsAbsolutePath()) {
            TF_WARN("argument to GetConciseRelativePaths contains a relative path.");
            return paths;
        }

        // first, get the prim paths
        SdfPath primPath = iter->GetPrimPath();
        SdfPath anchor = primPath.GetParentPath();

        primPaths.push_back(primPath);
        anchors.push_back(anchor);

        // we have to special case root anchors, since MakeRelativePath can't handle them
        if(anchor == SdfPath::AbsoluteRootPath())
          labels.push_back(primPath);
        else
          labels.push_back(primPath.MakeRelativePath(anchor));

    }

    // each ambiguous path must be raised to its parent
    bool ambiguous;
    do {

        ambiguous = false;

        // the next iteration of labels
        SdfPathVector newAnchors;
        SdfPathVector newLabels;

        // find ambiguous labels
        for(size_t i=0;i<labels.size();++i) {

           int ok = true;

           // search for some other path that makes this one ambiguous
           for(size_t j=0;j<labels.size();++j) {
              if(i != j && labels[i] == labels[j] && primPaths[i] != primPaths[j]) {
                  ok = false;
                  break;
              }
           }

           if(!ok) {

               // walk the anchor up one node
               SdfPath newAnchor = anchors[i].GetParentPath();

               newAnchors.push_back(newAnchor);
               newLabels.push_back( newAnchor == SdfPath::AbsoluteRootPath() ? primPaths[i]
                                       : primPaths[i].MakeRelativePath( newAnchor ) );
               ambiguous = true;

           } else {
               newAnchors.push_back(anchors[i]);
               newLabels.push_back(labels[i]);
           }

        }

        anchors = newAnchors;
        labels = newLabels;

    } while(ambiguous);

    // generate the final set from the anchors
    SdfPathVector result;

    for(size_t i=0; i<anchors.size();++i) {

       if(anchors[i] == SdfPath::AbsoluteRootPath()) {
          result.push_back( paths[i] );
       } else {
          result.push_back( paths[i].MakeRelativePath( anchors[i] ));
       }

    }

    return result;

}
Beispiel #18
0
bool
UsdGeomPointInstancer::ComputeInstanceTransformsAtTime(
    VtArray<GfMatrix4d>* xforms,
    const UsdTimeCode time,
    const UsdTimeCode baseTime,
    const ProtoXformInclusion doProtoXforms,
    const MaskApplication applyMask) const
{
    // XXX: Need to add handling of velocities/angularVelocities and baseTime.
    (void)baseTime;

    if (!xforms) {
        TF_WARN("%s -- null container passed to ComputeInstanceTransformsAtTime()",
                GetPrim().GetPath().GetText());
        return false;
    }

    VtIntArray protoIndices;
    if (!GetProtoIndicesAttr().Get(&protoIndices, time)) {
        TF_WARN("%s -- no prototype indices",
                GetPrim().GetPath().GetText());
        return false;
    }

    if (protoIndices.empty()) {
        xforms->clear();
        return true;
    }

    VtVec3fArray positions;
    if (!GetPositionsAttr().Get(&positions, time)) {
        TF_WARN("%s -- no positions",
                GetPrim().GetPath().GetText());
        return false;
    }

    if (positions.size() != protoIndices.size()) {
        TF_WARN("%s -- positions.size() [%zu] != protoIndices.size() [%zu]",
                GetPrim().GetPath().GetText(),
                positions.size(),
                protoIndices.size());
        return false;
    }

    VtVec3fArray scales;
    GetScalesAttr().Get(&scales, time);
    if (!scales.empty() && scales.size() != protoIndices.size()) {
        TF_WARN("%s -- scales.size() [%zu] != protoIndices.size() [%zu]",
                GetPrim().GetPath().GetText(),
                scales.size(),
                protoIndices.size());
        return false;
    }

    VtQuathArray orientations;
    GetOrientationsAttr().Get(&orientations, time);
    if (!orientations.empty() && orientations.size() != protoIndices.size()) {
        TF_WARN("%s -- orientations.size() [%zu] != protoIndices.size() [%zu]",
                GetPrim().GetPath().GetText(),
                orientations.size(),
                protoIndices.size());
        return false;
    }

    // If we're going to include the prototype transforms, verify that we have
    // prototypes and that all of the protoIndices are in bounds.
    SdfPathVector protoPaths;
    if (doProtoXforms == IncludeProtoXform) {
        const UsdRelationship prototypes = GetPrototypesRel();
        if (!prototypes.GetTargets(&protoPaths) || protoPaths.empty()) {
            TF_WARN("%s -- no prototypes",
                    GetPrim().GetPath().GetText());
            return false;
        }

        TF_FOR_ALL(iter, protoIndices) {
            const int protoIndex = *iter;
            if (protoIndex < 0 || static_cast<size_t>(protoIndex) >= protoPaths.size()) {
                TF_WARN("%s -- invalid prototype index: %d. Should be in [0, %zu)",
                        GetPrim().GetPath().GetText(),
                        protoIndex,
                        protoPaths.size());
                return false;
            }
        }
    }

    // Compute the mask only if applyMask says we should, otherwise we leave
    // mask empty so that its application below is a no-op.
    std::vector<bool> mask;
    if (applyMask == ApplyMask) {
        mask = ComputeMaskAtTime(time);
        if (!mask.empty() && mask.size() != protoIndices.size()) {
            TF_WARN("%s -- mask.size() [%zu] != protoIndices.size() [%zu]",
                    GetPrim().GetPath().GetText(),
                    mask.size(),
                    protoIndices.size());
            return false;
        }
    }

    UsdStageWeakPtr stage = GetPrim().GetStage();
    UsdGeomXformCache xformCache(time);

    xforms->assign(protoIndices.size(), GfMatrix4d(1.0));
    for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
        if (!mask.empty() && !mask[instanceId]) {
            continue;
        }

        GfTransform instanceTransform;

        if (!scales.empty()) {
            instanceTransform.SetScale(scales[instanceId]);
        }

        if (!orientations.empty()) {
            instanceTransform.SetRotation(GfRotation(orientations[instanceId]));
        }

        instanceTransform.SetTranslation(positions[instanceId]);

        GfMatrix4d protoXform(1.0);
        if (doProtoXforms == IncludeProtoXform) {
            const int protoIndex = protoIndices[instanceId];
            const SdfPath& protoPath = protoPaths[protoIndex];
            const UsdPrim& protoPrim = stage->GetPrimAtPath(protoPath);
            if (protoPrim) {
                // Get the prototype's local transformation.
                bool resetsXformStack;
                protoXform = xformCache.GetLocalTransformation(protoPrim,
                                                               &resetsXformStack);
            }
        }

        (*xforms)[instanceId] = protoXform * instanceTransform.GetMatrix();
    }

    return ApplyMaskToArray(mask, xforms);
}
Beispiel #19
0
bool
UsdGeomPointInstancer::ComputeExtentAtTime(
    VtVec3fArray* extent,
    const UsdTimeCode time,
    const UsdTimeCode baseTime) const
{
    if (!extent) {
        TF_WARN("%s -- null container passed to ComputeExtentAtTime()",
                GetPrim().GetPath().GetText());
        return false;
    }

    VtIntArray protoIndices;
    if (!GetProtoIndicesAttr().Get(&protoIndices, time)) {
        TF_WARN("%s -- no prototype indices",
                GetPrim().GetPath().GetText());
        return false;
    }

    const std::vector<bool> mask = ComputeMaskAtTime(time);
    if (!mask.empty() && mask.size() != protoIndices.size()) {
        TF_WARN("%s -- mask.size() [%zu] != protoIndices.size() [%zu]",
                GetPrim().GetPath().GetText(),
                mask.size(),
                protoIndices.size());
        return false;
    }

    const UsdRelationship prototypes = GetPrototypesRel();
    SdfPathVector protoPaths;
    if (!prototypes.GetTargets(&protoPaths) || protoPaths.empty()) {
        TF_WARN("%s -- no prototypes",
                GetPrim().GetPath().GetText());
        return false;
    }

    // verify that all the protoIndices are in bounds.
    TF_FOR_ALL(iter, protoIndices) {
        const int protoIndex = *iter;
        if (protoIndex < 0 || 
            static_cast<size_t>(protoIndex) >= protoPaths.size()) {
            TF_WARN("%s -- invalid prototype index: %d. Should be in [0, %zu)",
                    GetPrim().GetPath().GetText(),
                    protoIndex,
                    protoPaths.size());
            return false;
        }
    }

    // Note that we do NOT apply any masking when computing the instance
    // transforms. This is so that for a particular instance we can determine
    // both its transform and its prototype. Otherwise, the instanceTransforms
    // array would have masked instances culled out and we would lose the
    // mapping to the prototypes.
    // Masked instances will be culled before being applied to the extent below.
    VtMatrix4dArray instanceTransforms;
    if (!ComputeInstanceTransformsAtTime(&instanceTransforms,
                                         time,
                                         baseTime,
                                         IncludeProtoXform,
                                         IgnoreMask)) {
        TF_WARN("%s -- could not compute instance transforms",
                GetPrim().GetPath().GetText());
        return false;
    }

    UsdStageWeakPtr stage = GetPrim().GetStage();
    const TfTokenVector purposes {
        UsdGeomTokens->default_,
        UsdGeomTokens->proxy,
        UsdGeomTokens->render
    };
    UsdGeomBBoxCache bboxCache(time, purposes);
    bboxCache.SetTime(time);

    GfRange3d extentRange;

    for (size_t instanceId = 0; instanceId < protoIndices.size(); ++instanceId) {
        if (!mask.empty() && !mask[instanceId]) {
            continue;
        }

        const int protoIndex = protoIndices[instanceId];
        const SdfPath& protoPath = protoPaths[protoIndex];
        const UsdPrim& protoPrim = stage->GetPrimAtPath(protoPath);

        // Get the prototype bounding box.
        GfBBox3d thisBounds = bboxCache.ComputeUntransformedBound(protoPrim);

        // Apply the instance transform.
        thisBounds.Transform(instanceTransforms[instanceId]);
        extentRange.UnionWith(thisBounds.ComputeAlignedRange());
    }

    const GfVec3d extentMin = extentRange.GetMin();
    const GfVec3d extentMax = extentRange.GetMax();

    *extent = VtVec3fArray(2);
    (*extent)[0] = GfVec3f(extentMin[0], extentMin[1], extentMin[2]);
    (*extent)[1] = GfVec3f(extentMax[0], extentMax[1], extentMax[2]);

    return true;
}
Beispiel #20
0
static FnKat::Attribute
_GetMaterialAssignAttr(
        const UsdPrim& prim,
        const PxrUsdKatanaUsdInPrivateData& data)
{
    if (not prim or prim.GetPath() == SdfPath::AbsoluteRootPath()) {
        // Special-case to pre-empt coding errors.
        return FnKat::Attribute();
    }

    UsdRelationship usdRel = UsdShadeLook::GetBindingRel(prim);
    if (usdRel) {
        // USD shading binding
        SdfPathVector targetPaths;
        usdRel.GetForwardedTargets(&targetPaths);
        if (targetPaths.size() > 0) {
            if (not targetPaths[0].IsPrimPath()) {
                FnLogWarn("Target path " << prim.GetPath().GetString() <<
                          " is not a prim");
                return FnKat::Attribute();
            }

            // This is a copy as it could be modified below.
            SdfPath targetPath = targetPaths[0];
            UsdPrim targetPrim = data.GetUsdInArgs()->GetStage()->GetPrimAtPath(targetPath);
            // If the target is inside a master, then it needs to be re-targeted 
            // to the instance.
            // 
            // XXX remove this special awareness once GetMasterWithContext is
            //     is available as the provided prim will automatically
            //     retarget (or provide enough context to retarget without
            //     tracking manually).
            if (targetPrim and targetPrim.IsInMaster()) {
                if (not data.GetInstancePath().IsEmpty() and 
                        not data.GetMasterPath().IsEmpty()) {

                    // Check if the source and the target of the relationship 
                    // belong to the same master.
                    // If they do, we have the context necessary to do the 
                    // re-mapping.
                    if (data.GetMasterPath().GetCommonPrefix(targetPath).
                            GetPathElementCount() > 0) {
                        targetPath = data.GetInstancePath().AppendPath(
                            targetPath.ReplacePrefix(targetPath.GetPrefixes()[0],
                                SdfPath::ReflexiveRelativePath()));
                    } else {
                        // Warn saying the target of relationship isn't within 
                        // the same master as the source.
                        FnLogWarn("Target path " << prim.GetPath().GetString() 
                            << " isn't within the master " << data.GetMasterPath());
                        return FnKat::Attribute();
                    }
                } else {
                    // XXX
                    // When loading beneath a master via an isolatePath
                    // opArg, we can encounter targets which are within masters
                    // but not within the context of a material.
                    // While that would be an error according to the below
                    // warning, it produces the expected results.
                    // This case can occur when expanding pointinstancers as
                    // the sources are made via execution of PxrUsdIn again
                    // at the sub-trees.
                    
                    
                    // Warn saying target of relationship is in a master, 
                    // but the associated instance path is unknown!
                    // FnLogWarn("Target path " << prim.GetPath().GetString() 
                    //         << " is within a master, but the associated "
                    //         "instancePath is unknown.");
                    // return FnKat::Attribute();
                }
            }

            // Convert the target path to the equivalent katana location.
            // XXX: Looks may have an atypical USD->Katana 
            // path mapping
            std::string location =
                PxrUsdKatanaUtils::ConvertUsdLookPathToKatLocation(targetPath, data);
                
            // XXX Looks containing only display terminals are causing issues
            //     with katana material manipulation workflows.
            //     For now: exclude any material assign which doesn't include
            //     /Looks/ in the path
            if (location.find(UsdKatanaTokens->katanaLooksScopePathSubstring)
                    == std::string::npos)
            {
                return FnKat::Attribute();
            }
                
                
            // location = TfStringReplace(location, "/Looks/", "/Materials/");
            // XXX handle multiple assignments
            return FnKat::StringAttribute(location);
        }
    }

    return FnKat::Attribute();
}