예제 #1
0
파일: mesh.cpp 프로젝트: mplanck/USD
// For now, this is only used by the mesh op.  If this logic needs to be
// accessed elsewhere, it should move down into usdKatana.
static void 
_CreateFaceSetsFromFaceSetAPI(
        const UsdPrim& prim,
        const PxrUsdKatanaUsdInPrivateData &data,
        FnKat::GeolibCookInterface& interface)
{
    UsdGeomFaceSetAPI faceSet = UsdShadeMaterial::GetMaterialFaceSet(prim);
    bool isPartition = faceSet.GetIsPartition();;
    if (!isPartition) {
        TF_WARN("Found face set on prim <%s> that is not a partition.", 
                prim.GetPath().GetText());
        // continue here?
    }

    const double currentTime = data.GetCurrentTime();

    VtIntArray faceCounts, faceIndices;
    faceSet.GetFaceCounts(&faceCounts, currentTime);
    faceSet.GetFaceIndices(&faceIndices, currentTime);

    SdfPathVector bindingTargets;
    faceSet.GetBindingTargets(&bindingTargets);

    size_t faceSetIdxStart = 0;
    for(size_t faceSetIdx = 0; faceSetIdx < faceCounts.size(); ++faceSetIdx) {
        size_t faceCount = faceCounts[faceSetIdx];

        FnKat::GroupBuilder faceSetAttrs;

        faceSetAttrs.set("type", FnKat::StringAttribute("faceset"));
        faceSetAttrs.set("materialAssign", FnKat::StringAttribute(
            PxrUsdKatanaUtils::ConvertUsdMaterialPathToKatLocation(
                bindingTargets[faceSetIdx], data)));

        FnKat::IntBuilder facesBuilder;
        {
            std::vector<int> faceIndicesVec(faceCount);
            for (size_t faceIndicesIdx = 0; faceIndicesIdx < faceCount; ++faceIndicesIdx)
            {
                faceIndicesVec[faceIndicesIdx] = 
                    faceIndices[faceSetIdxStart + faceIndicesIdx];
            }
            faceSetIdxStart += faceCount;
            facesBuilder.set(faceIndicesVec);
        }
        faceSetAttrs.set("geometry.faces", facesBuilder.build());

        std::string faceSetName = TfStringPrintf("faceset_%zu", faceSetIdx);

        FnKat::GroupBuilder staticSceneCreateAttrs;
        staticSceneCreateAttrs.set("a", faceSetAttrs.build());
        interface.createChild(
            faceSetName,
            "StaticSceneCreate",
            staticSceneCreateAttrs.build());
    }
}
예제 #2
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));
    }
}
예제 #3
0
void
PxrUsdKatanaReadLightFilter(
        const UsdLuxLightFilter& lightFilter,
        const PxrUsdKatanaUsdInPrivateData& data,
        PxrUsdKatanaAttrMap& attrs)
{
    const UsdPrim filterPrim = lightFilter.GetPrim();
    const SdfPath primPath = filterPrim.GetPath();
    const double currentTime = data.GetCurrentTime();

    GroupBuilder materialBuilder;
    GroupBuilder filterBuilder;
    _UsdBuilder usdBuilder = {filterBuilder, currentTime};
    
    if (UsdRiLightFilterAPI f = UsdRiLightFilterAPI(filterPrim)) {
        usdBuilder
            .Set("density", f.GetRiDensityAttr())
            .Set("intensity", f.GetRiIntensityAttr())
            .Set("exposure", f.GetRiExposureAttr())
            .Set("invert", f.GetRiInvertAttr())
            .Set("diffuse", f.GetRiDiffuseAttr())
            .Set("specular", f.GetRiSpecularAttr())
            ;

        // combineMode
        {
            VtValue val;
            UsdAttribute attr = f.GetRiCombineModeAttr();
            if (attr.IsValid() && attr.HasAuthoredValueOpinion()
                && attr.Get(&val, currentTime) && val.IsHolding<TfToken>()) {
                TfToken t = val.Get<TfToken>();
                if (t == UsdRiTokens->multiply) {
                    filterBuilder.set("combineMode",
                                      FnKat::StringAttribute("mult"));
                } else if (t == UsdRiTokens->max) {
                    filterBuilder.set("combineMode",
                                      FnKat::StringAttribute("max"));
                } else if (t == UsdRiTokens->min) {
                    filterBuilder.set("combineMode",
                                      FnKat::StringAttribute("min"));
                } else if (t == UsdRiTokens->screen) {
                    filterBuilder.set("combineMode",
                                      FnKat::StringAttribute("screen"));
                }
            }
        }
    }
    if (UsdRiPxrIntMultLightFilter f = UsdRiPxrIntMultLightFilter(filterPrim)) {
        materialBuilder.set("prmanLightfilterShader",
                            FnKat::StringAttribute("PxrIntMultLightFilter"));
    }
    if (UsdRiPxrBarnLightFilter f = UsdRiPxrBarnLightFilter(filterPrim)) {
        materialBuilder.set("prmanLightfilterShader",
                            FnKat::StringAttribute("PxrBarnLightFilter"));
        usdBuilder
            .Set("directional", f.GetAnalyticDirectionalAttr())
            .Set("shearX", f.GetAnalyticShearXAttr())
            .Set("shearY", f.GetAnalyticShearYAttr())
            .Set("apex", f.GetAnalyticApexAttr())
            .Set("useLightDirection", f.GetAnalyticDirectionalAttr())
            .Set("width", f.GetWidthAttr())
            .Set("height", f.GetHeightAttr())
            .Set("radius", f.GetRadiusAttr())
            .Set("edge", f.GetEdgeThicknessAttr())
            .Set("scaleWidth", f.GetScaleWidthAttr())
            .Set("scaleHeight", f.GetScaleHeightAttr())
            .Set("left", f.GetRefineLeftAttr())
            .Set("right", f.GetRefineRightAttr())
            .Set("top", f.GetRefineTopAttr())
            .Set("bottom", f.GetRefineBottomAttr())
            .Set("leftEdge", f.GetEdgeLeftAttr())
            .Set("rightEdge", f.GetEdgeRightAttr())
            .Set("topEdge", f.GetEdgeTopAttr())
            .Set("bottomEdge", f.GetEdgeBottomAttr())
            .Set("densityNear", f.GetAnalyticDensityNearDistanceAttr())
            .Set("densityNearVal", f.GetAnalyticDensityNearValueAttr())
            .Set("densityFar", f.GetAnalyticDensityFarDistanceAttr())
            .Set("densityFarVal", f.GetAnalyticDensityFarValueAttr())
            .Set("densityPow", f.GetAnalyticDensityExponentAttr())
            ;

        // barnMode 
        {
            VtValue val;
            UsdAttribute attr = f.GetBarnModeAttr();
            if (attr.IsValid() && attr.HasAuthoredValueOpinion()
                && attr.Get(&val, currentTime) && val.IsHolding<TfToken>()) {
                TfToken t = val.Get<TfToken>();
                if (t == UsdRiTokens->analytic) {
                    filterBuilder.set("barnMode", FnKat::IntAttribute(1));
                } else if (t == UsdRiTokens->physical) {
                    filterBuilder.set("barnMode", FnKat::IntAttribute(0));
                }
            }
        }
        // preBarn
        {
            VtValue val;
            UsdAttribute attr = f.GetPreBarnEffectAttr();
            if (attr.IsValid() && attr.HasAuthoredValueOpinion()
                && attr.Get(&val, currentTime) && val.IsHolding<TfToken>()) {
                TfToken t = val.Get<TfToken>();
                if (t == UsdRiTokens->noEffect) {
                    filterBuilder.set("preBarn", FnKat::IntAttribute(0));
                } else if (t == UsdRiTokens->cone) {
                    filterBuilder.set("preBarn", FnKat::IntAttribute(1));
                } else if (t == UsdRiTokens->noLight) {
                    filterBuilder.set("preBarn", FnKat::IntAttribute(2));
                }
            }
        }
    }
    if (UsdRiPxrCookieLightFilter f = UsdRiPxrCookieLightFilter(filterPrim)) {
        materialBuilder.set("prmanLightfilterShader",
                            FnKat::StringAttribute("PxrCookieLightFilter"));
        // cookieMode 
        {
            VtValue val;
            UsdAttribute attr = f.GetCookieModeAttr();
            if (attr.IsValid() && attr.HasAuthoredValueOpinion()
                && attr.Get(&val, currentTime) && val.IsHolding<TfToken>()) {
                TfToken t = val.Get<TfToken>();
                if (t == UsdRiTokens->analytic) {
                    filterBuilder.set("cookieMode", FnKat::IntAttribute(1));
                } else if (t == UsdRiTokens->physical) {
                    filterBuilder.set("cookieMode", FnKat::IntAttribute(0));
                }
            }
        }
        // tileMode
        {
            VtValue val;
            UsdAttribute attr = f.GetTextureWrapModeAttr();
            if (attr.IsValid() && attr.HasAuthoredValueOpinion()
                && attr.Get(&val, currentTime) && val.IsHolding<TfToken>()) {
                TfToken t = val.Get<TfToken>();
                if (t == UsdRiTokens->off) {
                    filterBuilder.set("tileMode", FnKat::IntAttribute(0));
                } else if (t == UsdRiTokens->repeat) {
                    filterBuilder.set("tileMode", FnKat::IntAttribute(2));
                } else if (t == UsdRiTokens->clamp) {
                    filterBuilder.set("tileMode", FnKat::IntAttribute(1));
                }
            }
        }
        usdBuilder
            .Set("map", f.GetTextureMapAttr())
            .Set("fillColor", f.GetTextureFillColorAttr())
            .Set("width", f.GetWidthAttr())
            .Set("height", f.GetHeightAttr())
            .Set("directional", f.GetAnalyticDirectionalAttr())
            .Set("shearX", f.GetAnalyticShearXAttr())
            .Set("shearY", f.GetAnalyticShearYAttr())
            .Set("apex", f.GetAnalyticApexAttr())
            .Set("useLightDirection", f.GetAnalyticDirectionalAttr())
            .Set("invertU", f.GetTextureInvertUAttr())
            .Set("invertV", f.GetTextureInvertVAttr())
            .Set("scaleU", f.GetTextureScaleUAttr())
            .Set("scaleV", f.GetTextureScaleVAttr())
            .Set("offsetU", f.GetTextureOffsetUAttr())
            .Set("offsetV", f.GetTextureOffsetVAttr())
            .Set("blur", f.GetAnalyticBlurAmountAttr())
            .Set("sBlurMult", f.GetAnalyticBlurSMultAttr())
            .Set("tBlurMult", f.GetAnalyticBlurTMultAttr())
            .Set("blurNearDist", f.GetAnalyticBlurNearDistanceAttr())
            .Set("blurNearVal", f.GetAnalyticBlurNearValueAttr())
            .Set("blurFarDist", f.GetAnalyticBlurFarDistanceAttr())
            .Set("blurFarVal", f.GetAnalyticBlurFarValueAttr())
            .Set("blurMidpoint", f.GetAnalyticBlurMidpointAttr())
            .Set("blurMidVal", f.GetAnalyticBlurMidValueAttr())
            .Set("blurPow", f.GetAnalyticBlurExponentAttr())
            .Set("densityNearDist", f.GetAnalyticDensityNearDistanceAttr())
            .Set("densityNearVal", f.GetAnalyticDensityNearValueAttr())
            .Set("densityFarDist", f.GetAnalyticDensityFarDistanceAttr())
            .Set("densityFarVal", f.GetAnalyticDensityFarValueAttr())
            .Set("densityMidpoint", f.GetAnalyticDensityMidpointAttr())
            .Set("densityMidVal", f.GetAnalyticDensityMidValueAttr())
            .Set("densityPow", f.GetAnalyticDensityExponentAttr())
            .Set("saturation", f.GetColorSaturationAttr())
            .Set("midpoint", f.GetColorMidpointAttr())
            .Set("contrast", f.GetColorContrastAttr())
            .Set("whitepoint", f.GetColorWhitepointAttr())
            .Set("tint", f.GetColorTintAttr())
            ;
    }
    if (UsdRiPxrRampLightFilter f = UsdRiPxrRampLightFilter(filterPrim)) {
        materialBuilder.set("prmanLightfilterShader",
                            FnKat::StringAttribute("PxrRampLightFilter"));
        usdBuilder
            .Set("beginDist", f.GetFalloffRampBeginDistanceAttr())
            .Set("endDist", f.GetFalloffRampEndDistanceAttr())
            .SetSpline("colorRamp", "_Colors", f.GetColorRampAPI())
            .SetSpline("ramp", "_Floats", f.GetFalloffRampAPI())
            ;
        // rampMode
        {
            VtValue val;
            UsdAttribute attr = f.GetRampModeAttr();
            if (attr.IsValid() && attr.HasAuthoredValueOpinion()
                && attr.Get(&val, currentTime) && val.IsHolding<TfToken>()) {
                TfToken t = val.Get<TfToken>();
                if (t == UsdRiTokens->distanceToLight) {
                    filterBuilder.set("rampMode", FnKat::IntAttribute(0));
                } else if (t == UsdRiTokens->linear) {
                    filterBuilder.set("rampMode", FnKat::IntAttribute(1));
                } else if (t == UsdRiTokens->spherical) {
                    filterBuilder.set("rampMode", FnKat::IntAttribute(2));
                } else if (t == UsdRiTokens->radial) {
                    filterBuilder.set("rampMode", FnKat::IntAttribute(3));
                }
            }
        }
    }
    if (UsdRiPxrRodLightFilter f = UsdRiPxrRodLightFilter(filterPrim)) {
        materialBuilder.set("prmanLightfilterShader",
                            FnKat::StringAttribute("PxrRodLightFilter"));
        usdBuilder
            .Set("width", f.GetWidthAttr())
            .Set("height", f.GetHeightAttr())
            .Set("depth", f.GetDepthAttr())
            .Set("radius", f.GetRadiusAttr())
            .Set("edge", f.GetEdgeThicknessAttr())
            .Set("scaleWidth", f.GetScaleWidthAttr())
            .Set("scaleHeight", f.GetScaleHeightAttr())
            .Set("scaleDepth", f.GetScaleDepthAttr())
            .Set("left", f.GetRefineLeftAttr())
            .Set("right", f.GetRefineRightAttr())
            .Set("top", f.GetRefineTopAttr())
            .Set("bottom", f.GetRefineBottomAttr())
            .Set("front", f.GetRefineFrontAttr())
            .Set("back", f.GetRefineBackAttr())
            .Set("leftEdge", f.GetEdgeLeftAttr())
            .Set("rightEdge", f.GetEdgeRightAttr())
            .Set("topEdge", f.GetEdgeTopAttr())
            .Set("bottomEdge", f.GetEdgeBottomAttr())
            .Set("frontEdge", f.GetEdgeFrontAttr())
            .Set("backEdge", f.GetEdgeBackAttr())
            .Set("saturation", f.GetColorSaturationAttr())
            .SetSpline("colorRamp", "_Colors", f.GetColorRampAPI())
            .SetSpline("falloff", "_Floats", f.GetFalloffRampAPI())
            ;
    }

    // Gather prman statements
    FnKat::GroupBuilder prmanBuilder;
    PxrUsdKatanaReadPrimPrmanStatements(filterPrim, currentTime, prmanBuilder);
    attrs.set("prmanStatements", prmanBuilder.build());
    materialBuilder.set("prmanLightfilterParams", filterBuilder.build());
    attrs.set("material", materialBuilder.build());
    PxrUsdKatanaReadXformable(lightFilter, data, attrs);
    attrs.set("type", FnKat::StringAttribute("light filter"));
}