========= UsdExport ========= |sparkles| **New in Katana 4** This page documents how we export Katana Attributes to USD. To make the UsdMaterialBake node and the UsdExport plug-in available, ensure you have followed the GettingStarted page for Katana USD Plug-ins. In particular :ref:`enable-katana-usd-plugins`. UsdMaterialBake =============== UsdMaterialBake is implemented as a SuperTool, and has been designed to provide an example of the new ability to write custom nodes for export using extensions in the existing ``LookFileBakeAPI`` and ``Nodes3DAPI``: ``LookFileBakeAPI.LookFileBaker`` and ``Nodes3DAPI.LookFileBaking``. The node type is designed to provide an override layer that needs to be applied back in USD over the asset that is being look-developed. The UsdMaterialBake will write out differences in the output scene graph between the cooked op at the original (first input) and each of the other inputs in turn, each written out as separate variants. Assigned materials under ``/root/materials`` will also be written; a process much like the ``LookFileBake`` node. UsdExport Architecture ====================== The UsdExport codebase has been designed to be extensible to more than just the Materials and shading data we already provide. The :doc:`LookFileBakeAPI` provides us the construct of scene graph differences between the first and each other port. This fits with the USD layering ideas, where the base USD asset is imported, some edits are performed in Katana's node graph in a non-destructive manner, and a layer is written out containing the difference back to Usd. This layer can then be passed to other applications or back into Katana itself. The modules to support writing out attributes to USD are located in the ``/Usd/lib/python`` folder, and any additional modules which could be used in Katana, (externally to the baking process) should be added here. This allows us to import modules such as ``UsdExport.material``, to gain easy access to writing out the material attributes to USD for other purposes, for example, shelf scripts. Supported Behavior Out-of-the-Box ================================= The out-of-the-box experience with UsdExport supports the following behaviors - Material and shader writing to ``UsdShade`` - UsdLux Light writing including geometry and shadow linking - External renderer light writing through the Sdr Registry - Material assignments - Material interfaces - Multiple variants - Conversion from child materials to sibling materials. Katana to USD Differences ========================= Due to differences in design there are some sections of Katana where we have had to make adjustments to ensure the Katana attributes and locations exported work in a USD file loaded into any other application by default. This section will go over these changes. Child Materials --------------- USD does not use the concept of parent-child inheritance of attributes, as Katana does. Materials are also not meant to be nested within each other. This means we must change the hierarchy of child materials to being sibling materials. To try to ensure we do not name clash, we rebuild the name as the concatenation of the parent and child name, separated by an underscore ``_``. We then use the specializes USD composition arc by use of the ``UsdShade.Material`` ``SetBaseMaterial`` method. This then ensures our child material, which is now a sibling, still inherits its base attributes from its original parent. We also apply the ``LookAPI`` schema, shipped with the Katana USD Plug-ins, which also saves the original name of the child location. This is ready to be used to re-build the parent-child relationship when re-importing. Material and Shader Writing =========================== UsdExport uses ``UsdShade`` to write out the material and shader information. This means in order to write out a material and its shaders, the shaders themselves need to be registered in the Shader Registry (``Sdr``). You can quickly check which shaders you have available in your USD setup by running the following the python code below. .. code-block:: python # Replace fnpxr with pxr if not using the Usd Shipped with Katana from fnpxr import Sdr print Sdr.Registry().GetNodeNames() The reason this information is required is to ensure that we can write the correct type information onto the Shader, since the types in USD and the types in Katana differ. For example, a file path in USD can be represented by the ``Asset`` type, whereas in Katana, it is the ``String`` type. Light Writing ============= UsdExport uses the UsdLux Lighting Schema to write out UsdLux light shaders with the light prim type, parameter names and parameter types. Katana attribute names are matched against the UsdLux concrete prim, shaping API and shadow API parameters and where matches are found, the value is written with the corresponding parameter name and type. The ``UsdExport.lightLinking`` module allows writing of Light and Shadow linking to a prim location. This uses the attributes found in the light list at the ``/root/world`` scene graph location. Lights from External Renderers ------------------------------ Lights added by external renderers are written through an included UsdExport plug-in. In order for this plugin to write out these lights, the light must be registered in the Shader Registry (``Sdr``). Any lights written through this plugin will have the prim type of ``Light``, this is due to a limitation in the USD 21.05 Shader Registry whereby shaders are not linked to a concrete prim type. Where both a external renderer light shader and a UsdLux light shader exist on the same location, the concrete prim type will be set to that matching the UsdLux shader type. If you wish to set the prim type yourself based on the light attributes, this can be done through the :ref:`usdexport-plug-ins` system. Registering Renderer Shaders ============================ To register more renderer shaders you must build that Renderer's USD ``NdrParserPlugin``. These are usually in the same source code as the render delegates, although can be separate. As stated in the GettingStarted page, there are two ways to use USD in Katana, either using your own USD and Katana USD Plug-ins, or those shipped with Katana by default. If you are using your own USD, you must build the Katana USD Plug-ins against your own USD, and then also build the renderer's ``NdrParserPlugin`` against your own USD. You will then have to add the plugin folder to the ``PXR_PLUGINPATH_NAME`` environment variable. If you wish to continue using the plug-ins and the USD we ship with Katana, you must build the ``NdrParserPlugin``'s against our USD. See the section :ref:`building-usd-katana-plugins` for more information on building the Katana USD Plug-ins. You will then have to add the installed plugin folder to the ``FNPXR_PLUGINPATH`` environment variable. UsdExport --------- .. automodule:: UsdExport.light .. automodule:: UsdExport.lightLinking .. automodule:: UsdExport.material .. automodule:: UsdExport.prmanStatements .. automodule:: UsdExport.transform .. automodule:: UsdExport.typeConversionMaps .. _usdexport-plug-ins: UsdExport Plug-ins ================== A new type of plug-in has been added to allow further customization of the USD Export process without the need to rebuild the Katana USD plug-ins. The USD Export plug-in system is implemented with its own dedicated plug-in registry, whose API is accessible via the new ``UsdExport.pluginAPI`` and ``UsdExport.pluginRegistry`` Python modules. USD Export plug-ins are registered during application startup using the standard Katana plug-in registry mechanism, by adding a UsdExportPlugins folder to a directory whose file system location path is referenced in the ``KATANA_RESOURCES`` environment variable, and defining a PluginRegistry module variable in a Python module in that folder. Here's a simple example of defining and registering an export plug-in using such a plug-in Python module: .. code-block:: python from UsdExport.pluginAPI import BaseUsdExportPlugin class MyUsdExportPlugin(BaseUsdExportPlugin): priority = 1000 @staticmethod def WritePrim(stage, sdfLocationPath, attrDict): print('MyUsdExportPlugin.WritePrim(): Exporting "{}"...'.format(sdfLocationPath)) PluginRegistry = [ ('UsdExport', 1, 'MyUsdExportPlugin', (['light'], MyUsdExportPlugin)), ] The plug-in's WritePrim() function will be called as part of exporting USD on each location which matches the location types for which the plug-in is registered. In the example above, the WritePrim() function will be called for light locations. Using the new ``UsdExport.pluginRegistry`` APIs, it is also possible to register and deregister an export plug-in interactively at runtime, for example in a Python tab. This can be used for quickly iterating over a new plug-in that in in development. Here's an example: .. code-block:: python from UsdExport.pluginAPI import BaseUsdExportPlugin import UsdExport.pluginRegistry class MyUsdExportPlugin(BaseUsdExportPlugin): priority = 1000 @staticmethod def WritePrim(stage, sdfLocationPath, attrDict): print('MyUsdExportPlugin.WritePrim(): Exporting "{}"...'.format(sdfLocationPath)) UsdExport.pluginRegistry.RegisterUsdExportPlugin('MyUsdExportPlugin', ['light'], MyUsdExportPlugin) .. automodule:: UsdExport.pluginRegistry .. automodule:: UsdExport.pluginAPI Optimizations to be Considered ============================== The LookFileBakeAPI provides us a way of de-duplicating data. As presented, ``UsdExport`` is not utilizing this in order to keep the initial designs as simple as possible before starting to optimize further. However, this in combination with USD referencing could be used to create singular UsdPrim definitions, which are then referenced multiple times throughout the full location hierarchy. This will become more important once we start writing geometry location types. Variants are also written with no referencing between each variant. There is often lots of shared information between variants which we could deduce and write out more sparse USD files. .. |sparkles| unicode:: U+2728