alvr-org / alvr-visionos

Experimental visionOS client for ALVR - SteamVR on Apple Vision Pro!
MIT License
432 stars 31 forks source link

Controller Jitter #116

Open minusreality opened 5 months ago

minusreality commented 5 months ago

If I hold my hand out in SteamVR home, my hand tracking based controllers jitter noticeably. Is there any way of smoothing out the tracking? This occurs even without any kind of additional controller in hand.

VisionOS 2.0 Developer Beta 1 Latest ALVR Testflight 20.8.2 (2) ALVR Server 20.8.1 Windows 11 4080 PC

minusreality commented 5 months ago

https://github.com/alvr-org/alvr-visionos/assets/641766/9d1ad637-4f0e-403b-865f-3cdfa0c59527

minusreality commented 5 months ago

session.json

jamuus commented 3 months ago

This seems related to asking handTracking.handAnchors for a prediction too far into the future, in my testing anchorTimestamp ends up around +60ms from the current timestamp. Limiting this to 20-30ms significantly reduces jitter.

Try this:

--- a/ALVRClient/Renderer.swift
+++ b/ALVRClient/Renderer.swift
@@ -757,11 +757,13 @@ class Renderer {

             let targetTimestamp = vsyncTime + (Double(min(alvr_get_head_prediction_offset_ns(), WorldTracker.maxPrediction)) / Double(NSEC_PER_SEC))
             let reportedTargetTimestamp = vsyncTime
-            var anchorTimestamp = vsyncTime + (Double(min(alvr_get_head_prediction_offset_ns(), WorldTracker.maxPrediction)) / Double(NSEC_PER_SEC))//LayerRenderer.Clock.Instant.epoch.duration(to: drawable.frameTiming.trackableAnchorTime).timeInterval
+            var anchorTimestamp = vsyncTime + Double(alvr_get_head_prediction_offset_ns())/Double(NSEC_PER_SEC) //LayerRenderer.Clock.Instant.epoch.duration(to: drawable.frameTiming.trackableAnchorTime).timeInterval
             if #available(visionOS 2.0, *) {
                 //anchorTimestamp = LayerRenderer.Clock.Instant.epoch.duration(to: drawable.frameTiming.trackableAnchorTime).timeInterval
             }
-            
+            let maxPred = CACurrentMediaTime()+Double(WorldTracker.maxPrediction)/Double(NSEC_PER_SEC);
+            anchorTimestamp = min(anchorTimestamp, maxPred);
+
             WorldTracker.shared.sendTracking(viewTransforms: viewTransforms, viewFovs: viewFovs, targetTimestamp: targetTimestamp, reportedTargetTimestamp: reportedTargetTimestamp, anchorTimestamp: anchorTimestamp, delay: 0.0)
         }

and fiddle with WorldTracker.maxPrediction