Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BigRoy/d1a4c7aa92d85db2c206f443fb521673 to your computer and use it in GitHub Desktop.
Save BigRoy/d1a4c7aa92d85db2c206f443fb521673 to your computer and use it in GitHub Desktop.
Houdini Solaris Material Library LOP get the USD Material Prim Path mapping to the Houdini Material node in the Material Library
import logging
from typing import Dict
import hou
log = logging.getLogger(__name__)
def get_material_library_paths(material_lib: hou.LopNode) -> Dict[str, str]:
"""Return Houdini material node path to USD path mapping
Given a Houdini Material Library LOP provide a mapping of
all generated materials' USD paths to the relevant Houdini
material node paths.
Args:
material_lib (hou.LopNode): The Material Library LOP node.
Returns:
dict: Mapping from generated USD Material Prim Path to
the relevant Houdini Material VOP node path in the
Material Network.
"""
assert material_lib.type().name() == "materiallibrary"
material_lib.cook() # cook
modified_prims = set(material_lib.lastModifiedPrims())
# Materials will be relative to this material network
material_network = material_lib.parm("matnet").evalAsNode()
if not material_network:
raise RuntimeError("No material network found")
material_path_prefix = material_lib.evalParm(f"matpathprefix")
mapping = {}
for i in range(material_lib.evalParm("materials")):
index = i + 1
material_paths = material_lib.parm(f"matnode{index}").evalAsString()
if not material_paths:
continue
material_nodes = material_network.glob(material_paths)
if not material_nodes:
continue
material_flag_only = material_lib.evalParm(f"matflag{index}")
if material_flag_only:
material_nodes = [node for node in material_nodes
if node.isMaterialFlagSet()]
if not material_nodes:
continue
# Now for each material compute the resulting USD material path
matpath = material_lib.evalParm(f"matpath{index}")
for material_node in material_nodes:
if matpath:
node_matpath = matpath
else:
node_matpath = material_network.relativePathTo(material_node)
if not node_matpath.startswith("/"):
# Add material path prefix if path is not absolute already
node_matpath = f"{material_path_prefix}{node_matpath}"
mapping[node_matpath] = material_node.path()
# Let's do some re-assuring check to see if our computed output
# mappings correspond with the modified prims that Houdini lists
# for the LOP node. This is just a safety mechanism.
for path in mapping.keys():
if path not in modified_prims:
log.warning(
"Expected generation of USD Material Path %s yet "
"it was not reported by Houdini as a modified "
"primitive by this LOP node '%s'",
path, material_lib.path()
)
return mapping
# Example usage
material_library = hou.node("/stage/materiallibrary1")
for usd_prim_path, houdini_node_path in get_material_library_paths(material_library).items():
print(usd_prim_path, houdini_node_path)
@BigRoy
Copy link
Author

BigRoy commented Feb 23, 2024

An easier method than the above is to just get the editor nodes from the modified prims of the Material Library. Those editor nodes will be the Material VOP nodes.

For example:

import logging
from typing import Dict, List

import hou
import loputils
from pxr import Usd

log = logging.getLogger(__name__)


def get_editor_nodes(prim: Usd.Prim) -> List[hou.Node]:
    editor_nodes = loputils._getEditorNodes(prim, allow_locked_nodes=False)
    return editor_nodes


def get_material_library_paths(material_lib: hou.LopNode) -> Dict[str, hou.VopNode]:
    """Return Houdini material node path to USD path mapping

    Given a Houdini Material Library LOP provide a mapping of
    all generated materials' USD paths to the relevant Houdini
    material node paths.

    Args:
        material_lib (hou.LopNode): The Material Library LOP node.

    Returns:
        dict: Mapping from generated USD Material Prim Path to
            the relevant Houdini Material VOP node in the
            Material Network.

    """

    assert material_lib.type().name() == "materiallibrary"

    material_lib.cook()  # cook
    modified_prims = material_lib.lastModifiedPrims()
    if not modified_prims:
        return {}

    # The modified prims should be the generated materials
    stage = material_lib.stage()
    mapping = {}
    for material_path in modified_prims:
        prim = stage.GetPrimAtPath(material_path)
        node = get_editor_nodes(prim)[0]
        mapping[material_path] = node

    return mapping


# Example usage
for usd_path, houdini_path in get_material_library_paths(
        hou.node("/stage/materiallibrary1")).items():
    print(usd_path, houdini_path)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment