Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ find_package(Python REQUIRED COMPONENTS Development)

add_subdirectory(moonrayShaderDiscovery)
add_subdirectory(moonrayShaderParser)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/sitecustomize.py
DESTINATION lib/python
)
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,30 @@ which is required to use them as shader nodes in USD/Hydra.

This repository is part of the larger MoonRay/Arras codebase. It is included as a submodule in the top-level
OpenMoonRay repository located here: [OpenMoonRay](https://github.com/dreamworksanimation/openmoonray)

## Houdini 20.5 SDR Type Contract

The MoonRay parser maps RDL attribute metadata into Sdr properties consumed by
Houdini, Hydra, and USD shader discovery. For Houdini 20.5 the parser must
provide an Sdf type and default value with matching shape for every mapped RDL
type.

Important mappings:

- `Bool` and `BoolVector` keep real boolean defaults.
- `Rgb` / `Rgba` map to `color3f` / `color4f`.
- `RgbVector` / `RgbaVector` map to `color3f[]` / `color4f[]` with dynamic
array metadata.
- Numeric vector arrays map to `float2[]`, `float3[]`, `float4[]`,
`double2[]`, `double3[]`, and `double4[]`.
- `Mat4f` / `Mat4d` and their vector forms use `matrix4d` / `matrix4d[]`,
because Houdini 20.5 does not expose a valid `matrix4f` Sdf type.
- Scene object pointer/indexable vectors use token-shaped fallbacks.

Ramp-like MoonRay attributes preserve the coredata grouping metadata
`structure_name`, `structure_path`, and `structure_type` in the Sdr property
metadata. This keeps light-filter and material ramps discoverable as grouped
ramps while preserving valid Sdf/default shapes. For example,
`ColorRampLightFilter.colors` and Dwa material `iridescence_colors` are dynamic
`color3f[]` arrays, while Rod/VDB light-filter non-color ramp values are dynamic
`float[]` arrays and their interpolation controls are dynamic `int[]` arrays.
3 changes: 3 additions & 0 deletions moonrayShaderDiscovery/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ install(FILES ${plugInfoFile}
DESTINATION plugin/pxr/moonrayShaderDiscovery
)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
DESTINATION lib/python/pxr/MoonrayShaderDiscovery
)
3 changes: 3 additions & 0 deletions moonrayShaderParser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,7 @@ install(FILES ${plugInfoFile}
DESTINATION plugin/pxr/moonrayShaderParser
)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py
DESTINATION lib/python/pxr/MoonrayShaderParser
)

