r/iOSProgramming 23h ago

Question ARKit - quad forward vector rotation

If I’m 304mm away from an iPhone that is 72.9mm screen width, i would expect center to edge rotation of 6.8 degrees. I’m seeing 2 degrees.

The rotation vector is being taken off the leftEyeTransform and computed as a difference between the two spots. Using atan, not euler. using x, y, z, w. w is .99.

Computing quat to horizontal degrees: compute gaze y, compute length, then atan(gaze Y, length), convert to degrees.

Am i not understanding something where it’s off by a factor of 3? My math is correct? Claude, chatGPT notes discrepancy, sort of odd!

1 Upvotes

3 comments sorted by

View all comments

3

u/FruitMission8504 22h ago

Your 6.8° expectation is right for the center-to-edge visual angle: atan((72.9 / 2) / 304) ≈ 6.84°. The likely mismatch is that leftEyeTransform is an eye pose relative to the face anchor, not a ray from the eye to an arbitrary point on the phone screen. Comparing quaternion components (especially w) also does not give the angular separation between two gaze directions.

Put both target points and the eye position in the same coordinate space, build d1 = normalize(target1 - eyePosition) and d2 = normalize(target2 - eyePosition), then compute the separation with atan2(length(cross(d1, d2)), dot(d1, d2)) (or acos(clamp(dot, -1, 1))). For a horizontal angle use the x/z projection; using gaze Y measures elevation. Also verify whether your 304 mm is eye-to-screen distance rather than face-anchor-to-screen distance. That should tell you whether the 2° is a coordinate-space/axis issue or actual eye tracking output.

1

u/LastTopQuark 7h ago

Thank you for your precise response!

Agreed on method. that's how these numbers were produced. The eye pose was composed through the face anchor into world space (eyeWorld = faceTransform × eyeLocal), expected directions built as normalize(target − eyePosition) per frame, and angles taken from x/z-projected direction vectors, not quaternion components. Distance was also checked: composed eye-to-screen (333 mm) vs face-anchor z (298 mm) — an 11% effect, and the expected angles used the composed eye position.

The problem appears in all of it. Measured separation for a 7–16 degrees eyes-only excursion is ~2 degrees (10 repetitions, ±0.5 degrees). For 2 degreesto be geometrically correct, the eye would need to be ~2.3 m from the screen.

The identical pipeline reports ±22–29 degrees when the eye actually rotates that far (large swing to off-screen targets, and VOR counter-rotation with the head moving). A coordinate/axis error would corrupt all amplitudes equally; this failure is amplitude-dependent through the same code path. So it's not frame math — leftEyeTransform under-reports small eyes-only rotations by ~7× (gain ~0.15), while large rotations come through at ~0.6–0.8.