Skip to content

Latest commit

 

History

History
1026 lines (821 loc) · 37.3 KB

working_with_plugins.md

File metadata and controls

1026 lines (821 loc) · 37.3 KB

There's 2 ways of extending USD for your pipeline

  1. Fork USD and add the features in that you want (and then PR it back so others can use it!)
  2. Use Plugins

Option #2 is way easier to do and easier to maintain. But how are you supposed to know which USD features can be changed by using plugins? There's no master-list of how USD uses their own Plugin Framework . And there's no way to query that information in code, either. The best you can do is query what plugins are discoverable (which we'll get to in a bit).

Rather than write cookbook projects for every USD plugin, it makes more sense to make a glossary for reference and explain how to find out more information.

With that said, this guide will teach:

  • What plugins USD uses
  • The source-code location to find out more about those plugins
  • How to find plugins, yourself

Plugin Summary

USD has two main methods of querying plugins. USD either iterates over all plugins and searches for a specific key or it searches for plugins that inherit from a known USD type. We'll call these "By-Name" Plugins and "By-Type" Plugins, respectively.

Skip to How To Find Where To Look to find out how to search these definitions by yourself.

Table Of Contents

Here's a quick list of both styles that USD uses to query plugins.

"By-Name" Plugins

"By-Type" Plugins

How To Query Discovered Plugins

If you're only interested in finding out what plugins are loaded, USD already has a convenience method for that. That said, if you're using a default build of USD, the methods won't return very interesting results. But in a studio pipeline this list is a great opportunity for "discovering" projects that you may not have been aware of.

from pxr import Plug

for plugin in Plug.Registry().GetAllPlugins():
    print('Plugin: "{plugin.name}" is loaded: "{plugin.isLoaded}".'.format(plugin=plugin))
    print('Path: "{plugin.path}".'.format(plugin=plugin))

Example Output on a default build of USD:

Plugin: "usd" is loaded: "False".
Path: "/usr/local/USD-19.07/lib/libusd.so".
Plugin: "usdGeom" is loaded: "False".
Path: "/usr/local/USD-19.07/lib/libusdGeom.so".
Plugin: "usdLux" is loaded: "False".
Path: "/usr/local/USD-19.07/lib/libusdLux.so".
Plugin: "usdHydra" is loaded: "False".
Path: "/usr/local/USD-19.07/lib/libusdHydra.so".
...

USD uses its own plugin system to register many of its own modules. So you'll always see its libraries mixed in with any proprietary ones that a studio has added.

Plugin Details

This section goes over some simple plugins, what they do, and links to learn more. If a section contains sample plugin text, assume that the file needs to be named plugInfo.json and its directory should be found in the PXR_PLUGINPATH_NAME environment variable.

If you don't know what this means, check out The Variant Selection Fallback Plugin or The Plugin Metadata Plugin or The Custom Resolver Plugin projects to find out more information. Also, there's the USD PluginRegistry documentation

Set Your Default Scene Up Axis

Summary: Set a value for the up axis for USD scenes that don't have an authored up-axis value

Key: UsdGeomMetrics

Related Links:

Source Code Link: pxr/usd/lib/usdGeom/metrics.cpp

Plugin Sample Text:

plugInfo.json

{
    "Plugins": [
        {
            "Type": "resource",
            "Name": "scene_up_plugin",
            "Info": {
                "UsdGeomMetrics": {
                    "upAxis": "Z"
                }
            }
        }
    ]
}

Relevant Commands:

SdfSchema::GetInstance().GetFallback(UsdGeomTokens->upAxis)
TfToken UsdGeomGetFallbackUpAxis();
from pxr import Usd, UsdGeom
UsdGeom.GetFallbackUpAxis()

stage = Usd.Stage.CreateInMemory()
print(UsdGeom.GetStageUpAxis(stage))  # Prints "Y" normally but will print "Z" if the plugin is installed

Set Up Color Management

Summary: A way to store and interpret per-attribute color-space values

Key: UsdColorConfigFallbacks

Description: USD lets you set colorspace information in layers and attribute as metadata. If there's nothing authored, the color configuration fallback plugin is queried, instead. This is very useful because it lets different projects use different configurations without changing any USD files.

Source Code Link: pxr/usd/lib/stage.cpp

Related Links:

Plugin Sample Text:

plugInfo.json

