Python Usage Examples

Load an MDL module

For loading modules, the wrappers in Omniverse have to be used in order to guarantee proper resource tracking.

import omni.mdl.neuraylib

# acquire the neuraylib instance from OV
ov_neuraylib = omni.mdl.neuraylib.get_neuraylib()

# address the MDL module using its USD identifier / source asset name
usd_identifier = "nvidia/support_definitions.mdl"
ov_module = ov_neuraylib.createMdlModule(usd_identifier)
if ov_module and ov_module.valid():
    print(f"dbScopeName: {ov_module.dbScopeName}")
    print(f"dbName: {ov_module.dbName}")
    # ...
    # use omni.mdl.pymdlsdk to get low-level access to the MDL module using its `dbName`
    # ...

    # release to Omniverse wrapper
    ov_neuraylib.destroyMdlModule(ov_module)

Access an active material graph of the material back-end

The Neuraylib in Omniverse maps USD shader nodes to MDL function calls in order to provide implementations for them. When the RTX renderer or NVIDIA Iray is active, or more specifically, an rtx.hydra instance is active, this mapping can be accessed for the active scene renderer.

import omni.mdl.neuraylib

# acquire the neuraylib instance from OV
ov_neuraylib = omni.mdl.neuraylib.get_neuraylib()

# access a USD shader nodes MDL representation. Note, this USD shader node has to exist in the scene
usd_prim_path: str = "/World/Looks/Material/Shader"
ov_entity = ov_neuraylib.createMdlEntity(usd_prim_path)

if ov_entity and ov_entity.valid():
    # create a snapshot from the entity, the actual MDL node exists only for snapshot of the current point in time
    ov_entity_snapshot = ov_neuraylib.createMdlEntitySnapshot(ov_entity)
    if ov_entity_snapshot and ov_entity_snapshot.valid():
        print(f"dbScopeName: {ov_entity_snapshot.dbScopeName}")
        print(f"dbName: {ov_entity_snapshot.dbName}")
        # ...
        # use omni.mdl.pymdlsdk to get low-level access to the MDL function call using its `dbName`
        # ...

        # destroy the MdlEntitySnapshot
        ov_neuraylib.destroyMdlEntitySnapshot(ov_entity_snapshot)
    else:
        # this means that there is a node for this entity but no function is selected yet
        # setting up the nodes function is done in rtx.hydra and not available in python

    # destroy the mdlEntity
    ov_neuraylib.destroyMdlEntity(ov_entity)

Registration of MDL extension content

Omni Extensions can ship their own MDL modules that can be used in Omniverse and USD. The only requirement for a user to access these modules is to enable the extension of interest.

The extension developer needs to register the content during startup and unregister during shutdown. This allows extensions developers to:

  • reference their own MDL materials in USD for rendering and parameter editing

Add content to MDL search paths

To be able to reference MDL modules that ship with an extension in USD, the content has to be referenced in an MDL search path.

import omni.mdl.neuraylib
from pathlib import Path

# fetch information about the current extension
ext_id = omni.kit.app.get_app().get_extension_manager().get_extension_id_by_module(__name__)
ext_dir = Path(omni.kit.app.get_app().get_extension_manager().get_extension_path(ext_id))
ext_name: str = omni.ext.get_extension_name(ext_id)

# assuming the content we are interested in is located in the extension subfolder called `data/mdl` subfolder.
ext_mdl_dir = ext_dir.joinpath('data', 'mdl')

# register the content
abs_path: str = omni.mdl.neuraylib.RegisterExtensionSearchPath(ext_name, ext_mdl_dir)

Assuming the extension is called my.example.extension and the MDL module to reference is called A.mdl, that its path inside the extension folder is data/mdl/P1/P2/A.mdl, and that the module contains a material called Main, a corresponding reference in USD would be:

def Shader "ShaderNode"
{
    uniform token info:implementationSource = "sourceAsset"
    uniform asset info:mdl:sourceAsset = @omniverse_exts/my.example.extension/P1/P2/A.mdl@
    uniform token info:mdl:sourceAsset:subIdentifier = "Main"
    token outputs:out (
        renderType = "material"
    )
}

To clean up during the extension shutdown the content needs to be unregistered:

import omni.mdl.neuraylib

# fetch information about the current extension
ext_id = omni.kit.app.get_app().get_extension_manager().get_extension_id_by_module(__name__)
ext_name: str = omni.ext.get_extension_name(ext_id)

# unregister the content
removed: bool = omni.mdl.neuraylib.UnregisterExtensionSearchPath(ext_name)

Enable MDL module resolution without the RTX renderer

Without the RTX renderer enabled, or more specifically, without rtx.hydra, neuray needs to be started manually in order to enable MDL module resolution in USD. During the neuray startup, the MDL search paths are registered at the USD Asset Resolver. When using the RTX renderer or NVIDIA Iray, this is done automatically.

import omni.mdl.neuraylib

# this starts neuray if not running already
omni.mdl.neuraylib.EnsureRunning()