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>