{
    "Plugins": [
        {
            "Type": "resource",
            "Name": "color_management_definition",
            "Info": {
                "UsdColorConfigFallbacks": {
                    "colorConfiguration": "https://github.com/imageworks/OpenColorIO-Configs/blob/master/aces_1.0.1/config.ocio",
                    "colorManagementSystem": "OpenColorIO"
                }
            }
        }
    ]
}

Defining Values in USDA, Explicitly:

Looks.usda (This code can be used to explicitly set color management settings, per-layer)

#usda 1.0
(
    colorManagementSystem = "ocio"
    customLayerData = {
        string colorSpace = "acescg"
    }
)

Looks.usda (This code can be used to explicitly set color management settings, per-attribute)

color3f inputs:otherColor6 = (0.1, 0.1, 0.1) (
    colorSpace = "lin_rec709"
)

Relevant Commands:

SdfAssetPath UsdStage::GetColorConfiguration() const;
TfToken UsdStage::GetColorManagementSystem() const;
UsdStage::SetColorConfiguration(const SdfAssetPath &colorConfig) const;
void UsdStage::SetColorManagementSystem(const TfToken &cms) const;
Usd.Stage.GetColorConfiguration()
Usd.Stage.GetColorManagementSystem()
Usd.Stage.SetColorConfiguration()
Usd.Stage.SetColorManagementSystem()

UsdUtilsPipeline

The UsdUtilsPipeline plugin key is a plugin that configures some default USD stage settings.

Set Up A Default Camera Name

Summary: Store the name of the "primary/preferred camera" of your USD stage.

Description: If you define a PrimaryCameraName in UsdUtilsPipeline, that camera name is used. Otherwise, USD falls back to the site-defined DefaultPrimaryCameraName.

Default: If no primary camera name is given using this plugin, USD falls back to "main_cam".

Key:

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json

{
    "Plugins": [
        {
            "Name": "Default Camera Name",
            "Type": "resource",
            "Info": {
                "UsdUtilsPipeline": {
                    "PrimaryCameraName": "SomeCameraName"
                },
                "DefaultPrimaryCameraName": "SomeFallbackName"
            }
        }
    ]
}

Relevant Commands:

TfToken UsdUtilsGetPrimaryCameraName(const bool forceDefault);
UsdUtils.GetPrimaryCameraName()

Set Up A Registered Material Prim

Summary: Let USD know that Prims given a certain name have materials as its child Prims.

Description: From the USD documentation: "The name of the USD prim under which materials are expected to be authored"

Key:

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json

{
    "Plugins": [
        {
            "Name": "Default Material Prim Container",
            "Type": "resource",
            "Info": {
                "UsdUtilsPipeline": {
                    "MaterialsScopeName": "SomePrimName"
                },
                "DefaultMaterialsScopeName": "SomeFallbackPrimName"
            }
        }
    ]
}

Relevant Commands:

TfToken UsdUtilsGetMaterialsScopeName(const bool forceDefault);
UsdUtils.GetMaterialsScopeName()

Set Up Variant Selection Fallbacks

There's already an example project for this plugin, located at concepts/variant_fallbacks. But, for completion, let's also summarize the information here, too.

Summary: If a VariantSet has no selection, this plugin can control which variant gets selected, if needed, by-default.

Key: UsdVariantFallbacks

Related Links:

Source Code Link:

Plugin Sample Text:

{
    "Plugins": [
        {
            "Name": "Variant Set Fallbacks",
            "Type": "resource",
            "Info": {
                "UsdVariantFallbacks": {
                    "some_variant_set_name": ["possible_fallback_1", "possible_fallback_2", "possible_fallback_3", "foo", "bar"]
                }
            }
        }
    ]
}

Relevant Commands:

static PcpVariantFallbackMap GetGlobalVariantFallbacks();
static void SetGlobalVariantFallbacks(const PcpVariantFallbackMap &fallbacks);
Usd.Stage.GetGlobalVariantFallbacks()
# Set variant fallbacks explicitly (this will override any plugInfo.json fallbacks)
Usd.Stage.SetGlobalVariantFallbacks({"some_variant_set_name": ["foo", "bar"]})  # Must be done before creating a stage

Set Up Variant Selection Export Policies

There's already an example project for this plugin, located at guides/registered_variant_selection_export_policies. But, for completion, let's also summarize the information here, too.

Summary: Decide which USD VariantSet is allowed to be written to disk and under what conditions

Description: This plugin doesn't appear to do anything at the API level. It seems to be more like a reference for tools to use on-export to decide how to deal with VariantSets. USD uses this plugin in a number of places, mainly in Katana and Maya's translator plugins.

