# Using the Python API

# Loading USD files

All the functions exposed by the Multiverse Python API are contained in the multiverse module:

import multiverse
1

To create a new mvUsdCompoundShape node and load an USD asset simply pass the asset file path to CreateUsdCompound:

nodeName = multiverse.CreateUsdCompound('/path/to/asset.usdc')
1

We can also create a new mvUsdCompoundShape node and load multiple USD assets at the same time:

nodeName = multiverse.CreateUsdCompound(
    ['/path/to/asset.usd', '/path/to/overrides.usd'])
1
2

To query the paths of set assets currently set on a mvUsdCompoundShape node use:

paths = multiverse.GetUsdCompoundAssetPaths(nodeName)

# paths = ['/path/to/asset.usd', '/path/to/overrides.usd']
1
2
3

# Writing USD files

Multiverse API functions to write USD files support different set of options that can be passed to control the export operations. Since each write function can support a fairly large number of options, these are defined by custom option classes. For example, in order to export a Maya mesh object to USD, we can choose if we want to export normals, uvs, etc... For assets, all of these options are made available through the AssetWriteOptions class. For example to export a mesh sphere object called pSphere1 enabling normals and UVs information we would use:

opts = multiverse.AssetWriteOptions()

opts.writeNormals = True
opts.writeUVs = True

multiverse.WriteAsset('/path/to/sphere.usd', 'pSphere1', opts)
1
2
3
4
5
6

This also allows for options to be shared across different export operations.

Classes to control writing of assets and compositions (AssetWriteOptions and CompositionWriteOptions) also support a sub-set of options for animation. These options can be specified once the option object has been created or passed as parameter to the constructor (for example to share the same settings when writing assets and compositions):

# Case 1 - time options are set directly after object creation.
opts = multiverse.AssetWriteOptions()

opts.writeNormals = True
opts.writeUVs = True
opts.timeOptions.writeTimeRange = True
opts.timeOptions.frameRange = (1, 10)

# Case 2 - time options are passed as parameter to the constructor.

timeOpts = multiverse.TimeOptions()
timeOpts.writeTimeRange = True
timeOpts.frameRange = (1, 10)

assetOpts = multiverse.AssetWriteOptions(timeOptions=timeOpts)
compositionOpts = multiverse.CompositionWriteOptions(timeOptions=timeOpts)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Callback for Writing

As of version 8.0.1 there is a new writer callback functionality, allowing the TD to execute custom python scripts on USD write. Any functionality available from the USD and Python API can be used, such as removing unwanted prims, adding custom attributes, even notifying databases.

More information can be found in the callbacks section.

# Querying USD hierarchy

To query information about an asset's hierarchy, Multiverse exposes the GetChildrenForPath API function. The function takes the name of a mvUsdCompoundShape node and an item path and returns a list containing the children for the given item:

import multiverse

children = multiverse.GetChildrenForPath('myUsdCompoundShape', '/main')
1
2
3

The returned children list consists of MvUsdItem objects that contain information, such as name, parent, full path, for the child items.

child = children[0]

child
# /main/obj1

child.name
# obj1

child.fullPath
# /main/obj1

child.parent
# /main

child.typeName
# Xform
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

The GetChildrenForPath API function can be used to easily traverse the full hierarchy for an asset:

import os

def TraverseHierarchy(nodeName, root, depth=0):
    children = multiverse.GetChildrenForPath(nodeName, root)
    for child in children:
        print('{}- {} -- {}'.format('  ' * depth , child.name, child.fullPath))
        TraverseHierarchy(nodeName, os.path.join(root, child.name), depth + 1)

TraverseHierarchy('croc_animShape', '/')


# - main -- /main
#   - obj1 -- /main/obj1
#     - part1 -- /main/obj1/part1
#     - part2 -- /main/obj1/part2
#   - obj2 -- /main/obj2
#     - part1 -- /main/obj2/part1
#   ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Authoring Overrides

Multiverse API functions to author USD overrides provide a set of operations that can be used to create, query, remove/reset and writing. For example, we can read a USD asset called ashtray_geo.usdc and afterwards we can do series of operations from creating override, writing the override, getting the information and even remove the overrides.

Let's start defining the basic codes so that we can use them for the rest of the example:

import multiverse
from pymel import core as pmc

# Ashtray geo USD asset.
ashtrayGeoPath = 'ashtray_geo.usdc'

# CreateMat returns shading group Lambert2SG.
sg = CreateMat('lambert')

# Create an mvSet attribute node and set its namespace.
mvSet = pmc.createNode('mvSet')
mvSet.materialNamespace.set('fakeNameSpace')

xFormPrimPath = '/Ashtray/geo_cigaretteButt_1'
matPrimPath = '/Ashtray/geo_ashtray'
attrPath = '/Ashtray'
visPath = '/Ashtray/geo_cigarette'

# Read the asset.
mvNode = multiverse.CreateUsdCompound(ashtrayGeoPath)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Since now we have read the ashtray_geo.usdc into mvNode we can start using the Multiverse API functions to author the overrides. Let's start by creating different types of override:

# Create transform override to move '/Ashtray/geo_cigaretteButt_1' two
# units in 'x'.
xform = multiverse.CreateTransformOverride(mvNode, xFormPrimPath)
pmc.move(xform, (2, 0, 0))

# Create material override for '/Ashtray/geo_ashtray'.
multiverse.AddMaterialOverride(mvNode, matPrimPath, sg)

# Create attribute set override for '/Ashtray'.
multiverse.AddAttributeSetOverride(mvNode, attrPath, mvSet.name())

# Create viewport visibility override for '/Ashtray/geo_cigarette' to hidden.
multiverse.SetViewportVisibility(mvNode, visPath,
                                 multiverse.VisibilityMode.HIDDEN)

