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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
- 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>
- 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>
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>
- 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>
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>
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>
- Add edit-target layer combo at top of Scene Hierarchy panel (always
visible when stage loaded — session, root, sublayers); routes through
LayerManager::SetEditTarget so StageEditor ET checkboxes stay in sync
- Replace custom Create Sublayer modal with native SaveFile dialog;
LayerManager::CreateNewSublayer creates the file on disk, inserts it
at the top of the sublayer stack, and activates it as edit target
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each panel (Stage Editor, Scene Hierarchy, Viewport, Property Panel,
Timeline) now has a checkable menu item under View. Closing a panel via
its X button also unchecks the entry. Stage Info and Demo Window follow
below a separator.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rotate manipulator — correct axis bug:
- Object-space delta axis was set to initRot.GetRow3(axis) (a parent-space
vector) then applied in the prim's local frame via deltaM * initRot.
These frames are mismatched: the axis must be the canonical e_a so that
Rot(e_a) fixes e_a and the prim rotates purely about its own axis.
Fixed to use the canonical axis for both spaces; only composition order
differs (deltaM * initRot for object, initRot * deltaM for world).
Gizmo pivot placement:
- ComputeGizmoPivot() used the bounding-box centre (geometry centroid),
placing the gizmo at the wrong location for any non-centred prim.
Replaced with parentToWorld.Transform(translate + pivot) from
XformCommonAPI::GetXformVectors — the authored pivot point in world space.
Fallback for incompatible op stacks uses worldMatrix.ExtractTranslation().
Property panel:
- Show pivot (X/Y/Z) as read-only row below Scale, populated from
XformCommonAPI::GetXformVectors each frame.
- Removed active-rotate-axis display (was added and then removed per request).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SaveStage: explicitly call rootLayer->Save() before m_stage->Save() to
ensure root-layer metadata (subLayers field) is always written to disk
- SaveUsdFile: redirect to SaveAs when the root layer is anonymous so
Ctrl+S on an in-memory stage no longer silently does nothing
- SaveUsdFileAs: call RefreshManagers() after SaveStageAs so LayerManager
stays in sync with the newly opened file-backed stage; without this,
sublayers added after a Save As went to the old stale stage and were lost
- LayerCreateCommand::Execute: use GetSublayers() (sublayer-local indices)
instead of GetLayerStack() (full-stack indices) to record m_insertedIndex,
fixing undo of add-sublayer removing the wrong layer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace LayerPanel with StageEditorPanel for full sublayer composition workflow:
- Edit target (ET) checkbox on root/session and each sublayer; pen icon header
- Dirty indicator (*) per layer; muted layers remain visible in list
- Drag-drop and Move Up/Down reordering with undo (LayerReorderCommand)
- Add existing sublayer via file dialog; create new sublayer modal
- Fixed LayerReorderCommand::ApplyOrder using full-stack indices on sublayer-local
list (silent remove failure → duplicate insert → USD _ValidateEdit error)
- Fixed muted sublayer visibility: walk GetSubLayerPaths() + FindOrOpenRelativeToLayer
+ m_layerRefs to keep muted layers alive and visible
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace all text buttons with SVG icon buttons (skip-back, step-back,
play-back, play, pause, step-forward, skip-end)
- Add rewind: separate play-backward button that flips direction
- Add loop mode button with submenu (Loop / Bounce / Off)
- Loop wraps at boundaries; Bounce reflects direction (ping-pong)
- Start/end frames moved to flank the scrub slider as plain numbers
- New icons: play-back.svg, loop.svg (FA repeat), bounce.svg (FA exchange-alt)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>