Trying to Understand this Warning: UsdImagingStageSceneIndex adapter invoked for UsdImagingDelegate skipping

Hi,

I’m currently migrating a custom UsdImaging adapter from Hydra 1.0 to Hydra 2.0 API for a custom schema prim. This prim is visualized as HdBasisCurves. However, I keep encountering the following warning and am trying to understand what it implies:

// Warning: UsdImagingStageSceneIndex adapter invoked for UsdImagingDelegate for prim </transform1>, skipping...

There are not many examples out there but I think I have implemented everything correctly based on my current understanding":

So first, I created a custom data source to provide the point data:

constexpr const auto kSegmentsPerRing = 16; 
constexpr const auto kNumRings      = 1;
constexpr const auto kPointsPerSeg  = 3; // cubic Bezier: p0, cp1, cp2
constexpr const auto kVertsPerRing  = kSegmentsPerRing * kPointsPerSeg;
constexpr const auto kTotalPoints   = kNumRings * kVertsPerRing;
constexpr const auto kRadius        = 1.0f;
const           auto kKappa         = (4.0f / 3.0f) * std::tan(std::numbers::pi / (2.0f * kSegmentsPerRing));

class RingNodePointsDataSource : public HdTypedSampledDataSource
{
public:
HD_DECLARE_DATASOURCE(RingNodePointsDataSource);

PXR_NS::VtValue GetValue(HdSampledDataSource::Time shutterOffset) override {
  return PXR_NS::VtValue(GetTypedValue(shutterOffset));
}

bool GetContributingSampleTimesForInterval(
    HdSampledDataSource::Time startTime, 
    HdSampledDataSource::Time endTime, 
    std::vector<HdSampledDataSource::Time> *outSampleTimes) override 
{
    return false; 
}

PXR_NS::VtVec3fArray GetTypedValue(HdSampledDataSource::Time shutterOffset) override
{
    PXR_NS::VtVec3fArray points;
    points.reserve(kTotalPoints);

    ...

    return points;
}

};

My adapter then derives from UsdImagingSceneIndexPrimAdapter and implements all required functions.

In GetImagingSubprimData, I construct:

  • HdBasisCurves topology (cubic, bezier, periodic)

  • points primvar via my custom data source

class RingNodeAdapter : public PXR_NS::UsdImagingSceneIndexPrimAdapter
{
public:
using BaseAdapter = PXR_NS::UsdImagingSceneIndexPrimAdapter;

PXR_NS::TfTokenVector GetImagingSubprims(const PXR_NS::UsdPrim& prim) override;

PXR_NS::TfToken GetImagingSubprimType(const PXR_NS::UsdPrim& prim, 
                                      const PXR_NS::TfToken& subprim) override;

PXR_NS::HdContainerDataSourceHandle GetImagingSubprimData(
    const PXR_NS::UsdPrim& prim,
    const PXR_NS::TfToken& subprim,
    const PXR_NS::UsdImagingDataSourceStageGlobals& stageGlobals) override;

PXR_NS::HdDataSourceLocatorSet InvalidateImagingSubprim(
    const PXR_NS::UsdPrim& prim,
    const PXR_NS::TfToken& subprim,
    const PXR_NS::TfTokenVector& properties,
    PXR_NS::UsdImagingPropertyInvalidationType invalidationType) override;

};

TfTokenVector 
RingNodeAdapter::GetImagingSubprims(const UsdPrim& prim) {
    return { TfToken() };
}

TfToken 
RingNodeAdapter::GetImagingSubprimType(const UsdPrim& prim, const TfToken& subprim) 
{
    return HdPrimTypeTokens->basisCurves;
}

