Authoring Variants

Authoring Variants


VERIFIED ON USD VERSION 21.08

Setup Python

Ensure that you have configured your python environment, this is described in the USD Tutorials document.

This tutorial walks through authoring a simple variant set on our HelloWorld layer from Inspecting and Authoring Properties. The layer that we will be starting with is at USD/extras/usd/tutorials/authoringVariants/HelloWorld.usda and the code for this tutorial is at USD/extras/usd/tutorials/authoringVariants/authorVariants.py ; please copy those files to a working directory and make them writable.

  1. Open the stage and clear the authored opinion on the sphere's color. Because the USD composition engine considers local opinions stronger than variant opinions, if we do not clear this opinion, it will always win out over any ones authored on the same attribute within variants.

    If you comment out the Clear() call and run the tutorial script, you'll see that it authors all the variant opinions that we are setting in the steps below, but the final composed result will always have the locally-authored blue color. A future document will describe the composition order in more detail.

    from pxr import Usd, UsdGeom
    stage = Usd.Stage.Open('HelloWorld.usda')
    colorAttr = UsdGeom.Gprim.Get(stage, '/hello/world').GetDisplayColorAttr()
    colorAttr.Clear()
    print stage.GetRootLayer().ExportToString()

    Note that because displayColor is defined on the UsdGeom.Gprim schema, which UsdGeom.Sphere subclasses, we can treat the sphere at '/hello/world' generically as a gprim.

    #usda 1.0
    (
        defaultPrim = "hello"
    )
    
    def Xform "hello"
    {
        custom double3 xformOp:translate = (4, 5, 6)
        uniform token[] xformOpOrder = ["xformOp:translate"]
    
        def Sphere "world"
        {
            float3[] extent = [(-2, -2, -2), (2, 2, 2)]
            color3f[] primvars:displayColor
            double radius = 2
        }
    }

    The resultant scene description still has the declaration for the displayColor attribute; a future iteration on the Usd.Attribute API may clean this up.


  2.  Create a shading variant on the root prim called 'shadingVariant'

    rootPrim = stage.GetPrimAtPath('/hello')
    vset = rootPrim.GetVariantSets().AddVariantSet('shadingVariant')
    print stage.GetRootLayer().ExportToString()

    returns

    #usda 1.0
    (
        defaultPrim = "hello"
    )
    
    
    def Xform "hello" (
        prepend variantSets = "shadingVariant"
    )
    {
        custom double3 xformOp:translate = (4, 5, 6)
        uniform token[] xformOpOrder = ["xformOp:translate"]
    
        def Sphere "world"
        {
            float3[] extent = [(-2, -2, -2), (2, 2, 2)]
            color3f[] primvars:displayColor
            double radius = 2
        }
    }



  3. Create variants within 'shadingVariant' to contain the opinions we wish to author.

    vset.AddVariant('red')
    vset.AddVariant('blue')
    vset.AddVariant('green')
    print stage.GetRootLayer().ExportToString()

    returns

    #usda 1.0
    (
        defaultPrim = "hello"
    )
    
    def Xform "hello" (
        prepend variantSets = "shadingVariant"
    )
    {
        custom double3 xformOp:translate = (4, 5, 6)
        uniform token[] xformOpOrder = ["xformOp:translate"]
    
        def Sphere "world"
        {
            float3[] extent = [(-2, -2, -2), (2, 2, 2)]
            color3f[] primvars:displayColor
            double radius = 2
        }
    
        variantSet "shadingVariant" = {
            "blue" {
            }
    
            "green" {
            }
    
            "red" {
            }
        }
    }



  4. Give the 'red' variant a red color for the sphere prim at '/hello/world'

    vset.SetVariantSelection('red')
    with vset.GetVariantEditContext():
        colorAttr.Set([(1,0,0)])
    
    print stage.GetRootLayer().ExportToString()

    We need to set the variant selection and author our opinions with the variant set's edit context bound, or we'll be writing to the attribute locally (that is, the same opinion we cleared in step 1).
     

    #usda 1.0
    (
        defaultPrim = "hello"
    )
    
    def Xform "hello" (
        variants = {
            string shadingVariant = "red"
        }
        prepend variantSets = "shadingVariant"
    )
    {
        custom double3 xformOp:translate = (4, 5, 6)
        uniform token[] xformOpOrder = ["xformOp:translate"]
    
        def Sphere "world"
        {
            float3[] extent = [(-2, -2, -2), (2, 2, 2)]
            color3f[] primvars:displayColor
            double radius = 2
        }
    
        variantSet "shadingVariant" = {
            "blue" {
            }
    
            "green" {
            }
    
            "red" {
                over "world"
                {
                    color3f[] primvars:displayColor = [(1, 0, 0)]
                }
            }
        }
    }


    We can now see that "hello" has a default variant selection of "red" for "shadingVariant" and that "red" has an opinion on displayColor.


  5. Author the blue and green variants similarly.

    vset.SetVariantSelection('blue')
    with vset.GetVariantEditContext():
        colorAttr.Set([(0,0,1)])
    
    vset.SetVariantSelection('green')
    with vset.GetVariantEditContext():
        colorAttr.Set([(0,1,0)])
    
    print stage.GetRootLayer().ExportToString()

    returns

    #usda 1.0
    (
        defaultPrim = "hello"
    )
    
    def Xform "hello" (
        variants = {
            string shadingVariant = "green"
        }
        prepend variantSets = "shadingVariant"
    )
    {
        custom double3 xformOp:translate = (4, 5, 6)
        uniform token[] xformOpOrder = ["xformOp:translate"]
    
        def Sphere "world"
        {
            float3[] extent = [(-2, -2, -2), (2, 2, 2)]
            color3f[] primvars:displayColor
            double radius = 2
        }
    
        variantSet "shadingVariant" = {
            "blue" {
                over "world"
                {
                    color3f[] primvars:displayColor = [(0, 0, 1)]
                }
            }
    
            "green" {
                over "world"
                {
                    color3f[] primvars:displayColor = [(0, 1, 0)]
                }
            }
    
            "red" {
                over "world"
                {
                    color3f[] primvars:displayColor = [(1, 0, 0)]
                }
            }
        }
    }

    Strength order: Local vs Variant

    It was important in Step 1 to first clear out the "Local" opinion for primvars:displayColor because within any particular layer, Local opinions are the strongest. Had we not cleared the local opinion, the sphere would have remained blue no matter which shadingVariant we select because the local value of blue would override the variant opinion. 



  6. Let's take a look at the composed result.

    print stage.ExportToString(False)

    returns

    #usda 1.0
    (
        defaultPrim = "hello"
    )
    
    def Xform "hello"
    {
        custom double3 xformOp:translate = (4, 5, 6)
        uniform token[] xformOpOrder = ["xformOp:translate"]
    
        def Sphere "world"
        {
            float3[] extent = [(-2, -2, -2), (2, 2, 2)]
            color3f[] primvars:displayColor = [(0, 1, 0)]
            double radius = 2
        }
    
    }


    What happened to our variants? Flattening the composition applies all opinions for all variant selections, so we just get the final color value of green, since that was the last SetVariantSelection() call we had made.


  7. Save our edits on the authoring layer to a new file, HelloWorldWithVariants.usda

    stage.GetRootLayer().Export('HelloWorldWithVariants.usda')



  8. Run usdview on HelloWorldWithVariants.usda


    In the Meta Data tab for the "hello" prim (see lower right pane), you'll see the variant set that we authored, with a combo box that can toggle between red, blue, and green.



  9. You can use usdview's interpreter to look at the edits made to the session layer when switching variants. This would be the same sparse override you would see if you referenced this layer into another one and then authored the variant selection.

    print usdviewApi.stage.GetSessionLayer().ExportToString()

    returns

    #usda 1.0
    
    over "hello" (
        variants = {
            string shadingVariant = "red"
        }
    )
    {
    }
    





Graphics Home