Files
bearstonem--openmohaa-vr/code/client
bearstonemandClaude Opus 5 4f5b54c74c feat(vr): a hand on each controller, placed in the renderer's frame
The first person model already has the hands as separate surfaces - triggerhand,
lefthand, garandhand and viewsleeves on USarmyplyr.skd - so putting one on each
controller needs no mesh work at all. The weapon hand's copy drops the left hand
surface and a second copy is drawn on the off hand carrying only that, using the
same Surface_NameToNum and MDL_SURFACE_NODRAW the game already uses to swap
lefthand for garandhand on rifles.

Two things had to be right first, and both were wrong in ways that looked like
tuning problems rather than faults.

**The frame.** cg.refdef.vieworg is not the camera. R_VRComposeView adds the
head's play space offset to it, rotated into the body's frame, after cgame is
finished (tr_vr.c). So anything anchored on vieworg alone is left behind by
exactly the head's offset within the play space - and because the head swings
about the neck, every look around moved it, and a snap turn left it behind
entirely since a stick turn moves the body frame that a head relative offset
knows nothing about.

Both hands are now reported measured from the tracking origin, the frame
VR_PoseToView puts the eyes in, and composed the way the renderer composes the
camera:

    bodyAngles = (0, viewYaw - baseYaw, 0)
    handWorld  = vieworg + bodyAxis * trackingOffset

RTCWQuest reaches the same place by a different road - convertFromVR rotates a
head relative offset by viewangles[YAW] - hmdorientation[YAW] and the -64 plus
hmdposition[1] * worldScale rebase then replaces its height, which comes to the
same thing. Either route works. Taking half of each does not, and did not: a
head relative offset composed as though it were play space leaves the hand at
vieworg + R*(hand - head) while the camera is at vieworg + R*head, so the head's
movement is counted twice and every hand movement is amplified. That is what
"the right hand is accelerated" was, and it happened because VR_GetWeaponPose
was left reporting the old frame while its caller had moved to the new one - the
signature is identical either way, so nothing complained. The header now says so
at length.

**The anchor.** A hand drawn at the model origin sits wherever the animation put
it, which for a rifle is a long way out in front. The model is now moved so the
hand's own bone lands on the controller instead, inverting the composition the
engine itself uses in Entity::GetTagPositionAndOrientation. The off hand anchors
on Bip01 L Hand and the weapon hand on tag_weapon_right, because what the player
is holding there is the gun and the controller is its grip.

Every candidate anchor is measured and logged rather than trusted, which earned
itself immediately: tag_weapon_left was assumed to be an unused slot parked at
the origin and is nothing of the sort (23.5 units out), while the weapon hand's
lookup was returning -1 in silence and anchoring nothing. Both now report what
they found and how far out it is, and the early return says which precondition
failed.

Tracking is confirmed 1:1 on both controllers on the device. What is left is the
wrist bones' own rotation convention, which is a constant and lives in
vr_weaponAdjust and vr_offHandAdjust.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 23:45:57 -07:00
..
2025-10-19 21:03:23 +02:00
2025-09-07 19:45:51 +02:00
2023-05-24 19:29:36 +02:00
2023-05-24 19:29:36 +02:00
2025-07-19 23:30:20 +02:00
2024-06-07 20:34:13 +02:00
2025-07-19 23:30:20 +02:00
2025-11-24 00:48:41 +01:00
2023-12-31 22:02:47 +01:00
2025-10-19 21:03:23 +02:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2025-02-06 22:56:49 +01:00
2025-02-06 22:56:49 +01:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2025-07-19 23:30:20 +02:00
2023-12-30 17:36:01 +01:00
2023-12-29 20:19:28 +01:00
2024-01-01 14:53:16 +01:00
2023-12-29 22:06:36 +01:00
2025-07-19 23:30:20 +02:00
2023-12-29 20:19:28 +01:00
2025-07-19 23:30:20 +02:00
2025-09-07 19:45:51 +02:00
2023-05-24 19:40:02 +02:00
2025-03-24 22:16:43 +01:00
2023-05-24 19:42:48 +02:00
2023-05-24 19:42:48 +02:00
2025-08-13 23:20:04 +02:00
2023-05-24 19:42:48 +02:00
2023-05-24 19:42:48 +02:00
2025-09-07 19:45:51 +02:00
2025-08-13 23:20:04 +02:00
2024-08-21 18:35:06 +02:00
2025-09-07 19:45:51 +02:00
2023-06-11 12:49:19 +02:00
2024-01-07 23:50:02 +01:00
2024-01-07 23:50:02 +01:00
2025-08-23 23:30:50 +02:00
2025-09-07 19:45:51 +02:00
2023-05-24 19:42:48 +02:00