Skip to content

HYDRA-2168 : Generic translation of custom Maya plugin nodes to Hydra#400

Open
lanierd-adsk wants to merge 8 commits intodevfrom
lanierd/HYDRA-2168
Open

HYDRA-2168 : Generic translation of custom Maya plugin nodes to Hydra#400
lanierd-adsk wants to merge 8 commits intodevfrom
lanierd/HYDRA-2168

Conversation

@lanierd-adsk
Copy link
Copy Markdown
Collaborator

Summary
Adds a generic fallback adapter (MayaHydraGenericDagAdapter) that automatically translates any unrecognized Maya plugin DAG node to Hydra as a mayaCustomDagNode prim, without maya-hydra needing knowledge of specific plugin node types. Maya built-in nodes are always skipped. Exposes plugin node data via a custom mayaNode data source containing the Maya type name (mayaTypeName) and a dictionary of non-default attribute values (mayaAttributes), with per-attribute dirty locators (mayaNode.mayaAttributes.) for efficient change tracking. Provides an example scene index plugin demonstrating how a render delegate (using Arnold's aiPhotometricLight as an illustration) would consume mayaCustomDagNode prims and re-type/map them to standard Hydra prim types — with zero dependency on maya-hydra headers.

Summary
Adds a generic fallback adapter (MayaHydraGenericDagAdapter) that automatically translates any unrecognized Maya plugin DAG node to Hydra as a mayaCustomDagNode prim, without maya-hydra needing knowledge of specific plugin node types. Maya built-in nodes are always skipped.
Exposes plugin node data via a custom mayaNode data source containing the Maya type name (mayaTypeName) and a dictionary of non-default attribute values (mayaAttributes), with per-attribute dirty locators (mayaNode.mayaAttributes.<attrName>) for efficient change tracking.
Provides an example scene index plugin demonstrating how a render delegate (using Arnold's aiPhotometricLight as an illustration) would consume mayaCustomDagNode prims and re-type/map them to standard Hydra prim types — with zero dependency on maya-hydra headers.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a generic fallback path in maya-hydra to translate previously-unhandled plugin-defined Maya DAG nodes into Hydra, exposing their type name + non-default attributes via a dedicated data source, along with an example renderer-side scene index that can re-type/map those prims (illustrated with Arnold’s aiPhotometricLight).

Changes:

  • Introduce MayaHydraGenericDagAdapter to emit mayaCustomDagNode prims for plugin-registered DAG nodes lacking a dedicated adapter.
  • Add mayaNode container data source (mayaTypeName, mayaAttributes) and mixed-utils support for extracting non-default plugin-specific attributes.
  • Add an Arnold-focused example scene index plugin + new Python/GTest coverage validating prim typing, attribute filtering, and dirty locators.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test/lib/mayaUsd/render/mayaToHydra/cpp/testGenericDagNodeTranslation.py Sets up aiPhotometricLight nodes in Maya and dispatches to C++ verification.
test/lib/mayaUsd/render/mayaToHydra/cpp/testGenericDagNodeTranslation.cpp GTest coverage for prim type, data source contents, default filtering, and dirty locators.
test/lib/mayaUsd/render/mayaToHydra/cpp/CMakeLists.txt Adds new C++ test target source.
test/lib/mayaUsd/render/mayaToHydra/CMakeLists.txt Registers the new interactive Python test script.
lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndex.h Declares generic adapter creation + storage in the scene index.
lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraSceneIndex.cpp Wires generic adapter creation into DAG insertion and pending updates.
lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraGenericNodeDataSource.h Declares mayaNode container data source for generic plugin nodes.
lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraGenericNodeDataSource.cpp Implements mayaTypeName/mayaAttributes data source accessors.
lib/mayaHydra/hydraExtensions/sceneIndex/mayaHydraDataSource.cpp Exposes mayaNode (and xform/visibility/purpose) for mayaCustomDagNode prims.
lib/mayaHydra/hydraExtensions/sceneIndex/CMakeLists.txt Builds/installs the new generic node data source.
lib/mayaHydra/hydraExtensions/plugInfo.json Registers the new adapter type for plugin discovery/metadata.
lib/mayaHydra/hydraExtensions/mixedUtils.h Declares GetNonDefaultMayaAttributesFromNode() helper API.
lib/mayaHydra/hydraExtensions/mixedUtils.cpp Implements non-default attribute extraction with base-class attribute filtering.
lib/mayaHydra/hydraExtensions/adapters/tokens.h Adds convention tokens (mayaCustomDagNode, mayaNode, etc.).
lib/mayaHydra/hydraExtensions/adapters/genericDagAdapter.h Declares the generic fallback DAG adapter contract.
lib/mayaHydra/hydraExtensions/adapters/genericDagAdapter.cpp Implements the adapter + per-attribute dirtying callback.
lib/mayaHydra/hydraExtensions/adapters/CMakeLists.txt Adds the new adapter to the build.
lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/plugInfo.json Example HdSceneIndexPlugin registration (loads with Arnold).
lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/genericNodeTranslationSceneIndexPlugin.h Declares example scene index plugin wrapper.
lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/genericNodeTranslationSceneIndexPlugin.cpp Registers example plugin via HdSceneIndexPluginRegistry.
lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/genericNodeTranslationSceneIndex.h Declares filtering scene index that re-types/maps generic prims.
lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/genericNodeTranslationSceneIndex.cpp Implements example translation of aiPhotometricLight to sphereLight.
lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/CMakeLists.txt Build/install rules for the example plugin library.
doc/genericPluginNodeTranslation.md Documents the conventions, data sources, locators, and the example flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1275 to +1281
static const std::set<std::string>& GetBaseClassAttrNames()
{
static std::set<std::string> names;
static bool initialized = false;
if (!initialized) {
const char* baseTypes[] = { "locator" };
for (const char* typeName : baseTypes) {
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetBaseClassAttrNames() uses a manual lazy-init (static bool initialized) to populate a static std::set. This is not thread-safe and can cause a data race if multiple threads call GetNonDefaultMayaAttributesFromNode() concurrently (Hydra scene index evaluation can be multi-threaded, and BUILD_STRICT_MODE enables -Werror but not concurrency checks). Prefer a thread-safe one-time init (e.g., function-local static initialized via a lambda, or std::once_flag + std::call_once) so the set is constructed exactly once without races.

Copilot uses AI. Check for mistakes.
void _GenericNodeAttrChanged(
MNodeMessage::AttributeMessage msg,
MPlug& plug,
MPlug& otherPlug,
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_GenericNodeAttrChanged has an unused parameter (otherPlug). With the project's -Wall (and -Werror when BUILD_STRICT_MODE is enabled), this can fail the build on some toolchains. Mark it unused (e.g., TF_UNUSED(otherPlug)) or omit the parameter name in the function signature.

Suggested change
MPlug& otherPlug,
MPlug& /*otherPlug*/,

Copilot uses AI. Check for mistakes.
Comment on lines +203 to +206
void HdGenericNodeTranslationSceneIndex::_PrimsAdded(
const HdSceneIndexBase& sender,
const HdSceneIndexObserver::AddedPrimEntries& entries)
{
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'sender' parameter is unused. With the project's -Wall (and -Werror when BUILD_STRICT_MODE is enabled), unused parameters can break strict builds. Consider marking it unused (e.g., TF_UNUSED(sender)) or removing the parameter name in the definition.

Copilot uses AI. Check for mistakes.
Comment on lines +222 to +225
void HdGenericNodeTranslationSceneIndex::_PrimsRemoved(
const HdSceneIndexBase& sender,
const HdSceneIndexObserver::RemovedPrimEntries& entries)
{
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'sender' parameter is unused here as well; consider TF_UNUSED(sender) (or omit the name) to avoid -Wall/-Werror unused-parameter failures in strict builds.

Copilot uses AI. Check for mistakes.
Comment on lines +230 to +233
void HdGenericNodeTranslationSceneIndex::_PrimsDirtied(
const HdSceneIndexBase& sender,
const HdSceneIndexObserver::DirtiedPrimEntries& entries)
{
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'sender' parameter is unused here as well; consider TF_UNUSED(sender) (or omit the name) to avoid -Wall/-Werror unused-parameter failures in strict builds.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +20
// string ("Arnold") to the target renderer's registered name (e.g., "Prman",
// "Prman") and handle the relevant Maya node types in the
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment typo: the example list repeats "Prman" twice ("e.g., "Prman", "Prman""). Replace with distinct examples or a single entry (e.g., "Prman").

Suggested change
// string ("Arnold") to the target renderer's registered name (e.g., "Prman",
// "Prman") and handle the relevant Maya node types in the
// string ("Arnold") to the target renderer's registered name (e.g., "Prman")
// and handle the relevant Maya node types in the

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +82
if (!(msg & MNodeMessage::kAttributeSet)) {
return;
}
if (plug.isChild()) {
return;
}
// Message attributes are connection-only with no data value; skip them.
if (plug.attribute().apiType() == MFn::kMessageAttribute) {
return;
}

auto* adapter = reinterpret_cast<MayaHydraGenericDagAdapter*>(clientData);

MFnAttribute attr(plug.attribute());
TfToken attrName(attr.name().asChar());
HdDataSourceLocator locator(
MayaHydraAdapterTokens->mayaNode,
MayaHydraAdapterTokens->mayaAttributes,
attrName);
adapter->GetMayaHydraSceneIndex()->DirtyPrims({{ adapter->GetID(), HdDataSourceLocatorSet(locator) }});
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The attribute-changed callback dirties mayaNode.mayaAttributes. for all top-level non-message attributes. However, GetNonDefaultMayaAttributesFromNode() explicitly filters out Maya built-in base-class attributes (visibility, worldPosition, castsShadows, etc.), so changes to those attributes will still emit mayaAttributes dirty locators even though the mayaAttributes dictionary will never include them. Consider filtering these out in the callback as well (e.g., skip attributes that belong to Maya base classes) to avoid noisy/inefficient dirtying and better match the "plugin-specific attributes" intent.

Copilot uses AI. Check for mistakes.
…e value, add fixes from copilot comments from code review
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 24 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}

MFnAttribute attr(plug.attribute());
const char* name = attr.name().asChar();
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In _GenericNodeAttrChanged(), const char* name = attr.name().asChar(); stores a pointer into a temporary MString returned by attr.name(). That temporary is destroyed at the end of the statement, so name can be dangling by the time it’s used (e.g., in IsBaseClassAttrName(name) / TfToken attrName(name)). Store the MString in a local variable (or construct TfToken directly from a stable string) before taking asChar().

Suggested change
const char* name = attr.name().asChar();
MString attrNameStr = attr.name();
const char* name = attrNameStr.asChar();

Copilot uses AI. Check for mistakes.

bool MayaHydraGenericDagAdapter::GetVisible()
{
return GetDagPath().isVisible();
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MayaHydraGenericDagAdapter::MarkDirty() bypasses MayaHydraDagAdapter::MarkDirty(), so the base class’s internal visibility cache (_visibilityDirty / _isVisible) is never updated. However, the dirty-plug callbacks use IsVisible(false) to decide whether to invalidate transforms / emit DirtyTransform, so after any visibility change (or if a node starts hidden) those decisions can become permanently stale. Consider either (a) delegating the visibility bookkeeping to the base class (e.g., call MayaHydraDagAdapter::MarkDirty() for DirtyVisibility/DirtyTransform), or (b) keep _isVisible up to date by calling UpdateVisibility() in GetVisible() and/or avoid IsVisible() in these callbacks.

Suggested change
return GetDagPath().isVisible();
// Keep the base-class visibility cache (_isVisible / _visibilityDirty)
// in sync so that IsVisible(false) used by dirty-plug callbacks remains
// accurate even after visibility changes.
UpdateVisibility();
return IsVisible(false);

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +4
set(TARGET_NAME mayaHydraGenericNodeTranslationSceneIndex)

add_library(${TARGET_NAME} SHARED)

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example target won’t be built unless its directory is added from lib/mayaHydra/flowViewportAPIExamples/CMakeLists.txt (currently only adds flowViewportAPILocator/footPrintNode/customShadersNode/simpleHydraGenerativeProceduralPlugin). Add an add_subdirectory(genericNodeTranslationSceneIndex) there (optionally gated by whatever flag controls building examples) so the example is actually compiled/installed.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +783 to +796
if (!_genericsToAdd.empty()) {
for (const auto& obj : _genericsToAdd) {
if (obj.isNull()) {
continue;
}
MDagPath dag;
MStatus status = MDagPath::getAPathTo(obj, dag);
if (!status) {
continue;
}
if (!dag.hasFn(MFn::kTransform)) {
CreateGenericAdapter(dag);
}
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In FlushPendingUpdates(), generic nodes are added via MDagPath::getAPathTo() + CreateGenericAdapter() without the same filtering done in InsertDag() (intermediate objects and instanced paths with instanceNumber > 0). This can cause generic adapters/prims to be created for intermediate objects or for non-zero instances (potential duplicates / inconsistent behavior vs initial population). Consider adding the same checks here (isIntermediateObject, instancing guard) before calling CreateGenericAdapter().

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1385 to +1395
} else if (useMeshAdapter()) {
_addedNodes.push_back(obj);
} else {
_genericsToAdd.push_back(obj);
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above this if/else block says that when not using the mesh adapter the callback only cares about lights and cameras, but the new logic now also queues non-light/camera DAG nodes into _genericsToAdd. Please update or relocate the comment so it accurately reflects the current behavior (lights/cameras plus generic plugin DAG nodes when mesh adapter is disabled).

Copilot uses AI. Check for mistakes.
Comment on lines +236 to +242
void HdGenericNodeTranslationSceneIndex::_PrimsDirtied(
const HdSceneIndexBase& /*sender*/,
const HdSceneIndexObserver::DirtiedPrimEntries& entries)
{
if (!_IsObserved()) return;
_SendPrimsDirtied(entries);
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This filtering scene index re-types mayaCustomDagNode prims (e.g. to sphereLight) and synthesizes new data source keys (UsdLuxTokens->inputs:*), but _PrimsDirtied forwards the upstream dirty locators unchanged. Downstream consumers that rely on locator intersection for the translated schema may not notice changes (e.g. mayaNode.mayaAttributes.intensity doesn’t intersect inputs:intensity). Consider translating/augmenting dirty locators for translated prims (or conservatively dirtying a parent/root locator) so updates propagate correctly after re-typing.

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +64
HdSceneIndexBaseRefPtr
HdGenericNodeTranslationSceneIndexPlugin::_AppendSceneIndex(
const HdSceneIndexBaseRefPtr& inputScene,
const HdContainerDataSourceHandle& inputArgs)
{
return HdGenericNodeTranslationSceneIndex::New(inputScene);
}
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_AppendSceneIndex doesn’t use inputArgs. Other scene index plugins in this repo explicitly silence this (e.g. customPrimvarSceneIndexPlugin.cpp uses TF_UNUSED(inputArgs)). Consider adding TF_UNUSED(inputArgs) here as well to avoid unused-parameter warnings in builds that treat warnings as errors.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lanierd-adsk lanierd-adsk self-assigned this Apr 2, 2026
Copy link
Copy Markdown
Collaborator

@ppt-adsk ppt-adsk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! Just a few minor comments.

)
shapeDefaults = cmds.ls(shapeDefaults, long=True)[0]

self.setHdStormRenderer()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this? Is this not the default? Isn't it irrelevant which is the render delegate?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I removed this. We just need to be in hydra (not VP2)

- Makes no assumption about what the node represents (light, mesh, camera, etc.).

3. **Prim insertion**: The adapter inserts a Hydra prim with type `mayaCustomDagNode` into the scene index. The prim carries these data sources:
- `xform` -- standard Hydra transform from the DAG path.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the flattened xform from the complete Dag path?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I've moddified the doc to specify that.

Comment on lines +56 to +58
cmds.optionVar(stringValue=("mhGenericShape", shape))
cmds.optionVar(stringValue=("mhGenericShapeDefaults",
shapeDefaults))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these optionVar's doing? Would they be needed in an actual deployment?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optionVar calls are a test-only mechanism to pass Maya node paths from the Python test setup to the C++ GTest code. They are not needed in any actual deployment -- they're just a way for the Python side to tell the C++ side "here are the node names I created, so you can look them up in the Hydra scene index."

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's nothing wrong with that, but I believe this requirement is already covered by arguments to the mayaHydraCppTest command, so we don't need to create a new mechanism. See

cmds.mayaHydraCppTest(cubeObjectName, "mesh", f="TestPicking.pickObject")

auto [argc, argv] = getTestingArgs();

// Skip plugin nodes that already provide their own Hydra scene index
// (e.g. mayaUsdProxyShape contributes USD data through registration.cpp).
// Translating them generically would create duplicate prims in the scene.
static const char* kSceneIndexProviderTypes[] = { "mayaUsdProxyShape" };
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to find a way to make this extensible...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually removed that hardcoded string and I am using the dataProducer registered in flow viewport API as the exclude list as these are already providing their own hydra translation.
The new code is :
// Skip plugin nodes that already provide their own Hydra data through
// the Flow Viewport data producer API. Their MObjectHandle hash code
// is registered in DataProducersNodeHashCodeToSdfPathRegistry when
// they call addDataProducerSceneIndex() with a dccNode pointer.
MObjectHandle nodeHandle(dagPath.node());
if (!Fvp::DataProducersNodeHashCodeToSdfPathRegistry::Instance()
.GetPath(nodeHandle.hashCode()).IsEmpty()) {
return {};
}

Comment on lines +130 to +155
auto getFloat = [&](const char* key, float def) -> float {
auto it = mayaAttrs.find(key);
if (it != mayaAttrs.end() && it->second.IsHolding<float>())
return it->second.UncheckedGet<float>();
if (it != mayaAttrs.end() && it->second.IsHolding<double>())
return static_cast<float>(it->second.UncheckedGet<double>());
return def;
};
auto getVec3f = [&](const char* key, GfVec3f def) -> GfVec3f {
auto it = mayaAttrs.find(key);
if (it != mayaAttrs.end() && it->second.IsHolding<GfVec3f>())
return it->second.UncheckedGet<GfVec3f>();
return def;
};
auto getString = [&](const char* key, std::string def) -> std::string {
auto it = mayaAttrs.find(key);
if (it != mayaAttrs.end() && it->second.IsHolding<std::string>())
return it->second.UncheckedGet<std::string>();
return def;
};
auto getBool = [&](const char* key, bool def) -> bool {
auto it = mayaAttrs.find(key);
if (it != mayaAttrs.end() && it->second.IsHolding<bool>())
return it->second.UncheckedGet<bool>();
return def;
};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be converted into a template, it seems. Also, why are doubles converted to floats?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The four separate lambdas have been consolidated into a single generic getAttr lambda using auto parameter deduction (C++14) and if constexpr (C++17) for the float specialization. I've added a comment which explains why doubles are narrowed to floats: Maya stores many numeric attributes as doubles internally, but Hydra light schemas expect floats.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +64 to +65
* See flowViewportAPIExamples/genericNodeTranslationSceneIndex/ for a complete
* example that translates aiPhotometricLight to a UsdLux sphereLight for Arnold.
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment references the example path as flowViewportAPIExamples/genericNodeTranslationSceneIndex/, but the example added in this PR lives under lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/. Updating the path (or making it repository-relative in a consistent way) would avoid confusion for readers trying to locate the example.

Suggested change
* See flowViewportAPIExamples/genericNodeTranslationSceneIndex/ for a complete
* example that translates aiPhotometricLight to a UsdLux sphereLight for Arnold.
* See lib/mayaHydra/flowViewportAPIExamples/genericNodeTranslationSceneIndex/
* for a complete example that translates aiPhotometricLight to a UsdLux
* sphereLight for Arnold.

Copilot uses AI. Check for mistakes.
ppt-adsk
ppt-adsk previously approved these changes Apr 9, 2026
* delegate's scene index to react to specific attribute changes without
* recomputing everything.
*/
class MayaHydraGenericDagAdapter : public MayaHydraDagAdapter
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MayaHydraGenericDagAdapter is a bit confusing, sounds like similar as MayaHydraDagAdapter, would MayaHydraCustomDagAdapter be better?

// The original xform and visibility data sources from maya-hydra are preserved
// via HdOverlayContainerDataSource.
HdSceneIndexPrim
HdGenericNodeTranslationSceneIndex::_TranslatePhotometricLight(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to see an example, how the the rendering result looks like with PhotometricLight in HdArnold?

_shapeAdapters,
_lightAdapters,
_cameraAdapters,
_materialAdapters);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add _genericAdapters here when dealing _adaptersToRebuild?

// Maya callback invoked when any attribute on the generic node is modified.
// Fires a per-attribute dirty locator (mayaNode.mayaAttributes.<attrName>)
// so downstream scene indices can react to specific attribute changes.
void _GenericNodeAttrChanged(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have extension/custom attributes on custom node? If yes, how did we handle this case?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants