Reading texture coords in from HdSceneIndexPrim

Hi All,

I’ve been experimenting with HdGpGenerativeProcedural and encountered a problem when trying to read textures coordinates from this mesh:

Input usd file:

def Xform "sopimport1" (
    kind = "component"
)
{
    def Mesh "mesh_0"
    {
        color3f[] primvars:displayColor = [(1, 0, 0)] (
            interpolation = "constant"
        )

        float3[] extent = [(-5, 0, -5), (5, 0, 5)]
        int[] faceVertexCounts = [4]
        int[] faceVertexIndices = [0, 1, 3, 2]
        normal3f[] normals = [(0, 1, 0), (0, 1, 0), (0, 1, 0), (0, 1, 0)] (
            interpolation = "vertex"
        )
        uniform token orientation = "leftHanded"
        point3f[] points = [(-5, 0, -5), (5, 0, -5), (-5, 0, 5), (5, 0, 5)] (
            interpolation = "vertex"
        )
        texCoord2f[] primvars:st = [(0, 0), (1, 0), (1, 1), (0, 1)] (
            interpolation = "faceVarying"
        )
        int[] primvars:st:indices = None
        uniform token purpose = "proxy"
        uniform token subdivisionScheme = "none"
    }

code fragment to read what’s in the HdSceneIndexPrim:

void someFunction(const HdSceneIndexPrim& indexPrim) {
    for (const auto& name: indexPrim.dataSource->GetNames()) {
      fmt::print("[genproc] data source name:'{}'\n", name.GetString());
    }     
    auto primvars = HdPrimvarsSchema::GetFromParent(indexPrim.dataSource);

    const HdSampledDataSource::Time t {0.0f};

    for(const auto& primvarName : primvars.GetPrimvarNames()) {
        fmt::print("[genproc] primvar name:'{}'\n", primvarName.GetString());
    }
}

Console Output:

[genproc] data source name:'mesh'
[genproc] data source name:'primvars'
[genproc] data source name:'extComputationPrimvars'
[genproc] data source name:'materialBindings'
[genproc] data source name:'displayStyle'
[genproc] data source name:'coordSysBinding'
[genproc] data source name:'purpose'
[genproc] data source name:'visibility'
[genproc] data source name:'categories'
[genproc] data source name:'xform'
[genproc] data source name:'extent'
[genproc] data source name:'instancedBy'
[genproc] data source name:'sceneDelegate'
[genproc] primvar name:'displayColor'
[genproc] primvar name:'points'
[genproc] primvar name:'normals

Also I should mention I’m triggering the code path by executing usdview which calls my HdGpGenerativeProcedural.

I would have expected to be able to read the st / uv coordinates using HdPrimvarsSchema. What am I missing?

Cheers
Don

Hi Don,

I am not 100% sure about that, but I think you need to subclass the default generative procedural scene index and handle the primvars by yourself.
Your HdGpGenerativeProcedural needs to create a proper primvars data source that includes the texture coordinate.

// In your HdGpGenerativeProcedural implementation
HdDataSourceBaseHandle CreatePrimvarsDataSource() {
// Read the texture coordinates from your USD file
VtVec2fArray stValues = GetTextureCoordinatesFromUSD(); // Your method to read from USD

// Create the primvars container data source
HdContainerDataSourceHandle primvarsDs = HdRetainedContainerDataSource::New(
    // Points primvar
    HdPrimvarsSchemaTokens->points,
    HdPrimvarSchema::Builder()
        .SetPrimvarValue(HdRetainedTypedSampledDataSource<VtVec3fArray>::New(GetPointsFromUSD()))
        .SetInterpolation(HdPrimvarSchema::BuildInterpolationDataSource(HdPrimvarSchemaTokens->vertex))
        .SetRole(HdPrimvarSchema::BuildRoleDataSource(HdPrimvarSchemaTokens->point))
        .Build(),
        
    // Normals primvar  
    HdPrimvarsSchemaTokens->normals,
    HdPrimvarSchema::Builder()
        .SetPrimvarValue(HdRetainedTypedSampledDataSource<VtVec3fArray>::New(GetNormalsFromUSD()))
        .SetInterpolation(HdPrimvarSchema::BuildInterpolationDataSource(HdPrimvarSchemaTokens->vertex))
        .SetRole(HdPrimvarSchema::BuildRoleDataSource(HdPrimvarSchemaTokens->normal))
        .Build(),
        
    // Display color primvar
    HdTokens->displayColor,
    HdPrimvarSchema::Builder()
        .SetPrimvarValue(HdRetainedTypedSampledDataSource<VtVec3fArray>::New(GetDisplayColorFromUSD()))
        .SetInterpolation(HdPrimvarSchema::BuildInterpolationDataSource(HdPrimvarSchemaTokens->constant))
        .SetRole(HdPrimvarSchema::BuildRoleDataSource(HdPrimvarSchemaTokens->color))
        .Build(),
        
    // Texture coordinates primvar - THIS IS THE KEY PART
    TfToken("st"), // or HdTokens->st if available
    HdPrimvarSchema::Builder()
        .SetPrimvarValue(HdRetainedTypedSampledDataSource<VtVec2fArray>::New(stValues))
        .SetInterpolation(HdPrimvarSchema::BuildInterpolationDataSource(HdPrimvarSchemaTokens->faceVarying))
        .SetRole(HdPrimvarSchema::BuildRoleDataSource(HdPrimvarSchemaTokens->textureCoordinate))
        .Build()
);

return primvarsDs;

}

VtVec2fArray GetTextureCoordinatesFromUSD() {
    // Get the USD prim
    UsdGeomMesh mesh(usdPrim);
    UsdGeomPrimvarsAPI primvarsAPI(mesh);
    
    // Get the st primvar
    UsdGeomPrimvar stPrimvar = primvarsAPI.GetPrimvar(TfToken("st"));
    if (stPrimvar) {
        VtValue value;
        if (stPrimvar.ComputeFlattened(&value, UsdTimeCode::Default())) {
            return value.Get<VtVec2fArray>();
        }
    }
    
    return VtVec2fArray(); // Return empty array if not found
}

Regards,
David Lanier

It might be worth doing a sanity check of the Hydra Scene Browser, looking at the state of the Hydra data at the Scene Index just before your Generative Procedural gets resolved.

For example…

Hi David & Rob,

Thanks for the help!

My Generative procedural just looks up a vanilla mesh in the index and my assumption the uvs are unconditionally copied from UsdGeomMesh to the Scene Index representation using the default adapter for this purpose.

As far as I can tell I’m querying all the primvars in my code and the st isn’t appearing. Are they filtered in some way en route?

@robp_sidefx I’ll give the hydra viewer a go. It thought it wasn’t in usdview out of the box so I didn’t even try.

Don

In Houdini 20.5 the yayitworks_uvs primvar appears in the hydra scene browser regardless if there is a bound material or not but in my vanilla build of usd (0.25.8) I only get the texture coordinate if it’s referenced in a material as per the following example:

#usda 1.0
(
    defaultPrim = "Root"
)

def Xform "Root"
{
    def Xform "ground" (
        prepend apiSchemas = ["MaterialBindingAPI"]
        kind = "component"
    )
    {
        rel material:binding = </Root/SimpleTexturedMaterial>
        

        def Mesh "grid"
        {
            float3[] extent = [(-50, 0, -50), (50, 0, 50)]
            int[] faceVertexCounts = [3, 3]
            int[] faceVertexIndices = [0, 3, 1, 3, 0, 2]
            
            point3f[] points = [(-50, 0, -50), (50, 0, -50), (-50, 0, 50), (50, 0, 50)] (
                interpolation = "vertex"
            )
            texCoord2f[] primvars:yayitworks_uvs = [(0, 0), (1, -1), (1, 0), (1, -1), (0, 0), (0, -1)] (
                interpolation = "faceVarying"
            )
            int[] primvars:yayitworks_uvs:indices = None
            uniform token subdivisionScheme = "none"
        }
    }

    def Material "SimpleTexturedMaterial"
    {
        def Shader "PreviewSurface"
        {
            token info:id = "UsdPreviewSurface"

            color3f inputs:diffuseColor.connect = </Root/SimpleTexturedMaterial/DiffuseTexture.outputs:rgb>
            float inputs:roughness = 0.5
            token outputs:surface
        }

        def Shader "DiffuseTexture"
        {
            token info:id = "UsdUVTexture"

            asset inputs:file = @textures/test.jpg@
            token inputs:sourceColorSpace = "sRGB"
            float2 inputs:st.connect = </Root/SimpleTexturedMaterial/PrimvarSt.outputs:result>
            token outputs:rgb
        }

        def Shader "PrimvarSt"
        {
            uniform token info:id = "UsdPrimvarReader_float2"

            token inputs:varname = "yayitworks_uvs"
            float2 outputs:result
        }

        token outputs:surface.connect = </Root/SimpleTexturedMaterial/PreviewSurface.outputs:surface>
    }
}

My guess is you’re running into OpenUSD/pxr/usdImaging/usdImaging/gprimAdapter.cpp at 833d130b2d1e607b24822a6b0e59d7baaeb88c53 · PixarAnimationStudios/OpenUSD · GitHub