PXR_NS::HdContainerDataSourceHandle
RingNodeAdapter::GetImagingSubprimData(PXR_NS::UsdPrim const& prim,
    PXR_NS::TfToken const& subprim,
    const PXR_NS::UsdImagingDataSourceStageGlobals& stageGlobals)
{
    // Build Topology
    auto topologySource = PXR_NS::HdBasisCurvesTopologySchema::Builder()
        .SetCurveVertexCounts(PXR_NS::HdRetainedTypedSampledDataSource<PXR_NS::VtIntArray>::New(
            PXR_NS::VtIntArray(kNumRings, kVertsPerRing)))
        .SetBasis(PXR_NS::HdRetainedTypedSampledDataSource<PXR_NS::TfToken>::New(PXR_NS::HdTokens->bezier))
        .SetType(PXR_NS::HdRetainedTypedSampledDataSource<PXR_NS::TfToken>::New(PXR_NS::HdTokens->cubic))
        .SetWrap(PXR_NS::HdRetainedTypedSampledDataSource<PXR_NS::TfToken>::New(PXR_NS::HdTokens->periodic))
        .Build();

    // Build Primvars using RingNodePointsDataSource
    auto pointsPrimvar = PXR_NS::HdPrimvarSchema::Builder()
        .SetPrimvarValue(RingNodePointsDataSource::New())
        .SetInterpolation(PXR_NS::HdRetainedTypedSampledDataSource<PXR_NS::TfToken>::New(
            PXR_NS::HdPrimvarSchemaTokens->vertex))
        .SetRole(PXR_NS::HdRetainedTypedSampledDataSource<PXR_NS::TfToken>::New(
            PXR_NS::HdPrimvarSchemaTokens->point))
        .Build();

    auto primvars = PXR_NS::HdRetainedContainerDataSource::New(
        PXR_NS::HdPrimvarsSchemaTokens->points,
        pointsPrimvar
    );

    PXR_NS::UsdTimeCode time(stageGlobals.GetTime());
    PXR_NS::GfMatrix4d mat(1.0);
    PXR_NS::UsdGeomXformable xformable(prim);
    if (xformable) {
        bool resetsXformStack = false;
        xformable.GetLocalTransformation(&mat, &resetsXformStack, time);
    }

    return PXR_NS::HdRetainedContainerDataSource::New(
        PXR_NS::HdBasisCurvesSchemaTokens->basisCurves,
        PXR_NS::HdBasisCurvesSchema::Builder()
            .SetTopology(topologySource)
            .Build(),

        PXR_NS::HdPrimvarsSchemaTokens->primvars,
        primvars,

        // XFORM
        PXR_NS::HdXformSchemaTokens->xform,
        PXR_NS::HdXformSchema::Builder()
        .SetMatrix(
            PXR_NS::HdRetainedTypedSampledDataSource<
            PXR_NS::GfMatrix4d>::New(mat))
        .Build(),

        // VISIBILITY
        PXR_NS::HdVisibilitySchemaTokens->visibility,
        PXR_NS::HdVisibilitySchema::Builder()
            .SetVisibility(
                PXR_NS::HdRetainedTypedSampledDataSource<bool>::New(
                    PXR_NS::UsdGeomImageable(prim)
                        .ComputeVisibility(
                            PXR_NS::UsdTimeCode::Default()) 
                        != PXR_NS::UsdGeomTokens->invisible))
            .Build()
    );
}

PXR_NS::HdDataSourceLocatorSet RingNodeAdapter::InvalidateImagingSubprim(
    const PXR_NS::UsdPrim& prim,
    const PXR_NS::TfToken& subprim,
    const PXR_NS::TfTokenVector& properties,
    PXR_NS::UsdImagingPropertyInvalidationType invalidationType)
{
    PXR_NS::HdDataSourceLocatorSet locators;
        
    for (const PXR_NS::TfToken& propertyName : properties) {
        if (PXR_NS::UsdGeomXformable::IsTransformationAffectedByAttrNamed(propertyName)) {
            locators.insert(PXR_NS::HdXformSchema::GetDefaultLocator());
        } else if (propertyName == PXR_NS::UsdGeomTokens->visibility) {
            locators.insert(PXR_NS::HdVisibilitySchema::GetDefaultLocator());
        }
    }
    return locators;
}

I’ve registered the adapter as follows:

TF_REGISTRY_FUNCTION(TfType) {
    TfType t = TfType::Define<RingNodeAdapter, TfType::Bases<RingNodeAdapter::BaseAdapter>>();
    t.SetFactory<UsdImagingPrimAdapterFactory<RingNodeAdapter>>();
}

And in plugInfo.json:

"RingNodeAdapter": {
    "bases": [
        "UsdImagingSceneIndexPrimAdapter"
    ],
    "primTypeName": "RingNode"
}

and here is a minimal usd example:

#usda 1.0
(
    defaultPrim = "transform1"
)

def RingNode "transform1" (
)
{
}

Am I missing something required for Hydra 2.0 adapter registration? Is there an additional step that I am missing?

Any help is really appreciated.

-H

FWIW, this is my Hydra 1.0 implementation:

class RingNodeAdapter: public PXR_NS::UsdImagingPrimAdapter
PXR_NS::VtValue RingNodeAdapter::Get(const PXR_NS::UsdPrim& prim,
const PXR_NS::SdfPath& cachePath,
const PXR_NS::TfToken& key,
PXR_NS::UsdTimeCode time,
PXR_NS::VtIntArray* outIndices) const
{
if (key == PXR_NS::HdTokens->points) {
return PointsData(prim, time);
}

return BaseAdapter::Get(prim, cachePath, key, time, outIndices);

}

PXR_NS::VtValue RingNodeAdapter::GetTopology(const PXR_NS::UsdPrim& prim,
const PXR_NS::SdfPath& cachePath,
PXR_NS::UsdTimeCode time) const
{
PXR_NS::VtIntArray curveVertexCounts(kNumRings, kVertsPerRing);
PXR_NS::HdBasisCurvesTopology topo( PXR_NS::HdTokens->cubic,
PXR_NS::HdTokens->bezier,
PXR_NS::HdTokens->periodic,
curveVertexCounts,
PXR_NS::VtIntArray());
return PXR_NS::VtValue(topo);
}

PXR_NS::VtValue RingNodeAdapter::PointsData(const PXR_NS::UsdPrim& prim,
PXR_NS::UsdTimeCode timeCode) const
{
PXR_NS::VtVec3fArray points;
points.reserve(kTotalPoints);

....

return PXR_NS::VtValue(points);

}

this is what the rings looks like

Nvm, I figured it out. I needed to enable USDIMAGINGGL_ENGINE_ENABLE_TASK_SCENE_INDEX