How do I manage variants on instances?

I have a skelmesh.usd file which contains joints & initial transforms etc, as well as setting out variants pointing to various geometry options. This looks good, its a self contained .usd where I can see in usdview my variants and am able to switch between them

I then have a stage.usd which defines animation files loads a reference to the skelmesh file for each agent in my scene

Finally I have a ‘masterstage.usd’ which loads in all the stages, and sets the overrides on the variants for each agent.

This all works ok.

However, my agents are not instanced. This is really heavy with 10,000+ agents.

So I thought about setting ‘instanceable=True’ onto my skelmesh.usd because this contains all the variations, joints and geo meshes etc, I only need to load this once right?

but in my master scene I can no-longer override the agents

if I try to change the variants I get:
'Cannot create prim spec at path </agent/Agent_1/Geo/hat>; authoring to an instance proxy is not allowed

So my question is: how do I instance tens of thousands of agents, and be able to change their variations?

to flesh out my setup, here is a stripped down example of the master_stage.usd

#usda 1.0
(
    endTimeCode = 2
    framesPerSecond = 24
    metersPerUnit = 0.01
    startTimeCode = 0
    subLayers = [
        @/USD_Main/stage_1.usd@
    ]
    timeCodesPerSecond = 24
)

over "agent"
{
    over "Agent_1"
    {
        def "skelmesh"
        {
            def "Geo"
            {
                def "hat" (
                    variants = {
                        string hat = "5"
                    }
                )
                {
                    int primvars:hat_map = 1 (
                        interpolation = "constant"
                    )
                }
    }

    over "Agent_2"
    {
        def "skelmesh"
        {
            def "Geo"
            {
                def "hat" (
                    variants = {
                        string hat = "0"
                    }
                )
                {
                    int primvars:hat_map = 1 (
                        interpolation = "constant"
                    )
                }

    }

and here is the stage_1.usd

#usda 1.0

def Scope "Animations"
{
    def "Agent_Animation_1" (
        prepend references = @/USD_Main/anim/new/agent_anim.1.usd@</agent_SkelMesh/agent_Skel/agent_animation>
    )
    {
    }

    def "Agent_Animation_2" (
        prepend references = @/USD_Main/anim/new/agent_anim.2.usd@</agent_SkelMesh/agent_Skel/agent_animation>
    )
    {
    }

    def "Agent_Animation_3" (
        prepend references = @/USD_Main/anim/new/agent_anim.3.usd@</agent_SkelMesh/agent_Skel/agent_animation>
    )
    {
    }
}

def "agent"
{
    def "Agent_1" (
        prepend apiSchemas = ["SkelBindingAPI"]
        prepend references = @/USD/agent.usd@
    )
    {
        rel skel:animationSource = </Animations/Agent_Animation_1>
    }

    def "Agent_2" (
        prepend apiSchemas = ["SkelBindingAPI"]
        prepend references = @/USD/agent.usd@
    )
    {
        rel skel:animationSource = </Animations/Agent_Animation_2>
    }

    def "Agent_3" (
        prepend apiSchemas = ["SkelBindingAPI"]
        prepend references = @/USD/agent.usd@
    )
    {
        rel skel:animationSource = </Animations/Agent_Animation_3>
    }
}

and finally the agent.usd

#usda 1.0
(
    defaultPrim = "agent"
    metersPerUnit = 0.01
    upAxis = "Y"
)

def SkelRoot "agent" (
    kind = "component"
    instanceable = true

)
{
    float3[] extent = [(-11.33957, 137.0923, -3.25284), (11.149568, 178.5312, 20.55213)]

    def Skeleton "root" (
        prepend apiSchemas = ["SkelBindingAPI"]
        
    )
    {
        uniform matrix4d[] bindTransforms = [....]
        uniform token[] joints = ["root", ...]
        uniform matrix4d[] restTransforms = [...]
    }

    def Xform "Geo"
    {
        def Xform "hat" (
            kind = "component"
            variants = {
                string hat = "0"
            }
            prepend variantSets = "hat"
        )
        {
            variantSet "hat" = {
                "0" {
                    def Mesh "Nohat" (
                        prepend apiSchemas = ["SkelBindingAPI"]
                    )
                    {
                    }

                }
                "1" {
                    def Mesh "cap_1_geo" (
                        prepend apiSchemas = ["SkelBindingAPI"]
                        prepend payload = @/USD/Meshes/cap_1_geo.usd@</cap_1_geo>
                    )
                    {
                        rel skel:skeleton = </agent/root>
                    }

                }
                "2" {
                    def Mesh "cap_2_geo" (
                        prepend apiSchemas = ["SkelBindingAPI"]
                        prepend payload = @/USD/Meshes/cap_2_geo.usd@</cap_2_geo>
                    )
                    {
                        rel skel:skeleton = </agent/root>
                    }

                }
                "3" {....

Hi @SCF.

You might consider creating a hat_variant on your agent which coordinates the underlying variants and opinions.

For example,

def "agent" (append variantSets = ["agent_hat"]){
    variantSet "agent_hat" = {
        "hat_01" {
            over "geo" {
                over "hat" (variants = {string hat = "1"}){}
            }
        }
        "hat_02" {
            over "geo" {
                over "hat" (variants = {string hat = "2"}){}
            }
        }

    }
}

This would allow you specify variant selection opinions on instanced agents.

1 Like

Thanks, I tried setting that in the stage, and although the stage loads, none of the variants are changed.

Can you show us, i nyour example, what you did, and also what “none of the variants changed” means? E.g. is it just that imaging does not update, or if you drill down inside the instance in usdview, has nothing changed?

What @nvmkuruc suggested definitely should work, and is the recommended pattern for coordinating variantSets on instanceable prims.

We have a new module on instancing that that explains the ins and outs of how scenegraph instancing works and how to setup an instanceable asset. These topics on asset parameterization and lofting variants are also relevant and you may find them helpful.

sorry for the delay, other issues took over.

I have attached a basic repo case of what I am doing. there are two setups, one not using instancing and the other using it.
MasterStage is the main file to view, it sets the overrides and also calls the sub-set stage, which in turn loads the agents and their animations

I hope its clear.

the non instancing version works fine, you can see some of the agents have torus and other have cones. But the instanced version they are all torus and the variant cant be changed.

instancing.zip (22.6 KB)