Commit Graph

66 Commits

Author SHA1 Message Date
indigo bb9a5d9428 Author shader-ball node-preview overrides in the session layer
Fixes 'No spec at </Materials/...> when trying to set field
primChildren' during pin edits: the per-revision wipe used raw spec
surgery (RemoveNameChild/RemoveProperty) plus a ClearReferences/
AddReference cycle that briefly leaves the material's over spec empty
and inert, which Sdf cleanup can delete out from under later authoring.

The reference to the source material is now authored only when the
material changes (shared in-memory layers recompose live), and all
node-preview overrides live in the preview stage's session layer,
wiped wholesale with SdfLayer::Clear — no spec-level removal remains,
and switching materials no longer leaves stale overrides behind. The
edit target is pinned to the root layer so the rig never lands in the
cleared session layer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 23:09:05 +08:00
indigo b08bb6b233 Style material editor node properties like PropertyPanel
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>
2026-07-04 23:09:05 +08:00
indigo 09819091c4 Add Hypershade-style Material Editor with node graph and shader-ball preview
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>
2026-07-04 20:44:54 +08:00
indigo 338970b243 Mask viewport split dividers under floating windows
The divider hit-zones are raw screen rects; gate them on
IsWindowHovered(ChildWindows) so a window stacked over the viewport
(e.g. the Material Editor) doesn't highlight or start a resize drag
through it. In-progress drags still track until release.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 20:44:36 +08:00
indigo 0640201d5b Add keyable attrs, clear override, material binding, and API schema groups to PropertyPanel
Attributes with SdfVariabilityVarying now show a (k) button when the
timeline is at a non-default frame. Orange = exact time sample at the
current frame; gray = no sample here. Clicking keys the current value
via AttributeSetCommand (undoable).

Right-click on any attribute or relationship name opens a context menu
with "Clear Override" (greyed when nothing is authored at the edit
target). Undo restores all previously authored time samples and default
values.

Prims with UsdShadeMaterialBindingAPI now show a "Material Binding"
collapsing section above the transform block, listing Direct / Preview /
Full purpose bindings and the resolved computed material path.

RenderPropertiesTable now groups attributes and relationships under
CollapsingHeader sections named after their USD API schema. Base-type
attributes (e.g. Mesh, Xform) appear first; applied API schema groups
(MaterialBindingAPI, CollectionAPI, etc.) follow alphabetically.
Uncategorised attributes are bucketed by namespace prefix (primvars,
inputs, outputs, …). xformOp attrs are still filtered out (shown in the
TRS section above).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 07:13:21 +08:00
indigo f7a2262e80 Add multi-select, specifier column, and visibility shortcuts to hierarchy panel
Ctrl+click toggles prim selection; Shift+click range-selects using a
per-frame visible-order list. Multi-selection is broadcast to the viewport
via a new SetOnPrimsSelected callback so Hydra highlights all selected prims.

Adds a 5th table column showing each prim's SdfSpecifier (def/over/class)
with colour coding. 'over' prims are shown in orange to make overrides
immediately visible.