Key: RegisteredVariantSets

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json

{
    "Plugins": [
        {
            "Name": "Variant Selection Export Policies",
            "Type": "resource",
            "Info": {
                "UsdUtilsPipeline": {
                    "RegisteredVariantSets": {
                        "some_variant_set": {
                            "selectionExportPolicy": "never"
                        },
                        "standin": {
                            "selectionExportPolicy": "never"
                        }
                    }
                }
            }
        }
    ]
}

Relevant Commands

const std::set<UsdUtilsRegisteredVariantSet>& UsdUtilsGetRegisteredVariantSets();
UsdUtils.GetRegisteredVariantSets()

Subclass Your Own Kind

Summary: Create a custom Kind by using one of USD's existing Kinds as a base class.

Key: Kinds

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json (This was copy/pasted from pxr/usd/lib/kind/testenv/testKindRegistry/lib/python/plugInfo.json)

{
    "Plugins": [
        {
            "Type": "python",
            "Name": "TestKindModule",
            "Info": {
                "Kinds": {
                    # Add "test_model_kind" as a kind of model.
                    "test_model_kind": {
                        "baseKind": "model"
                    },
                    # Add "test_root_kind" as a root kind.
                    "test_root_kind": {
                    }
                }
            }
        }
    ]
}

Important: It's highly recommended to inherit from an existing Kind, rather than create a new root kind. USD traversals use predicate flags to quickly get models. Custom root kinds can still be traversed normally but it will be much slower. It's faster to inherit from a model Kind and use UsdPrimRange like normal. You can still make a root kind of course, it's just not recommended. Source conversation here.

Relevant Commands:

UsdPrimRange::Stage(const UsdStagePtr &stage, const Usd_PrimFlagsPredicate &predicate);
UsdPrimRange::UsdPrimRange(Usd_PrimDataConstPtr begin, Usd_PrimDataConstPtr end, const SdfPath& proxyPrimPath, const Usd_PrimFlagsPredicate &predicate = UsdPrimDefaultPredicate);

Extend Metadata

There's already an example project for this plugin, located at concepts/plugin_metadata. But, for completion, let's also summarize the information here, too.

Summary: Registry new metadata types so you can add your own custom metadata onto layers, attributes, prims, and more.

Key: SdfMetadata

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json

{
    "Plugins": [
        {
            "Name": "Plugin double extension",
            "Type": "resource",
            "Info": {
                "SdfMetadata": {
                    "another_metadata": {
                        "type": "double[]",
                        "appliesTo": "layers",
                        "default": [5.0, 13.0]
                    },
                    "my_custom_double": {
                        "type": "double",
                        "appliesTo": "prims",
                        "default": 12.0
                    }
                }
            }
        }
    ]
}

Relevant Commands:

TfToken SdfSchemaBase::SpecDefinition::GetMetadataFieldDisplayGroup(const TfToken& name) const
TfTokenVector SdfSchemaBase::SpecDefinition::GetMetadataFields() const;
bool SdfSchemaBase::SpecDefinition::IsMetadataField(const TfToken& name) const;
const VtValue& SdfSchemaBase::GetFallback(const TfToken &fieldKey) const;
const VtValue& SdfSpec::GetFallbackForInfo( const TfToken & key ) const
std::vector<TfToken> SdfSpec::GetMetaDataInfoKeys() const;
TfToken GetMetaDataDisplayGroup(TfToken const &key) const;
Sdf.Spec.GetFallbackForInfo()
Sdf.Spec.GetMetadataInfoKeys()
Sdf.Spec.GetMetadataDisplayGroup()

Register A File Format

Summary: Add a file format so that it can be natively converted to and from USD.

Key: SdfFileFormat

