From c09b40a2efdc79188bcc47f8765d5c20d4309d7e Mon Sep 17 00:00:00 2001 From: Stefan Maier <145186748+Cesarus85@users.noreply.github.com> Date: Tue, 6 Oct 2026 17:54:15 +0200 Subject: [PATCH] VR arms: the free left arm solved first, its hand turned after As HaloCE-Quest-VR does it: the free arm is bent to the controller's grip from the animated pose (the hand free to swing with it), and only then is the hand turned to the controller and the roll shared along the forearm. Turning the hand first left the solve to swing it on, which stretched the arm's skin like a rubber band (Quest, 2026-10-06). vr.arm_ik stays off by default until it is seen right. Co-Authored-By: Claude Opus 5.5 --- source/interface/first_person_weapons.c | 31 +++++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/source/interface/first_person_weapons.c b/source/interface/first_person_weapons.c index d038bca6..5fd88cdf 100644 --- a/source/interface/first_person_weapons.c +++ b/source/interface/first_person_weapons.c @@ -1707,7 +1707,12 @@ static void first_person_weapon_vr_arms( { if (halo_vr_left_hand(local_player_index, hand_position, hand_forward, hand_up)) { - vr_left_hand_free(&vr_arm_skeleton, node_matrices, rigid, hand_position, hand_forward, hand_up); + /* (rigid: the hand and its arm carried to the controller now; + bent, the arm is solved to it first, below, and the hand turned + after, as HaloCE-Quest-VR does: turned first, the solve's swing + turned it on and the arm's skin stretched) */ + if (rigid) + vr_left_hand_free(&vr_arm_skeleton, node_matrices, rigid, hand_position, hand_forward, hand_up); left_free = TRUE; } } @@ -1748,10 +1753,26 @@ static void first_person_weapon_vr_arms( vr_point_upper_arm(node_matrices, vr_arm_nodes.upper[side], vr_arm_nodes.fore[side], &shoulder); continue; } - /* the hand stays where it is (at the controller, or on the - weapon): the arm bends to it */ - vr_solve_arm(&vr_arm_skeleton, node_matrices, bones, shoulder, &node_matrices[bones[_vr_arm_hand]].position, - &pole, TRUE, &vr_arm_history[side]); + if (!side && left_free) + { + /* the free left arm bent to the controller's grip (the wrist + 7 cm behind it), the hand turned to the controller after */ + real_point3d target; + + target.x = hand_position[0] - hand_forward[0] * 0.07f / VR_METRES_PER_WORLD_UNIT; + target.y = hand_position[1] - hand_forward[1] * 0.07f / VR_METRES_PER_WORLD_UNIT; + target.z = hand_position[2] - hand_forward[2] * 0.07f / VR_METRES_PER_WORLD_UNIT; + vr_solve_arm(&vr_arm_skeleton, node_matrices, bones, shoulder, &target, &pole, FALSE, + &vr_arm_history[side]); + vr_left_hand_free(&vr_arm_skeleton, node_matrices, FALSE, hand_position, hand_forward, hand_up); + } + else + { + /* the hand stays where it is (on the weapon): the arm bends to + it */ + vr_solve_arm(&vr_arm_skeleton, node_matrices, bones, shoulder, + &node_matrices[bones[_vr_arm_hand]].position, &pole, TRUE, &vr_arm_history[side]); + } vr_align_elbow(node_matrices, bones, &animated_upper[side], &animated_forearm[side], &animated_wrist[side]); vr_distribute_arm_twist(node_matrices, bones, &animated_forearm[side], &animated_wrist[side], &vr_arm_history[side]);