Visibility icon updated: invisible prims show EyeSlash in orange instead
of grey. Ctrl+H / Shift+H keyboard shortcuts hide / show all selected prims.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 07:04:22 +08:00
indigo 781d464f47 Add per-viewport cull style option
Exposes UsdImagingGLCullStyle as a Cull Style sub-menu in the gear popup
(Back Unless Double-Sided / Back / Front / Nothing / No Opinion). Defaults
to BackUnlessDoubleSided, matching usdview. Setting persists per-viewport
to viewport_settings.ini.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 08:15:20 +08:00
indigo 7586d380e9 Move Purpose toggles into a Purpose sub-menu in the gear popup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 07:21:31 +08:00
indigo 1c55907573 Add renderer purpose display toggles (Guide, Proxy, Render)
Exposes UsdGeomImageable purpose visibility as three per-viewport toggles
in the gear popup (Purpose: Guide / Proxy / Render), wired to
showGuides/showProxy/showRender on UsdImagingGLRenderParams. Defaults match
the USD render params defaults (Proxy on, Guide and Render off). Settings
persist per-viewport to viewport_settings.ini.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 07:02:35 +08:00
indigo 205bf65ab3 Add renderer settings dialog with tab categories per delegate
Surfaces each render delegate's settings (FLAG/INT/FLOAT/STRING) in a
per-viewport floating dialog opened from the gear popup. Settings are grouped
into tabs by key namespace prefix (split at ':'); unprefixed keys go into
General. Changes apply immediately; Reset Defaults restores defValues.
Settings list is cached per delegate to avoid TF_WARN flooding the log on
every frame.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 04:34:53 +08:00
indigo 862f3c9745 Add per-viewport AOV selection (stageView.py GetRendererAovs port)
Exposes the render delegate's available AOVs in the gear popup under a new
"AOV" sub-menu. Selecting an AOV calls SetRendererAov on the engine and
persists the choice per-viewport in viewport_settings.ini. Switching the
render delegate resets the AOV to "color", matching stageView.py's
_handleRendererChanged. Menu is greyed-out when the delegate reports no AOVs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 03:03:00 +08:00
indigo 6adf022c13 Add Camera Guide viewport toggle (stageView.py DrawCameraGuides port)
Adds a per-viewport "Camera Guide" toggle (default off) that draws a full
frustum wireframe box (near quad + far quad + 4 connecting edges) in oracle
orange for every non-active UsdGeomCamera prim, matching usdview's
displayCameraOracles behaviour. Uses GfFrustum::ComputeCorners() and the
same 24-index line layout as DrawCameraGuides. Toggle exposed in the
right-click context menu and gear popup; persists to INI as ShowCameraGuide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 02:35:39 +08:00
indigo a59b3a5405 Replace custom ViewportColorCorrector with stageView.py color correction
Remove the custom GL post-process (ViewportColorCorrector) that bypassed
HdxColorCorrectionTask. Instead pass colorCorrectionMode, ocioDisplay,
ocioView, ocioColorSpace, and ocioLook directly to UsdImagingGLRenderParams
and SetColorCorrectionSettings(), delegating correction to Hydra —
the same approach used in usdview's stageView.renderSinglePass().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 01:35:06 +08:00
indigo 45d1cc4391 Add screen shot for MaterialX display 2026-06-29 08:25:19 +08:00
indigo cb0d72d980 Add global Preferences dialog and per-viewport render delegate
Preferences (Edit > Preferences, tabbed General/Animation/Viewport):
- Viewport tab: Default Render Delegate and Color Correction settings
- Persisted to %APPDATA%\UsdLayerManager\preferences.ini
- Render delegate: startup default only (not live-applied to running tiles)
- Color correction: global, applied live to all viewports on change

Render delegate per-viewport:
- Each tile toolbar switches its own delegate independently
- Saved per-tile in viewport_settings.ini; restored on next launch
- Tiles with no saved delegate get the pref default on startup

Color correction global:
- Removed from gear popup; lives in Preferences > Viewport only
- Applied to all tiles on init and on live change from Preferences

Fix InitRenderer always applying m_currentRendererPlugin when set,
rather than skipping when UsdImagingGLEngine auto-selects a default.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 11:43:32 +08:00
indigo b02a736da0 Fix prim expiry crashes and add context menu hierarchy ops
Crash fixes (expired UsdPrim after namespace edits):
- RenderPrimNode: early-out after rename commit (renamed flag + column cleanup)
- RenderPrimNode: early-out after context menu op expires prim (prim.IsValid() guard)
- RenderContextMenu: EndPopup+return when Unparent/Group expires prim mid-popup
- Child iteration: snapshot GetChildren() into vector before recursing to guard
  against live iterator invalidation from stage mutations deeper in the tree
- Rename: firstFrame guard prevents spurious IsItemDeactivated cancel on
  SetKeyboardFocusHere activation frame (fixes second-rename not working)
- RenamePrimCommand: check RenamePrim() return value, log if rejected