Description: This plugin takes a dictionary with a number of allowed keys:

  • bases - The registered File Format name that this plugin inherits. It must inherit from a type that inherits from SdfFileFormat or it must inherit SdfFileFormat, directly.
  • extensions - list of strings. It's the filetype extensions that can be processed by this formatter
  • formatId - string - A unique ID that is used to find this file format plugin. Usually this value matches the extension of the file format. But it's not a requirement.
  • primary - If this file format plugin should be the preferred plugin for its extensions
  • target - To be honest, I'm not really sure what this is for. Maybe it's the file format that this registered file format is meant to be converted into? All of the examples online that I see convert to either "usd" or "sdf", which seems to support that idea.

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json (This was copied from USD's usd module)

{
    "Plugins": [
        {
            "Info": {
                "Types": {
                    # ...

                    "UsdUsdcFileFormat": {
                        "bases": [
                            "SdfFileFormat"
                        ],
                        "displayName": "USD Crate File Format",
                        "extensions": [
                            "usdc"
                        ],
                        "formatId": "usdc",
                        "primary": true,
                        "target": "usd"
                    }

                    # ...
                }
            }
        }
    ]
}

Relevant Commands:

Everything from the FileFormatRegistry class

Adding A Custom Resolver

This plugin has been covered by the custom_resolver project in this repository. But, for completion, let's also summarize the information here, too.

Summary: A resolver plugin is used to convert any string to a path on-disk. For example, USD Asset paths may be a totally arbitrary string syntax, such as: "[foo][bar[bazz]??usda|v=001]". A custom resolver's job is to convert that string into a path on-disk like "/tmp/foo_folder/bar_bazz_v001.usda".

Key: ArResolver (any plugin that inherits this class)

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json (Copied file from the generated results of this custom resolver project)

{
    "Plugins": [
        {
            "Info": {
                "Types": {
                    "URIResolver" : {
                        "bases": ["ArResolver"]
                    }
                }
            },
            "LibraryPath": "../libURIResolver.so",
            "Name": "URIResolver",
            "Type": "library"
        }
    ]
}

Relevant Commands:

void ArSetPreferredResolver(const std::string& resolverTypeName);
ArResolver& ArGetResolver();
std::vector<TfType> ArGetAvailableResolvers();
Ar.SetPreferredResolver()
Ar.GetResolver()

Adding A Package Resolver

Summary: Like "Adding A Custom Resolver" but for USD package resolvers.

Description: There's not that much documentation about package resolvers. That said, USD package resolvers are similar in concept to an asset resolver but with the following differences:

  • You aren't supposed to instantiate package resolvers yourself. USD does this internally, for you. Always prefer ArGetResolver
  • The ArResolver class converts a logical path (a string or URI) into a physical path.
  • The ArPackageResolver class specifically handles "package" file formats like files with ".pack" extension. It is responsible for [resolving information about assets stored within that package](https://graphics.pixar.com/usd/docs/api/class_ar_package_resolv er.html)
  • In other words, ArPackageResolver resolves a subset of a file on disk (an asset within a package file) and ArResolver resolves a whole file, instead.

So the question is, how do you define a package resolver? You do it the same way as an asset resolver, just with a different key.

Key: ArPackageResolver

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json (Copied from The ArPackageResolver documentation)

{
    "Plugins": [
        {
            "Info": {
                "Types" : {
                    "CustomPackageResolver" : {
                        "bases": [ "ArPackageResolver" ],
                        "extensions": [ "pack" ]
                    }
                }
            },
            ...
        },
        ...
    ]

}

Pair A usdImaging Adapter Class With A Usd Prim Type

Summary: Add a usdImaging Adapter Type for a given USD Prim type.

Description: This plugin has 3 main keys:

  • bases - list of strings - The USD adapter class that this adapter is based off of.
  • isInternal - bool - External adapters can be turned on and off depending on if the USDIMAGING_ENABLE_PLUGINS environment variable is enabled. This environment variable is mainly used for debugging purposes. Internal adapters stay on.
  • primTypeName - string - The USD Prim type that the adapter is for

Key: UsdImagingPrimAdapter (must be derived from this class)

Related Links:

Source Code Link:

Plugin Sample Text

plugInfo.json (Copied from pxr/usdImaging/lib/usdVolImaging/plugInfo.json)

"UsdImagingOpenVDBAssetAdapter": {
    "bases": [
        "UsdImagingFieldAdapter"
    ],
    "isInternal": true,
    "primTypeName": "OpenVDBAsset"
},
"UsdImagingField3DAssetAdapter": {
    "bases": [
        "UsdImagingFieldAdapter"
    ],
    "isInternal": true,
    "primTypeName": "Field3DAsset"
}

Relevant Commands:

Everything in the UsdImagingAdapterRegistry class

Add Shader Resources To Hydra

Summary: A way to add additional shader definitions to Hydra.

Key: [Info][ShaderResources]

Source Code Link:

Plugin Sample Text:

plugInfo.json (Copied from pxr/imaging/lib/hdx/plugInfo.json)

{
    "Plugins": [
        {
            "Info": {
                "ShaderResources": "shaders"
            },
            "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@",
            "Name": "hdSt",
            "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@",
            "Root": "@PLUG_INFO_ROOT@",
            "Type": "library"
        }
    ]
}

Relevant Commands:

Anything in the ShaderResourceRegistry class

Create A Custom Schema

Summary: Define a USD type to use in your C++ / Python projects. This system is the same as the one that USD itself uses for most of its class types.

Key: UsdSchemaBase

Related Links:

Source Code Link:

Plugin Sample Text:

{
    "Plugins": [
        {
            "Info": {
                "Types": {
                    # ...

                    "UsdGeomCube": {
                        "alias": {
                            "UsdSchemaBase": "Cube"
                        },
                        "autoGenerated": true,
                        "bases": [
                            "UsdGeomGprim"
                        ],
                        "implementsComputeExtent": true
                    }

                    # ...
                }
            }
        }
    ]
}

Relevant Commands:

Everything in the UsdSchemaRegistry class

Encode Shaders As USD Prims

The USD documentation is fairly extensive about this plugin so, instead of re-iterating its points, links will be provided, below:

OpenGL USD Types

Summary: To be honest, I'm not read up enough on OpenGL and how it is consumed by USD to discuss this particular plugin. Maybe this section can be filled in once someone with experience sees this.

Judging from the plugInfo.json file, it looks like this plugin is used to define classes to consume texture file types for viewport rendering. It has some kind of a ranked ordering, using "precedence" as the ordering key. But this is all just a guess.

Key: GlfImage

Related Links:

Source Code Link:

Plugin Sample Text:

plugInfo.json (Copied from plugInfo.json)

{
    "Plugins": [
        {
            "Info": {
                "ShaderResources": "shaders",
                "Types": {                                                                  
                    "Glf_OIIOImage" : {
                        "bases": ["GlfImage"],
                        "imageTypes": ["bmp", "exr", "jpg", "png", "tif", "zfile", "tx"],
                        "precedence": 0 
                    },
                    "Glf_StbImage" : {
                        "bases": ["GlfImage"],
                        "imageTypes": ["bmp", "jpg", "png", "tga", "hdr"],
                        "precedence": 2
                    },
                    "GlfPtexTexture" : {
                        "bases": ["GlfTexture"],
                        "textureTypes": ["ptx", "ptex"],
                        "precedence": 1
                    },
                    "GlfUVTexture" : {
                        "bases": ["GlfBaseTexture"],
                        "textureTypes": ["*"],
                        "precedence": 0
                    }
                }
            },
            "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@",
            "Name": "glf",
            "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@",
            "Root": "@PLUG_INFO_ROOT@",
            "Type": "library"
        }
    ]
}

How To Find Where To Look

Like mentioned in past sections, there's no one way of finding out how USD uses its own plugins. At best, you can query what plugins are currently being used and work backwards from there.

That said, it's not all hopeless. Here's a few methods for searching that were used to write this article

Search for plugInfo.json files

USD's plugin system relies on these files so it makes sense that we can find pretty much any plugin under the sun just by searching for those files

Linux:

git clone https://github.com/PixarAnimationStudios/USD && cd USD
find -type f -name "plugInfo.json"

Plugins are typically "found" in USD by either a special key under "Info", like "UsdUtilsPipeline"

{
    "Plugins": [
        {
            "Name": "Default Camera Name",
            "Type": "resource",
            "Info": {
                "UsdUtilsPipeline": {
                    # ...
                }
            }
        }
    ]
}

or USD will search for a specific type, using the "bases" key of a plugin, like this

{
    "Plugins": [
        {
            "Info": {
                "Types": {
                    "URIResolver" : {
                        "bases": ["ArResolver"]
                    }
                }
            }
        }
    ]
}

In both cases, once you see a plugInfo.json, you can read the keys under "Info" or search for PluginRegistry for methods that require ArResolver and you're pretty likely to find exactly where that plugInfo.json is meant to be used.

Search for uses of registry classes

Searching C++ code for phrases like GetAllPlugins, GetAllDerivedTypes, and really any public member function in the PlugRegistry class will find many plugins, right away.

The only thing to keep in mind with this search method is that there are multiple registries in USD. There's:

And possibly others that just aren't listed here yet.

So keep that in mind while searching. If you search by-registry and can't find what you're looking for, consider the idea that you may need to be looking for a different registry.

Search Online

There's a USD repository called parallax/ar-export that has a list of many plugInfo.json file examples that is a decent reference. There's also repositories from VFX companies, like Luma and RodeoFX. Many of those repositories will have example plugin uses.