Skip to content

Commit b548c9e

Browse files
committed
fix(trackerobjects): re-assert kinematic each frame in pose drive
One-shot isKinematic = true at bind isn't enough — BasisObjectSyncNetworking Awake and ControlState both flip kinematic back to false for locally-owned props, and ControlState fires on ownership-transfer events that can happen long after bind. Once physics gets hold of the rigidbody between our pose writes, Scene view samples those intermediate frames (out of step with onBeforeRender) and flickers even when Game view (which renders right after our write) stays clean. Re-asserting kinematic = true each frame in OnAfterSimulateOnRender is a single bool set per binding, cheap, and defends against any external setter without playing whack-a-mole with every code path that touches RigidRef. Spec updated to describe the per-frame enforcement and its motivation.
1 parent da231ff commit b548c9e

2 files changed

Lines changed: 12 additions & 1 deletion

File tree

Basis/Packages/com.basis.trackerobjects/REQUIREMENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Existing `BasisObjectSyncNetworking.CanNetworkSteal` is unchanged; the veto sits
135135
`BasisObjectSyncNetworking.ControlState` sets `Rigidbody.isKinematic = false` when the object is locally owned, so physics drives the rigidbody. With a tracker also writing the transform every render frame, the two compete and the prop jitters. To prevent this:
136136

137137
- `TryCreateBinding` captures `pickupInteractable.RigidRef.isKinematic` and stores it on the binding.
138-
- It then sets `isKinematic = true` for the duration of the binding.
138+
- It then sets `isKinematic = true`, and the per-frame pose drive re-asserts `isKinematic = true` each frame. Re-assertion (rather than one-shot) is required because `BasisObjectSyncNetworking.Awake` and `ControlState` both set `isKinematic = false` for locally-owned props, and `ControlState` can fire after bind on ownership-transfer events. Physics moving the rigidbody between our writes shows up as Scene-view flicker even when Game view (which renders right after `onBeforeRender`) looks clean.
139139
- `TryRemoveBinding` restores the captured value.
140140

141141
If the target has no `BasisPickupInteractable` or no `Rigidbody`, the kinematic toggle is skipped.

Basis/Packages/com.basis.trackerobjects/Runtime/BasisTrackerObjectManager.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,17 @@ private static void OnAfterSimulateOnRender()
160160
{
161161
continue;
162162
}
163+
// BasisObjectSyncNetworking.Awake and ControlState both flip
164+
// isKinematic = false on locally-owned props, and ControlState can
165+
// re-fire on ownership-transfer events long after bind. If physics
166+
// touches the rigidbody between our writes, Scene view samples those
167+
// intermediate frames (out of step with onBeforeRender) and flickers
168+
// even when Game view stays clean. Re-asserting kinematic each frame
169+
// is cheap and avoids playing whack-a-mole with every external setter.
170+
if (binding.HasKinematicCaptured && binding.RigidRef != null)
171+
{
172+
binding.RigidRef.isKinematic = true;
173+
}
163174
binding.Tracker.transform.GetPositionAndRotation(out Vector3 trackerPos, out Quaternion trackerRot);
164175
binding.Target.SetPositionAndRotation(
165176
trackerPos + trackerRot * binding.LocalPositionOffset,

0 commit comments

Comments
 (0)