New features:
- Context menu Add Child submenu: create typed child prim under selection
- Context menu Unparent to Root: move prim to stage root (undo-able)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 03:43:01 +08:00
indigo b31ca69d4f Add Maya-style prim editing to SceneHierarchyPanel
- Inline rename: double-click prim label or F2 to edit name in-place;
  Enter commits, click-away or Esc cancels (undo-able)
- Drag-and-drop reparent: drag any prim onto another to make it a child;
  invisible root drop zone below tree to reparent to stage root (undo-able)
- Ctrl+G group: creates Xform group at common parent, reparents selection
  under it; filters descendant duplication; selects new group (undo-able)
- Delete key shortcut: opens existing remove-prim modal when panel focused
- Context menu: Rename (F2) and Group (Ctrl+G) items added
- Three new undo-able commands using UsdNamespaceEditor (USD 25.05):
  RenamePrimCommand, ReparentPrimCommand, GroupPrimsCommand

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:44:55 +08:00
indigo 88ae8ccefa Update CLAUDE.md 2026-06-27 18:41:41 +08:00
indigo 46d83d300d Add ADR for custom viewport color correction
Document the decision to replace HdxColorCorrectionTask with a custom GL
post-process (linear render + sRGB/OCIO correction via the OCIO GPU API),
including rationale, pipeline, consequences, and alternatives considered.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:13:46 +08:00
indigo fb1ae9d3a6 Add custom viewport color correction (sRGB/OCIO), bypassing HdxColorCorrectionTask
Hydra's HdxColorCorrectionTask rendered prims black in OCIO mode and could
corrupt the GlfDrawTarget bind stack on failure (skipping Unbind), blacking
out every later frame including sRGB. Replace it with our own GL post-process:
the scene renders linear (RGBA16F) and is corrected by a fullscreen shader --
linear->sRGB encode, or OCIO via the OCIO 2.1 GPU API (GpuShaderDesc plus
uploaded 1D/3D LUT textures). OCIO build failures fall back to sRGB (never
black) and USD diagnostics are routed to the app log.

- core: ViewportColorCorrector + ApplyViewportColorCorrection in UsdSceneRenderer
- utils: OcioConfigParser enumerates displays/views/colorspaces/looks from $OCIO
- ui: gear-menu OCIO controls (ViewportTile) + per-viewport persistence (ViewportPanel)
- Application: point $OCIO at the bundled ACES 1.2 config
- CMake: link/copy OpenColorIO, download ACES 1.2 config; plus hdCycles build
  config (disable OpenVDB/Embree, fix TBB/OpenSubdiv/Imath dirs, exclude CRT DLLs)
- main: pre-flight plugin DLL load check to skip plugins with missing deps

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:10:44 +08:00
indigo 8316e419ba Add gear icon toolbar button with viewport options dropdown
Adds a ⚙ icon button to the right of the AA toggle in each viewport
tile's compact toolbar.  Clicking it opens a dropdown with:
  - Shading submenu: Smooth Shaded / Flat Shaded / Wireframe on Surface /
    Wireframe / Unlit  (new ShadingMode enum driving UsdImagingGLDrawMode)
  - Lighting submenu: Camera Headlight / Scene Lights + Dome Light toggle
  - Show Grid and Anti-Aliasing toggles (mirrored from icon buttons)
  - Bounding Box submenu: None / Per Object / All Selection
  - Background submenu: Dark Gray / Black / Light Gray / Midnight Blue

ShadingMode is persisted in viewport_settings.ini alongside the existing
per-tile settings (saved on shutdown, restored on startup).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 09:56:49 +08:00
indigo 9d8840ced6 Add per-viewport render settings persistence (delegate, grid, AA, bg, bbox, lighting)
ViewportTileSettings struct captures: render delegate, show grid, AA, background
color, bbox mode, ambient-light-only, dome-light flags.

ViewportPanel::SaveSettings() writes a simple INI file (layout + one [TileN]
section per tile) to %APPDATA%\UsdLayerManager\viewport_settings.ini on
Application::Shutdown().

ViewportPanel::LoadSettings() is called at the end of Application::Initialize()
— after the viewport panel is constructed but before the first frame — so the
saved render delegate is picked up by UsdSceneRenderer::InitRenderer() on the
first Render() call.  Layout (Single/HSplit/VSplit/Quad) and split ratios are
also restored, creating the correct number of tiles before settings are applied.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 09:34:00 +08:00
indigo 4b7323c24c Fix hdCycles DLL init failure in install: exclude bundled CRTs, add python311.dll
Two independent fixes for the install layout:

1. Cycles bundles old MSVC CRT DLLs (MSVCP140 v14.34, VCRUNTIME140 v14.34)
   that are placed in install/bin/ via the CYCLES_INSTALL_DIR copy. These take
   precedence over System32 on the DLL search path. sycl8.dll (built with newer
   VS2022 CRT v14.42) calls functions that don't exist in the old version, causing
   ERROR_DLL_INIT_FAILED (1114) when hdCycles.dll loads embree4 -> sycl8. Fix:
   exclude MSVCP140*.dll, VCRUNTIME140*.dll, ucrtbase*.dll, api-ms-win-*.dll from
   the install(DIRECTORY cycles_install/) rule. The system VC++ Redistributable
   satisfies these at runtime.

2. usd_python.dll (the OpenUSD Python bindings DLL) was compiled against Python
   3.11 while our build targets Python 3.12. Add auto-detection of python311.dll
   from common install paths and deploy it to both the build output and install/bin/
   so the dependency chain hdCycles->usd_python->python311 is satisfied.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 09:07:38 +08:00
indigo e85944ccb6 CMake install: fix Hydra plugin path and include all built delegates
plugin/usd without a trailing slash made CMake install the directory
itself under bin/usd/, landing plugins at bin/usd/usd/hdStorm/ etc.
(one level too deep). Adding the trailing slash installs the contents
directly into bin/usd/, matching the build-directory layout that
POST_BUILD produces via copy_directory.

Also removed the now-redundant install(FILES hdStorm.dll DESTINATION bin)
which was placing the DLL in the exe root instead of bin/usd/ where
plugInfo.json's LibraryPath expects it.

hdEmbree, hdArnold, and hdCycles install rules were already correct
(they explicitly target bin/usd/); this change makes the base USD
plugin/usd contents consistent with them.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 20:42:52 +08:00
indigo ab934d0818 Save imgui.ini to %APPDATA%\UsdLayerManager\ instead of CWD
Sets io.IniFilename to %APPDATA%\UsdLayerManager\imgui.ini right after
CreateContext so ImGui never touches the working directory for layout
persistence. The directory is created on first run via create_directories.
m_iniFilePath on ImGuiContext holds the string so the pointer stays valid
for the lifetime of the context.

Also removes imgui.ini from version control and adds it to .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 20:36:25 +08:00
indigo 08f4bd351b Add Screen Shot for Render Delegate 2026-06-24 09:34:20 +08:00
indigo ddffa5764c Curve editor: fix repeated Apply after bake
Three bugs prevented Apply from working correctly after the first bake:

1. m_needsRefresh spuriously set during bake
   ClearAllTimeSamples/WriteChannelValue fire OnObjectsChanged synchronously.
   Since the channel is dirty at that moment, it was skipped, setting
   anyMatchedChannel=false and triggering m_needsRefresh=true. This caused
   RefreshFromStage() on the next frame, clearing m_selection and rebuilding
   m_channels — dropping the user's edit context. Fixed with m_suppressNotice:
   set true during USD writes so OnObjectsChanged is a no-op during bake.

2. Prim-level metadata notice triggered rebuild
   SaveBezierToMetadata calls SetCustomDataByKey, which fires a notice with
   changed==primPath. No attribute channel matched, so m_needsRefresh=true
   again. Fixed in OnObjectsChanged: skip changed==primPath (metadata-only
   changes), and mark a path as "known" even if the channel is dirty (so
   the refresh gate only fires for genuinely new/unknown attributes).

3. Dangling chPtr in undo/redo closures
   After RefreshFromStage() cleared and rebuilt m_channels, the raw pointer
   captured in closures pointed to freed memory. Replaced with a findCh
   lambda that searches m_channels by attr path + component at call time.
   Falls back to m_needsRefresh=true if the channel no longer exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:28:09 +08:00
