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>
- NodeThumbnailCache/MaterialPreviewRenderer: keep a material node
thumbnail stale (re-pumped each frame) until the shared preview
renderer actually converges, instead of caching after one render
pass. Progressive delegates (Arnold/Cycles/Embree) need multiple
passes to accumulate past their first noisy sample, so thumbnails
previously froze on an early frame and only "fixed themselves"
when toggling thumbnail display forced a fresh render.
- MaterialEditorPanel: add a Color Space row under Asset-typed
shader inputs, authoring the attribute's colorSpace metadata from
the active OCIO config's color spaces.
- MaterialManager: surface Sdr-declared allowed values (enums) per
shader input so the property panel can render a dropdown instead
of free text.
- CMakePresets.json: build the release preset with debug info
(RelWithDebInfo) for easier diagnosis.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Material editor toolbar gets an eye icon to hide/show node thumbnails
(skips the reserved space and decode/render work, not just the
visual) and a 3-dot icon that broadcasts a pin-display mode (All /
Connected / Collapsed) to every node in the open material at once.
The dot icon is shared with the per-node toggle via a parameterized
DrawPinDisplayModeIcon, with dot radius/spacing scaled to fit the
toolbar's fixed icon-button size instead of overflowing it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cycle each node through All -> Connected -> Collapsed -> All via a
custom-drawn icon (filled-dot count encodes how much is shown: 3/2/1).
Collapsed hides every pin on a side, linked or not, behind one
connector nub; existing links now redirect to that nub too
(EffectivePinId), so they visually converge like Hypershade's collapse
view instead of only hiding unconnected pins. Also moved the connector
nubs off the title row onto the node's bottom row. Persisted mode
switches from a bool (uiShowAllPins) to an int (uiPinDisplayMode).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Each node gets an All/Conn toggle: connected-only mode hides
unconnected pins behind collapsed connector nubs on the title row;
dragging a link onto (or from) a nub opens a menu to pick which hidden
pin to wire, and the pin appears once connected. The toggle is drawn
and hit-tested geometrically, and its tooltip is deferred to after
NE::End() so it lands at the cursor. A new Preferences > Material
checkbox opts into persisting the per-node mode as USD customData
(uiShowAllPins); otherwise it stays session-only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Texture nodes show their decoded source image (background thread);
material nodes show a shader-ball render, amortized one-per-frame.
Also classifies shader nodes by Hypershade-style category and adds
an Arnold preset graph alongside the existing USD/MaterialX ones.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drag a link off a pin onto empty canvas to open a create-node menu at
the drop point (the editor's QueryNewNode path), filtered to nodes with a
type-connectable pin; the chosen node is created and auto-wired to the
source pin. Direction is handled both ways — drag from an output makes a
downstream consumer, from an input an upstream producer. Type matching is
lenient (exact, or same scalar/2-/3-/4-vector class), mirroring what USD/
MaterialX networks already tolerate; the target pin is the first exact
match else the first connectable. RenderNodeSearchMenu gained an optional
linkSource arg so the TAB popup and this share one implementation, and
CreateShaderNode now returns the created path. Create and connect are two
undo steps.
Materials list: double-click a row starts an inline rename (mirrors
SceneHierarchyPanel — Enter commits, focus-loss/Esc cancels) through
RenamePrimCommand, which fixes up bindings/arcs via UsdNamespaceEditor.
Selection and the open graph follow the rename. This repurposes the row's
double-click, which previously opened the graph; opening stays on the
Show Graph button.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Toolbar: every action is now an icon button (tooltip carries the label,
text fallback with no icon set) via a local iconBtn helper matching the
StageEditor/Timeline convention — Create Material, Presets, Create + Bind,
Bind Current. Icons fill the standard button height (GetFrameHeight, zero
frame padding) so the row stays uniform.
Browser: the materials list and the create-node list are now split by a
draggable HorizontalSplitter (sibling to the column VerticalSplitter)
instead of a fixed 45% / separator; m_browserListRatio holds the list's
share (clamped 0.15-0.85). Create-node entries get a per-category glyph
(Material/Texture/Geometry/Light/Utility) sized to the text line height.
Silence the temporary node-editor drag-regression tracing: the
[NodeGraph] event-trace block is #if 0'd, its PersistNodePosition logs
commented, and the [ed] g_AxNodeEditorDebugLog hook install is commented
out (the vendored editor's dumps are guarded on that hook).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the imgui-node-editor subset the build actually compiles from
third_party/imgui-node-editor to src/ui/NodeEditor (version-controlled,
MIT LICENSE included). FindImguiNodeEditor.cmake points at the new
location; CMakeLists excludes src/ui/NodeEditor from UI_SOURCES so it
isn't compiled twice.
Material editor presets: a Presets menu (disabled with no open material)
builds a UsdPreviewSurface + UsdUVTexture graph fed by an st primvar
reader, or a MaterialX standard_surface + image graph fed by a texcoord
node. Each is one idempotent, undoable command that re-normalizes layout.
Create Material becomes an icon button. New nodes route through
FindFreeCanvasSpot so a creation never lands on top of an existing node
(overlapping nodes fight over the editor hit test and become undraggable).
Shader-ball preview: pick a previewable output (terminal or 3/4-component
color-like) instead of always the first output, so scalar-only nodes keep
the whole-material preview rather than failing Storm codegen. Per-shape
camera frame-fit margins and auto-clip framing.
Fixes: DeletePrimCommand::Undo recreates missing destination ancestors
before SdfCopySpec (parent material may have been deleted after the
command ran). ConfigWindowsMoveFromTitleBarOnly stops a content-area drag
in the node canvas from moving the whole Material Editor window.
Temporary (marked for removal once the node-editor drag regression is
diagnosed): main.cpp mirrors LOG_INFO to %APPDATA%\UsdLayerManager\
debug.log; a g_AxNodeEditorDebugLog hook in the vendored editor plus a
[NodeGraph] event-trace block in RenderNodeGraphCanvas dump click/drag/
selection/position-save state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Preview geometry dropdown: Sphere / Cube / Cylinder (native prims),
Teapot and Hair (bundled resources/preview/*.usdc - teapot tessellated
from the Newell patch data with the Blinn 1.3x height correction, hair
as 220 procedural B-spline strands), and Cloud Volume (UsdVolVolume
over the OpenVDB bunny_cloud sample, downloaded at CMake configure and
gitignored like the HDRIs). Shapes live under one scope with the
material bound on it; switching activates one shape and reframes the
camera. Missing assets drop out of the dropdown. usdVol added to the
USD link set. The camera starts in a Maya-style 3/4 view.
Node property values switch from Input* fields back to draggable
controls (Ctrl+click to type): live-apply while dragging, one undo
command on release.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the 'Shader Ball' label; the renderer switch and HDR environment
dropdowns sit side by side at the top of the preview column, above the
swatch. Both pickers take an optional item width.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MaterialBrowserWidth / MaterialPreviewWidth in preferences.ini, saved
from the live splitter positions on shutdown and restored (clamped to
the splitter ranges) at startup.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The create-node list is now a two-level tree: a header per node source
(USD, MaterialX, Arnold, Cycles - from the Sdr sourceType, with glslfx
and OSL merged into USD so core nodes don't appear twice) containing
Hypershade-style category sub-trees (Material / Texture / Geometry /
Utility / Light) derived from Sdr context, terminal output types, role,
and name keywords. Duplicate collapsing is per (source, label) so
same-named nodes from different providers both stay; searching forces
all sections open. The TAB popup shows [Source/Category] per entry.
The browser and preview columns get drag splitters (viewport-divider
styling, clamped widths); the canvas absorbs the remainder.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same table anatomy as the attribute inspector: authored-state (a)
mini-button with path/type tooltip and copy-path popup, fixed name
column, stretch value column with row striping. Widgets switch to the
same vocabulary (InputFloat/InputScalarN %.4f, InputInt, default
ColorEdit swatches) committing on deactivation, and connected inputs
render as '-> node.output'. Preview column widens to 320 to fit; the
shader ball centers in it. Per-edit undo commands are kept.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Browser column lists all scene materials plus a searchable create-node
list; Show Graph (or double-click) loads a material into the node-graph
work area. The graph shows the entire network including MaterialX
(.mtlx) node graphs, resolving connections through NodeGraph boundaries
via UsdShadeUtils::GetValueProducingAttributes, with layered auto-layout
for nodes lacking authored uiPosition. Canvas navigates viewport-style
(Alt+MMB pan / Alt+RMB zoom) and TAB opens a Nuke-style search popup.
Selecting a node shows a typed property editor (live-apply, one undo
command per edit) and previews that node's output on the shader ball.
The preview renders through its own Hydra engine into a scratch stage
that composes the material via a reference to the source root layer (so
referenced .mtlx materials work), re-renders until progressive delegates
(Arnold/Cycles/Embree) converge, and lights with HDR dome presets
(External/Room/Interior/Sunset; CC0 Poly Haven EXRs fetched at CMake
configure). texture:format is authored latlong explicitly - left
automatic, hdArnold falls back to Arnold's angular fisheye default -
and hdCycles gets a -90 X pole rotation to match Storm's +Y-pole
sampling.
Mutations go through new ICommand subclasses (create shader node,
connect/disconnect attrs). imgui-node-editor is vendored (gitignored)
with a local one-line patch: c_ScrollButtonIndex 1->2 for MMB pan.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>