Add Maya-style Render Layer panel

Render layers built on the existing USD sublayer architecture: each layer is a
file-backed SdfLayer mounted as a sublayer and tagged via custom layer data,
with membership stored in a UsdCollectionAPI on a hidden /RenderLayerData prim.
Activating a layer applies its overrides and isolates it to its members.
"Default" is virtual -- it means all render-layer sublayers muted.

See docs/adr/0002-render-layer.md for the design and rationale.

- RenderLayerManager: create/delete/rename/activate, membership, mute-based
  isolation. Sdf-level APIs are used while a layer is muted (Usd-level APIs
  can't see muted layers) and Usd-level APIs when active.
- Commands: create/delete/rename/activate and add/remove members, all undoable.
- RenderLayerPanel: layer list with one-click activation and a membership
  editor for the selected prims.
- StageEditorPanel / SceneHierarchyPanel: badge render-layer-owned sublayers,
  disable their mute/remove controls (they're managed from the Render Layer
  panel so the two can't desync), and lock the edit target while a non-Default
  layer is active.
- ConnectShaderAttrs/DisconnectShaderAttr: take an explicit editLayer captured
  at construction, so undo targets the same layer as execute even if the
  ambient edit target changed in between (e.g. a render-layer switch).

Note: SceneHierarchyPanel.h also carries declarations for the sublayers
section added in the following commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 10:02:33 +08:00
parent e2a4961ebe
commit b5c1e50438
19 changed files with 1720 additions and 35 deletions
@@ -1,5 +1,6 @@
#include "DisconnectShaderAttrCommand.h"
#include "../../utils/Logger.h"
#include <pxr/usd/usd/editContext.h>
#include <pxr/usd/usdShade/shader.h>
#include <pxr/usd/usdShade/connectableAPI.h>
#include <pxr/base/tf/token.h>
@@ -8,10 +9,12 @@ namespace UsdLayerManager {
DisconnectShaderAttrCommand::DisconnectShaderAttrCommand(pxr::UsdStageRefPtr stage,
const pxr::SdfPath& destNode,
const std::string& destInput)
const std::string& destInput,
pxr::SdfLayerHandle editLayer)
: m_stage(stage)
, m_destNode(destNode)
, m_destInput(destInput)
, m_editLayer(editLayer)
, m_description("Disconnect " + destNode.GetName() + "." + destInput)
{
if (!stage) return;
@@ -38,7 +41,13 @@ void DisconnectShaderAttrCommand::Execute() {
if (!destShader) return;
pxr::UsdShadeInput input = destShader.GetInput(pxr::TfToken(m_destInput));
if (!input) return;
pxr::UsdShadeConnectableAPI::DisconnectSource(input);
if (m_editLayer) {
pxr::UsdEditContext ec(m_stage, m_editLayer);
pxr::UsdShadeConnectableAPI::DisconnectSource(input);
} else {
pxr::UsdShadeConnectableAPI::DisconnectSource(input);
}
} catch (const std::exception& e) {
LOG_ERROR(std::string("DisconnectShaderAttrCommand::Execute error: ") + e.what());
}
@@ -53,8 +62,14 @@ void DisconnectShaderAttrCommand::Undo() {
pxr::UsdShadeInput input = destShader.GetInput(pxr::TfToken(m_destInput));
pxr::UsdShadeOutput output = sourceShader.GetOutput(pxr::TfToken(m_sourceOutput));
if (input && output)
if (!input || !output) return;
if (m_editLayer) {
pxr::UsdEditContext ec(m_stage, m_editLayer);
pxr::UsdShadeConnectableAPI::ConnectToSource(input, output);
} else {
pxr::UsdShadeConnectableAPI::ConnectToSource(input, output);
}
} catch (const std::exception& e) {
LOG_ERROR(std::string("DisconnectShaderAttrCommand::Undo error: ") + e.what());
}