indigo e8a73674ad Curve editor: fix context menu, persist Bezier metadata, always-visible handles
Context menu fix:
- Move RMB popup and hit-test lambdas before the early-return guard in
  HandleCanvasInput so BeginPopup is called every frame while the popup is
  open, regardless of whether the mouse has left the canvas area.
  Previously the early-return fired (hovered=false) the moment the mouse
  moved onto the menu, silently closing it before any item could register.

Bezier metadata persistence:
- On Apply/bake, write each channel's BezierKey array into
  prim.customData["curveEditor"]["channels"][attrName@component] as flat
  double[]/int[] arrays (times, values, inDt, inDv, outDt, outDv, broken).
- FitCurveFromSamples tries LoadBezierFromMetadata first; falls back to
  Catmull-Rom only when no saved entry exists, so tangent shapes survive
  file save/reload.
- Bake undo command snapshots the entire curveEditor customData value and
  restores it on Ctrl+Z, keeping metadata in sync with sample history.

Always-visible tangent handles:
- Remove keySel guard so in/out handle lines and circles render for every
  keyframe, not just selected ones.
- hitTestHandle now iterates all visible channels/keys so any handle can
  be clicked directly without first selecting its parent keyframe.
- Clicking a handle auto-selects the parent key as well, keeping context
  menu operations (Flatten, Break, Delete) consistent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 09:07:01 +08:00
indigo e0597ae31d Add screen shot for curve editor 2026-06-24 08:26:13 +08:00
indigo 425d21db45 Add animation curve editor with Bezier F-curve round-trip
Maya-style Graph Editor panel (View > Curve Editor) that fits Catmull-Rom
Bezier curves through USD time samples, allows interactive editing with
tangent handles, and bakes the result back to dense linear samples on Apply.

Key behaviours:
- Left panel lists all animated attributes of the selected prim, decomposed
  into per-component channels (translate [X/Y/Z], etc.) with colour swatches
  and visibility toggles
- ImDrawList canvas: smooth Bezier polylines, always-visible tangent handle
  lines/circles, diamond keyframe markers
- Pan (MMB/Alt+drag), zoom (scroll / Shift+scroll), Frame All (F)
- LMB drag moves keyframes; tangent handle drag reshapes curve with mirrored
  or broken handles; box-select for multi-selection
- Double-click canvas adds a keyframe; Delete removes selected keyframes
- RMB context menu: Delete, Flatten, Break/Unify Tangents, Auto Tangents
- Simplify toggle (Ramer-Douglas-Peucker) reduces baked sample count
- Time cursor draggable to scrub the timeline
- UsdNotice::ObjectsChanged listener re-fits clean channels whenever the
  stage changes externally (Property Panel edits, Auto-Key, undo/redo),
  while preserving channels with unsaved Bezier edits
- Bake is a single undoable AttributeSetCommand (Ctrl+Z restores original
  sparse samples); Revert discards in-editor edits without touching USD

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 08:25:25 +08:00
indigo 0538dd3243 Add playblast: viewport capture to H.264 MP4 via libavcodec
- TimelinePanel: Playblast button opens modal with output dir (native
  folder picker via IFileOpenDialog), custom resolution (HD/FHD/4K
  presets), frame range, and movie export toggle
- UsdSceneRenderer: CaptureFrame() reads pixels from resolved MSAA FBO;
  Render() stores last dimensions for off-screen re-render at capture res
- MovieEncoder: streams RGBA frames directly into MP4 using libavcodec/
  libswscale (H.264, tries libx264 → nvenc → qsv → amf → openh264)
- Application: CapturePlayblastFrame() re-renders at capture resolution
  each frame; opens/writes/closes MovieEncoder inline with the render loop
- FileDialog: BrowseFolder() using Vista-style IFileOpenDialog (COM)
- CMake: FindFFmpeg.cmake locates prebuilt BtbN GPL shared package in
  third_party/ffmpeg; links and copies DLLs for main and test targets

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-23 09:36:30 +08:00
indigo c796c76561 Renderer: suppress camera headlight when stage contains authored lights
Mirrors usdview behaviour -- when the stage has at least one UsdLux
light the default camera fill-light is disabled so the scene is lit
purely by its authored lights.  StageHasAuthoredLights() early-exits
on the first HasAPI<UsdLuxLightAPI>() hit to keep the per-frame cost
minimal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 08:17:10 +08:00
indigo 2649fe814c Add light shape wireframe display in viewport
Draw a type-appropriate wireframe gizmo for every UsdLux light in the stage,
mirroring the existing camera-wireframe overlay (dedicated VAO/VBO reusing the
bbox shader, drawn on top with depth-test off).

Shapes, built in the light's local space and pushed through its local-to-world
transform:
  - SphereLight   3 orthogonal circles (radius); axis-cross when treatAsPoint
  - RectLight     width x height rectangle + emission direction line
  - DiskLight     circle + direction line
  - CylinderLight two end-cap circles + connectors (radius/length)
  - DistantLight  sun disc + parallel rays
  - DomeLight     3 large display-scaled circles

Selected lights draw accent orange, others warm yellow.

Verified by creating a SphereLight (3-circle sphere) and a RectLight
(rectangle) in-app: distinct shapes, correct selected/deselected colours,
gizmos visible over geometry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 07:56:47 +08:00
indigo a24eff04bd CMake: drop invalid OPTIONAL from Cycles runtime-deps install
install(DIRECTORY) disallows OPTIONAL together with FILES_MATCHING, which
broke reconfigure. The directory is always present here (produced by the
CyclesBuild step), so OPTIONAL was unnecessary.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:49:29 +08:00
indigo 4d3cc85ece Fix rotate manipulator desync on already-rotated prims
The matrix->Euler decode at the end of a rotate drag used the rows of the
prim's initial rotation matrix (its already-rotated frame) as the
DecomposeRotation axes. But UsdGeomXformCommonAPI::SetRotate interprets the
written angles about the CANONICAL x/y/z axes, so the two only agreed when
the prim was at zero rotation -- the authored orientation desynced from the
manipulator the moment the prim already carried a rotation.

Decompose the result matrix about the canonical axes instead, matching how
SetRotate reconstructs it. The result-matrix computation (which correctly
tracks the visual ring axis) is unchanged.

Verified numerically via the real XformCommonAPI authoring path: from
rotateXYZ=(30,45,60), a +20deg object-X drag now authors exactly
(50,45,60) (err 0.0) vs the old decode's (41.07,27.07,66.61) (err 0.287).

Assumes RotationOrderXYZ (the XformCommonAPI default); non-XYZ orders are
mapped as before -- noted in a code comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:49:22 +08:00
indigo 119a55b1aa docs: add renderer version requirements to render delegate table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:30:34 +08:00
indigo 3210c16c7f docs: update README with render delegate support and Cycles build notes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:22:54 +08:00
indigo 7b1fe91cac CMake: add hdCycles Hydra delegate build and deployment
- Build Cycles from third_party/cycles via ExternalProject (WITH_CYCLES=ON)
- Deploy hdCycles.dll + plugin metadata to usd/ alongside hdEmbree/hdArnold
- Copy Cycles runtime deps (embree4, openvdb, OIDN, sycl, imath, etc.) via
  a cmake -P script that globs at build time, excluding CRT DLLs to avoid
  MSVCP140 version conflicts
- Deploy tbb12.dll explicitly from the precompiled lib tree (required by
  openvdb/embree4 but absent from the install output)