# Create render visibility override for '/Ashtray/geo_cigarette' to hidden.
multiverse.SetRenderVisibility(mvNode, visPath,
                               multiverse.VisibilityMode.HIDDEN)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Now that we have covered the writing functions, let's have a look at the snippets below to check for different kind of overrides:

# Check for transform override.
multiverse.HasTransformOverride(mvNode, xFormPrimPath)

# Check for material override.
multiverse.HasMaterialOverride(mvNode, matPrimPath)

# Check for attribute override.
multiverse.HasAttributeOverride(mvNode, attrPath)

# Check for viewport visibility override.
multiverse.HasViewportVisibilityOverride(mvNode, visPath)

# Check render visibility override.
multiverse.HasRenderVisibilityOverride(mvNode, visPath)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

We can also remove specific overrides that we have done:

# Remove transform override.
multiverse.RemoveTransformOverride(mvNode, xFormPrimPath)

# Remove material override.
multiverse.RemoveMaterialOverride(mvNode, matPrimPath)

# Remove attribute override.
multiverse.RemoveAttributeSetOverride(mvNode, attrPath)

# Reset viewport visibility.
multiverse.ResetViewportVisibility(mvNode, visPath)

# Reset render visibility.
multiverse.ResetRenderVisibility(mvNode, visPath)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

If you feel that you want to wipe out per primitive path overrides:

# Get primitives with overrides.
primPaths = multiverse.GetPrimitivesWithOverrides(mvNode)

# Iterate and remove overrides from each primitive in primPaths.
for primPath in primPaths:
    multiverse.RemovePrimitiveOverrides(mvNode, primPath)
1
2
3
4
5
6

You can also remove all overrides for the whole node:

# remove all overrides from the node
multiverse.RemoveNodeOverrides(mvNode)
1
2

Finally to write the overrides:

ashtrayOverridePath = 'ashtray_over.usda'

overrideOptions = multiverse.OverridesWriteOptions()
overrideOptions.writeVariants = False

multiverse.WriteOverrides(ashtrayOverridePath, mvNode, overrideOptions)
```## Selection Basics

Multiverse API provides two functions to cover selection operations for
`mvUsdCompoundShape`.

Here's a simple snippet to select primitives and query the selection back for
further manipulations:

```python
import multiverse

path = 'ashtray_geo.usdc'
primPaths = ['/Ashtray/geo_cigaretteButt_1', '/Ashtray/geo_ashtray']

# Read the asset.
mvNode = multiverse.CreateUsdCompound(path)

# Select primitives.
multiverse.SelectPrimitives(mvNode, primPaths)

# List currently selected primitives.
selectedPrims = multiverse.GetSelectedPrimitives(mvNode)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# Writing USD Compositions

Multiverse API to write a composition has similar flow as WriteAsset. By specifying the path where the composition will be written, selection of Maya nodes and the options that can be customized by declaring each options separately.

Here is a simple snippet to read two USD files, layer them together, make it as a group and write it as a USD composition:

import multiverse
from pymel import core as pmc

baseAshtray = 'ashtray_geo.usdc'
overAshtray = 'ashtray_over.usda'

# Read and layer the overrides.
assetPaths = [baseAshtray, overAshtray]
mvNode = multiverse.CreateUsdCompound(assetPaths)

# Get the transform node from mvNode.
mvNodeXForm = pmc.listRelatives(mvNode, allParents=True)[0].name()

# Put the USD under Ashtray group
rootGrp = pmc.group(mvNodeXForm, name='Ashtray')

# Set composition options.
timeOptions = multiverse.TimeOptions()
compOptions = multiverse.CompositionWriteOptions(timeOptions=timeOptions)

# Write composition.
output = 'AshtrayFinal.usda'
multiverse.WriteComposition(output, rootGrp.name(), compOptions)

# Read back the result.
asset = multiverse.CreateUsdCompound(output)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# Writing Animations

In order to write animation, we can specify the path and selection of objects that we want to write the animations. Make sure to set the necessary animation properties by using AssetWriteOptions and pass the option to WriteAsset:

import multiverse

path = 'croc_anim.usdc'
selections = ['crocGeo_grp', 'necklace']

# Set write animation options.
writeOptions = multiverse.AssetWriteOptions()
writeOptions.timeOptions.writeTimeRange = True
writeOptions.timeOptions.frameRange = (1, 64)

# Write the animation.
multiverse.WriteAsset(path, selections, writeOptions)

# Read it back.
mvNode = multiverse.CreateUsdCompound(path)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Setting Variant Overrides

Multiverse API offers a set of functions to author variant overrides. Here is a simple snippet to set, reset and querying overrides from a mvUsdCompoundShape:

import multiverse

assetPath = 'sphere_variant.usda'
primPath = '/Sphere'

# Read the USD.
mvNode = multiverse.CreateUsdCompound(assetPath)

# Get the variants. Result will be {'shadingVariant': ('green', ['blue', 'green', 'red'])}.
# If contains more variants, the key of the dictionary will have the same format.
variants = multiverse.GetVariantSetsData(mvNode, primPath)

# Get the variant name. Result: 'shadingVariant'
variantName = variants.keys()[0]

# Get the variant values. Result: ['blue', 'green', 'red']
variantValues = variants[variantName][-1]

# Set the variant to 'red'.
multiverse.SetVariantSetsOverride(mvNode, primPath, variantName, variantValues[2])

# Check whether mvNode has Variants
multiverse.HasVariantsOverride(mvNode, primPath)

# Reset 'shadingVariant'
multiverse.ResetVariantOverride(mvNode, primPath, variantName)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Last Updated: 3/22/2023, 12:29:45 PM