62 changes: 55 additions & 7 deletions moonrayShaderParser/parserPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ VtValue convertVector(const JsValue& val,
VtValue convertDefault(const JsValue& val,
const std::string& attrType)
{
if (attrType == "Bool") return VtValue(val.GetBool() ? 0 : 1);
if (attrType == "Bool") return VtValue(val.GetBool());
if (attrType == "Int") return VtValue(val.GetInt());
if (attrType == "Long") return VtValue(val.GetInt64());
if (attrType == "Float") return VtValue((float)val.GetReal());
Expand Down Expand Up @@ -124,7 +124,7 @@ VtValue convertDefault(const JsValue& val,
for (const JsValue& val : arr) {
data.emplace_back(val.GetArrayOf<double>());
}
return VtValue(GfMatrix4f(data));
return VtValue(GfMatrix4d(data));
}
if (attrType == "Mat4d") {
std::vector<std::vector<double>> data;
Expand All @@ -138,22 +138,21 @@ VtValue convertDefault(const JsValue& val,
// can't initialize to anything except null
return VtValue(nullSceneObjectPtr);
}
if (attrType == "BoolVector") return convertVector<int>(val,"Bool");
if (attrType == "BoolVector") return convertVector<bool>(val,"Bool");
if (attrType == "IntVector") return convertVector<int>(val,"Int");
if (attrType == "LongVector") return convertVector<int64_t>(val,"Long");
if (attrType == "FloatVector") return convertVector<float>(val,"Float");
if (attrType == "DoubleVector") return convertVector<double>(val,"Double");
if (attrType == "StringVector") return convertVector<std::string>(val,"String");
if (attrType == "RgbVector") return convertVector<GfVec3f>(val,"Rgb");
if (attrType == "Vec3fVector") return convertVector<GfVec3f>(val,"Vec3f");
if (attrType == "RgbaVector") return convertVector<GfVec3f>(val,"Rgba");
if (attrType == "Vec4f") return convertVector<GfVec4f>(val,"Vec4f");
if (attrType == "RgbaVector") return convertVector<GfVec4f>(val,"Rgba");
if (attrType == "Vec2fVector") return convertVector<GfVec2f>(val,"Vec2f");
if (attrType == "Vec2dVector") return convertVector<GfVec2d>(val,"Vec2d");
if (attrType == "Vec3dVector") return convertVector<GfVec3d>(val,"Vec3d");
if (attrType == "Vec4fVector") return convertVector<GfVec4f>(val,"Vec4f");
if (attrType == "Vec4dVector") return convertVector<GfVec4d>(val,"Vec4d");
if (attrType == "Mat4fVector") return convertVector<GfMatrix4f>(val,"Mat4f");
if (attrType == "Mat4fVector") return convertVector<GfMatrix4d>(val,"Mat4f");
if (attrType == "Mat4dVector") return convertVector<GfMatrix4d>(val,"Mat4d");
if (attrType == "SceneObjectVector" || attrType == "SceneObjectIndexable")
return convertVector<TfToken>(val,"SceneObject");
Expand All @@ -165,6 +164,9 @@ VtValue convertVector(const JsValue& val,
const std::string& baseType)
{
VtArray<T> arrayOut;
if (val.IsNull()) {
return VtValue(arrayOut);
}
const JsArray& arrayIn = val.GetJsArray();
for (const JsValue& elem : arrayIn) {
VtValue vtElem = convertDefault(elem,baseType);
Expand All @@ -175,10 +177,44 @@ VtValue convertVector(const JsValue& val,

bool isDynamicVector(const std::string& type)
{
if (type == "SceneObjectIndexable") {
return true;
}
return (type.size() > 6) &&
(type.substr(type.size()-6,std::string::npos) == "Vector");
}

TfToken getSdfType(const std::string& attrType)
{
if (attrType == "Bool") return TfToken("bool");
if (attrType == "Long") return TfToken("int64");
if (attrType == "Double") return TfToken("double");
if (attrType == "Rgb") return TfToken("color3f");
if (attrType == "Rgba") return TfToken("color4f");
if (attrType == "Vec2d") return TfToken("double2");
if (attrType == "Vec3d") return TfToken("double3");
if (attrType == "Vec4d") return TfToken("double4");
if (attrType == "Mat4f" || attrType == "Mat4d") return TfToken("matrix4d");
if (attrType == "SceneObject*") return TfToken("token");
if (attrType == "BoolVector") return TfToken("bool[]");
if (attrType == "IntVector") return TfToken("int[]");
if (attrType == "LongVector") return TfToken("int64[]");
if (attrType == "FloatVector") return TfToken("float[]");
if (attrType == "DoubleVector") return TfToken("double[]");
if (attrType == "StringVector") return TfToken("string[]");
if (attrType == "RgbVector") return TfToken("color3f[]");
if (attrType == "RgbaVector") return TfToken("color4f[]");
if (attrType == "Vec2fVector") return TfToken("float2[]");
if (attrType == "Vec3fVector") return TfToken("float3[]");
if (attrType == "Vec4fVector") return TfToken("float4[]");
if (attrType == "Vec2dVector") return TfToken("double2[]");
if (attrType == "Vec3dVector") return TfToken("double3[]");
if (attrType == "Vec4dVector") return TfToken("double4[]");
if (attrType == "Mat4fVector" || attrType == "Mat4dVector") return TfToken("matrix4d[]");
if (attrType == "SceneObjectVector" || attrType == "SceneObjectIndexable") return TfToken("token[]");
return TfToken();
}

const TfToken getNodeContext(const JsObject& definition)
{
std::string nodeType = definition.at("type").GetString();
Expand Down Expand Up @@ -262,6 +298,12 @@ getNodeProperties(const NdrNodeDiscoveryResult& discoveryResult,
if (mdIt != attrMetadata.end()) metadata[SdrPropertyMetadata->Label] = mdIt->second.GetString();
mdIt = attrMetadata.find("comment");
if (mdIt != attrMetadata.end()) metadata[SdrPropertyMetadata->Help] = mdIt->second.GetString();
mdIt = attrMetadata.find("structure_name");
if (mdIt != attrMetadata.end()) metadata[TfToken("structure_name")] = mdIt->second.GetString();
mdIt = attrMetadata.find("structure_path");
if (mdIt != attrMetadata.end()) metadata[TfToken("structure_path")] = mdIt->second.GetString();
mdIt = attrMetadata.find("structure_type");
if (mdIt != attrMetadata.end()) metadata[TfToken("structure_type")] = mdIt->second.GetString();
}

// "page" metadata is set from group name
Expand All @@ -270,8 +312,14 @@ getNodeProperties(const NdrNodeDiscoveryResult& discoveryResult,
metadata[SdrPropertyMetadata->Page] = groupIt->second;
}

if (isDynamicVector(attrType))
const TfToken sdfType = getSdfType(attrType);
if (!sdfType.IsEmpty()) {
metadata[SdrPropertyMetadata->SdrUsdDefinitionType] = sdfType;
}

if (isDynamicVector(attrType)) {
metadata[SdrPropertyMetadata->IsDynamicArray] = TfToken("true");
}

auto bindIt = attrData.find("bindable");
if (bindIt != attrData.end() &&
Expand Down
19 changes: 19 additions & 0 deletions sitecustomize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Expose MoonRay's USD Python plugin stubs to Houdini's pxr package.

Houdini ships pxr as a regular Python package instead of a namespace package, so
adding MoonRay's lib/python directory to PYTHONPATH is not enough for imports
such as pxr.MoonrayShaderParser. The Sdr plugins are native USD plugins; these
small Python stubs only prevent Plug from reporting missing Python modules when
the native parser/discovery plugins are loaded.
"""

import os

try:
import pxr

moonray_pxr_path = os.path.join(os.path.dirname(__file__), "pxr")
if hasattr(pxr, "__path__") and moonray_pxr_path not in pxr.__path__:
pxr.__path__.append(moonray_pxr_path)
except Exception:
pass