- Bake all renderer paths into CMakePresets.json default preset
  (WITH_CYCLES, HDARNOLD_ROOT -> E:/library/hdArnold, ARNOLD_LOCATION,
  HDEMBREE_USD_ROOT) so a fresh configure needs no manual -D flags

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 10:08:01 +08:00
indigo 81f9e9b4e4 CMake: add hdArnold plugin detection and deployment
Adds HDARNOLD_ROOT and ARNOLD_LOCATION cache variables to detect and deploy
the arnold-usd Hydra render delegate (hdArnold.dll, ndrArnold.dll) built from
arnold-usd Arnold-7.4.0.0 against MtoA 5.5.0. DLLs land in usd/ alongside
their plugInfo metadata dirs so LibraryPath ../hdArnold.dll resolves correctly.
ai.dll is copied to the exe root for Windows DLL search resolution.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 23:22:52 +08:00
indigo 364973fb65 CMake: fix hdEmbree.dll deployment path -- copy to usd/ not exe root
plugInfo.json declares LibraryPath '../hdEmbree.dll', relative to usd/hdEmbree/,
so the DLL must live at usd/hdEmbree.dll. The previous POST_BUILD copied it to
the exe root, causing the module-not-found error at load time.

Fix: copy hdEmbree.dll into usd/ for POST_BUILD and install(). embree3.dll
stays in the exe root where Windows DLL search finds it as a dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:45:50 +08:00
indigo 11ce024d6c CMake: support separate HDEMBREE_USD_ROOT for hdEmbree integration
The previous approach assumed hdEmbree lived inside OpenUSD_ROOT_DIR, which
only works when USD itself was built with PXR_ENABLE_EMBREE_PLUGIN=ON.

This change adds HDEMBREE_USD_ROOT to point at a separate USD build that
includes hdEmbree (e.g. E:/USD_v25.05_embree), while the main USD install
remains at OpenUSD_ROOT_DIR. Fixes three bugs from the prior commit:

- Detection now resolves _hdembree_root from HDEMBREE_USD_ROOT first
- hdEmbree.dll path corrected: it lives at plugin/usd/hdEmbree.dll, not
  inside the plugin/usd/hdEmbree/ metadata subdirectory
- DLL glob changed from tbb12.dll (Embree 4) to embree*.dll only; tbb*.dll
  is deliberately excluded to avoid conflicts with the main USD install
- POST_BUILD now also deploys the hdEmbree/ metadata dir to usd/hdEmbree/
- install() deploys the hdEmbree/ metadata dir alongside hdEmbree.dll

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:40:47 +08:00
indigo 91fff304b5 CMake: add hdEmbree plugin detection and deployment
When the USD installation contains plugin/usd/hdEmbree/ (i.e. USD was built
with PXR_ENABLE_EMBREE_PLUGIN=ON), the build system now:
- Detects OPENUSD_HAS_EMBREE and logs status in the CMake configure output
- POST_BUILD: copies Embree runtime DLLs to the exe directory (looks in USD lib/
  first, or EMBREE_LOCATION cache variable if DLLs live in a separate SDK dir)
- install(): deploys hdEmbree.dll and Embree DLLs alongside other runtime DLLs
- Adds EMBREE_LOCATION CACHE PATH for pointing at an external Embree SDK bin/

No app code changes needed: UsdImagingGLEngine::GetRendererPlugins() already
enumerates all registered Hydra plugins, and the per-viewport renderer dropdown
already lists them. HdEmbree will appear automatically once the plugin is present.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 09:36:28 +08:00
indigo d280136ca7 Modify font size to 15 2026-06-18 07:15:55 +08:00
indigo 81d4372bf6 Scene hierarchy: add Inherit, Specialize, and VariantSet composition arc menus
Prim right-click context menu now exposes all five USD composition arc types:

- Inherit▶  Add... (modal for SdfPath input) | Remove▶ (lists via GetAllDirectInherits()) | Clear All
- Specialize▶  Add... | Remove▶ (lists via UsdPrimCompositionQuery + ArcTypeFilter::Specialize) | Clear All
- VariantSet▶  Add... | per-set sub-menu: Add Variant... + selectable variant list (SetVariantSelection)

