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>
This commit is contained in:
2026-06-24 09:28:09 +08:00
parent e8a73674ad
commit ddffa5764c
2 changed files with 64 additions and 38 deletions
+4 -1
View File
@@ -102,6 +102,8 @@ private:
// Bezier metadata persistence (stored in prim customData["curveEditor"])
static std::string ChannelMetadataKey(const CurveChannel& ch);
bool SaveBezierToMetadata(const pxr::UsdPrim& prim, const CurveChannel& ch) const;
bool SaveBezierToMetadata(const pxr::UsdPrim& prim, const std::string& channelKey,
const std::vector<BezierKey>& keys) const;
bool LoadBezierFromMetadata(const pxr::UsdPrim& prim, CurveChannel& ch) const;
// ── State ────────────────────────────────────────────────────────────────
@@ -116,7 +118,8 @@ private:
std::vector<SelectedHandle> m_selection;
int m_activeChannel = -1; // for double-click-to-add
bool m_needsRefresh = true;
bool m_needsRefresh = true;
bool m_suppressNotice = false; // set during bake writes to silence OnObjectsChanged
// USD change notification
pxr::TfNotice::Key m_stageChangeKey;