diff --git a/libs/common/constant_strings.h b/libs/common/constant_strings.h index 2404d6ed3..4fa804b26 100644 --- a/libs/common/constant_strings.h +++ b/libs/common/constant_strings.h @@ -447,6 +447,7 @@ ASTR(plugin_searchpath); ASTR(point_light); ASTR(points); ASTR(polymesh); +ASTR(portal_light); ASTR(procedural_custom); ASTR(procedural_searchpath); ASTR(progressive); diff --git a/plugins/node_registry/parser.cpp b/plugins/node_registry/parser.cpp index f8af4a061..cb6963714 100644 --- a/plugins/node_registry/parser.cpp +++ b/plugins/node_registry/parser.cpp @@ -69,6 +69,9 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens, (uisoftmax) (enumValues) (attrsOrder) + (nodeType) + (usdSchema) + (light) (binary)); // clang-format on @@ -408,21 +411,41 @@ ShaderNodeUniquePtr NdrArnoldParserPlugin::PARSE_FUNC(const ShaderNodeDiscoveryR _ReadShaderAttribute(attr, properties, ""); } + // Resolve the SdrShaderNode context. The discovery plugin emits + // `discoveryResult.discoveryType == "arnold"` so the parser plugin is + // routed correctly (see GetDiscoveryTypes() below), but the *context* + // we register the node under should reflect its role in a USD material + // network. Lights tagged with `nodeType == "light"` in customData are + // registered under SdrNodeContext->Light ("light") so DCC-agnostic + // tools can enumerate them via `Sdr.Registry.GetShaderNodesByContext("light")`. + // Everything else stays under the legacy "arnold" context for backwards + // compatibility with existing consumers. + TfToken context = discoveryResult.discoveryType; + auto nodeTypeIt = primCustomData.find(_tokens->nodeType); + if (nodeTypeIt != primCustomData.end() && + nodeTypeIt->second.IsHolding() && + nodeTypeIt->second.UncheckedGet() == _tokens->light.GetString()) { + context = _tokens->light; + } + // Now handle the metadatas at the node level ShaderTokenMap metadata; for (const auto &it : primCustomData) { - // uigroups was handled above - if (it.first == _tokens->uigroups || it.first == _tokens->attrsOrder) + // uigroups was handled above; nodeType is an internal routing marker + // (already consumed to compute `context`) and must not leak into the + // user-visible metadata map. + if (it.first == _tokens->uigroups || it.first == _tokens->attrsOrder || + it.first == _tokens->nodeType) continue; metadata.insert({TfToken(it.first), TfStringify(it.second)}); } - + return ShaderNodeUniquePtr(new SdrShaderNode( discoveryResult.identifier, // identifier discoveryResult.version, // version discoveryResult.name, // name discoveryResult.family, // family - discoveryResult.discoveryType, // context + context, // context discoveryResult.sourceType, // sourceType discoveryResult.uri, // uri discoveryResult.uri, // resolvedUri diff --git a/plugins/node_registry/utils.cpp b/plugins/node_registry/utils.cpp index da2a685d2..1bbde8d4b 100644 --- a/plugins/node_registry/utils.cpp +++ b/plugins/node_registry/utils.cpp @@ -59,11 +59,37 @@ TF_DEFINE_PRIVATE_TOKENS(_tokens, (uisoftmax) (enumValues) (attrsOrder) + (nodeType) + (usdSchema) + (light) ); // clang-format on namespace { +// Maps an Arnold light node entry name to the corresponding stock USD light +// prim type (UsdLux / UsdImaging). Recorded as the "usdSchema" node-level +// metadata on the registered SdrShaderNode so DCC-agnostic tools can write +// arnold lights to USD layers without guessing. Lights not in this table +// (e.g. third-party lights surfaced via AI_NODE_LIGHT) are still registered +// under context "light" but without a usdSchema hint. +const std::unordered_map& _GetArnoldLightToUsdPrimType() +{ + static const std::unordered_map ret = { + {"distant_light", "DistantLight"}, + {"disk_light", "DiskLight"}, + {"quad_light", "RectLight"}, + {"cylinder_light", "CylinderLight"}, + {"skydome_light", "DomeLight"}, + {"point_light", "SphereLight"}, + {"spot_light", "SphereLight"}, + {"photometric_light", "SphereLight"}, + {"mesh_light", "GeometryLight"}, + {"portal_light", "PortalLight"}, + }; + return ret; +} + // TODO(pal): All this should be moved to a schema API. // The conversion classes store both the sdf type and a simple function pointer @@ -411,6 +437,16 @@ void _ReadArnoldShaderDef(UsdStageRefPtr stage, const AtNodeEntry* nodeEntry) } else if (nodeEntryType == AI_NODE_IMAGER || nodeEntryType == AI_NODE_OPERATOR) { // create an output type for imagers prim.CreateAttribute(_tokens->output, SdfValueTypeNames->String, false); + } else if (nodeEntryType == AI_NODE_LIGHT) { + // Tag the prim so the parser registers it under SdrNodeContext->Light + // and record the corresponding stock USD light prim type, if any. + primCustomData[_tokens->nodeType] = _tokens->light.GetString(); + const auto& usdPrimTypeMap = _GetArnoldLightToUsdPrimType(); + const std::string nodeName = AiNodeEntryGetName(nodeEntry); + auto it = usdPrimTypeMap.find(nodeName); + if (it != usdPrimTypeMap.end()) { + primCustomData[_tokens->usdSchema] = it->second; + } } VtArray attrsOrder; @@ -567,7 +603,8 @@ UsdStageRefPtr NodeRegistryArnoldGetShaderDefs() #endif } - auto* nodeIter = AiUniverseGetNodeEntryIterator(AI_NODE_SHADER | AI_NODE_IMAGER | AI_NODE_OPERATOR); + auto* nodeIter = AiUniverseGetNodeEntryIterator( + AI_NODE_SHADER | AI_NODE_IMAGER | AI_NODE_OPERATOR | AI_NODE_LIGHT); while (!AiNodeEntryIteratorFinished(nodeIter)) { _ReadArnoldShaderDef(stage, AiNodeEntryIteratorGetNext(nodeIter));