All text-input operations share a single RenderArcModal() driven by ArcModalMode enum.
VariantSet/Variant names go through SanitizeUsdName(); Inherit/Specialize paths are passed
as-is to SdfPath. OK button is disabled until input is non-empty; Enter key also confirms.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 04:48:18 +08:00
indigo 3ba00761c1 Scene hierarchy: group composition arcs into Reference/Payload submenus + add Payload ops
- Prim context menu: consolidate Add/Replace/Remove Reference under a single Reference▶ submenu
- Prim context menu: add Payload▶ submenu with Add.../Remove▶/Clear All
- Stage blank-area context menu: same grouping (Reference▶ and Payload▶)
- Include pxr/usd/usd/payloads.h and pxr/usd/sdf/payload.h; use SdfPayloadEditorProxy + UsdPrimCompositionQuery::ArcTypeFilter::Payload for per-payload removal

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 04:37:16 +08:00
indigo f56f4674cc Property panel: token[] view/edit, uniform row heights
- Add token[] attribute display: inline InputText (or Combo when
  allowedTokens metadata is present), collapsible [N tokens] tree
  for arrays with up to 32 editable entries
- Force all property table rows to GetFrameHeight() minimum via
  TableNextRow min_row_height so text-only and widget rows match
- Add AlignTextToFramePadding() before every TextUnformatted /
  TextDisabled / TextColored in cols 0-2 so short text sits centred
  in the uniform-height row rather than pinned to the top
- Wrap matrix attributes in TreeNodeEx [NxN] so they collapse to a
  single-height row; relationship targets use inline text / collapsible
  tree instead of a variable-height ListBox

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 08:02:41 +08:00
indigo 251174ddc3 Property panel: display and edit primvars:displayColor[] as color swatches
DrawVtValueWidget now handles Color-role array attributes (VtArray<GfVec3f>
and VtArray<GfVec4f>) that previously fell through to the generic [array N]
fallback.

- Single element: inline ColorEdit3/4
- Multiple elements: collapsible row with up to 5 swatch previews + [N] count;
  expanded view shows per-index ColorEdit3/4 (capped at 16 entries)
- Editing any element writes the full modified VtArray back via attr.Set()

Covers primvars:displayColor, primvars:displayOpacity[], and any other
color3f[]/color4f[] primvar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 07:28:04 +08:00
indigo dc0c15de70 Scale manipulator: center handle for uniform scale + hover fix
- Add center dot hit test (axis 3) for the scale gizmo so hovering/
  clicking the center circle performs uniform scale on all three axes.
  Center is checked before HitTestAxes to prevent the pivot (which is
  an endpoint of all three axis segments) from always resolving to X.

- Uniform scale uses screen-space pixel delta (right = grow, left =
  shrink, 200 px ≈ ×2) instead of the world-space axis-line ratio.
  The axis-line approach broke because the mouse starts at the pivot
  (oT ≈ 0), making cT/oT explode on any small movement.

- Center dot highlights in orange and grows when hovered or active.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 06:47:42 +08:00
indigo 7d53eb18d4 Fix USD camera tumble: lossless matrix write-back + gimbal-free orbit init
Two issues caused the camera orientation to flip when tumbling a custom
USD camera:

1. Write-back decomposed the camera matrix to XYZ-euler via
   Decompose(X,Y,Z) and re-authored it as a rotateXYZ op. That round-trip
   is lossy — the angles Decompose returns do not reconstruct the same
   matrix as a rotateXYZ op, so the orientation read back from the prim
   differed from the free-camera view shown during the drag. The view
   jumped every time a drag finished and snapped back on the next drag.
   Now author the full camera-to-world transform as a single matrix op,
   which round-trips exactly through UsdGeomCamera::GetCamera().

2. Orbit init relied on PullFromCameraTransform's Euler decomposition for
   theta/phi, which is gimbal-affected. Added
   ViewportCamera::InitOrbitFromEyeAndCenter to derive theta/phi directly
   from the eye->center vector (zero roll), respecting the Z-up matrix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 07:28:28 +08:00
indigo ee1b750f8c Fix USD camera orbit pivot — use scene bbox centroid instead of focus distance
When switching to a USD camera, the orbit pivot was set from
GfCamera::GetFocusDistance() which is a depth-of-field attribute
that defaults to 5 scene units regardless of scene scale.

InitCameraNavigation() now computes the scene bounding box centroid,
projects it onto the camera view ray to get a proper orbit distance,
and calls SetFocalPoint/SetDist to place the pivot correctly.
Added SetDist() setter on ViewportCamera to support this.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 04:46:20 +08:00