mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 12:00:26 +02:00
VR arms 3a.5: the fingers posed
- vr_arms.c: vr_finger_nodes, vr_pose_finger (after HaloCE-Quest-VR, CC0, nearly verbatim): each finger's three joints found by name under the hand, posed by absolute directions in the palm's frame (a little bent at rest, a fist at full curl; the thumb up the handle or across the palm), each segment's subtree turned with its length kept. Its touch of the world (rays per finger) is left out for the Frame's processor. - The free left hand takes its controller's curls (halo_vr_finger_curls: index from the trigger, the others from the grip, the thumb from where it rests; round a held grenade). On the foregrip the hand keeps the weapon's pose. - The hand on the weapon keeps its grip; only its index finger is lifted part way off the trigger while the controller says it is (touch known and the finger off it), never where touch is unknown. - Joints found once per skeleton; the cost is a few dozen node turns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7754532683
commit
98e848de39
5 files changed
+309
-5
No files matched your search
@@ -523,4 +523,230 @@ void vr_distribute_arm_twist(
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- the fingers
|
||||
|
||||
Each finger's joints are found by name: "finger" and its number (0 the
|
||||
thumb to 4 the little finger), or "thumb", "index", "middle", "ring",
|
||||
"pinky", on the hand's side ("l ", "r "). They are posed by absolute
|
||||
directions in the controller's palm frame, each segment's subtree turned,
|
||||
its length kept (after HaloCE-Quest-VR, CC0, nearly verbatim; its touch of
|
||||
the world, a few rays a finger, is left out: it costs the Steam Frame's
|
||||
processor too much). */
|
||||
|
||||
/* the finger (0 the thumb .. 4 the little finger) a node's name says it is
|
||||
a joint of, on that side; NONE when not a finger's */
|
||||
static short vr_finger_of(
|
||||
char const *name,
|
||||
char const *side)
|
||||
{
|
||||
static char const *const names[] = { "thumb", "index", "middle", "ring", "pinky" };
|
||||
char const *finger;
|
||||
short index;
|
||||
|
||||
if (!name || !strstr(name, side))
|
||||
return NONE;
|
||||
finger = strstr(name, "finger");
|
||||
if (finger && finger[6] >= '0' && finger[6] <= '4')
|
||||
return (short)(finger[6] - '0');
|
||||
for (index = 0; index < 5; index++)
|
||||
{
|
||||
if (strstr(name, names[index]))
|
||||
return index;
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
void vr_finger_nodes(
|
||||
struct vr_skeleton const *skeleton,
|
||||
short hand,
|
||||
char const *side,
|
||||
short joints[5][3])
|
||||
{
|
||||
short node_index, finger, depth;
|
||||
|
||||
for (finger = 0; finger < 5; finger++)
|
||||
{
|
||||
for (depth = 0; depth < 3; depth++)
|
||||
joints[finger][depth] = NONE;
|
||||
}
|
||||
for (node_index = 0; node_index < skeleton->node_count; node_index++)
|
||||
{
|
||||
short at;
|
||||
|
||||
finger = vr_finger_of(animation_graph_node_name(skeleton->graph_index, node_index), side);
|
||||
if (finger == NONE || !vr_skeleton_under(skeleton, node_index, hand))
|
||||
continue;
|
||||
/* its depth: how many of the same finger's joints above it */
|
||||
depth = 0;
|
||||
for (at = skeleton->parents[node_index]; at != NONE; at = skeleton->parents[at])
|
||||
{
|
||||
if (vr_finger_of(animation_graph_node_name(skeleton->graph_index, at), side) == finger)
|
||||
depth++;
|
||||
}
|
||||
if (depth < 3)
|
||||
joints[finger][depth] = node_index;
|
||||
}
|
||||
}
|
||||
|
||||
/* a node and all under it turned about the node */
|
||||
static void vr_turn_subtree(
|
||||
struct vr_skeleton const *skeleton,
|
||||
real_matrix4x3 *matrices,
|
||||
short root,
|
||||
real rotation[3][3])
|
||||
{
|
||||
real_point3d pivot = matrices[root].position;
|
||||
unsigned long long under = skeleton->under[root];
|
||||
short node_index;
|
||||
|
||||
for (node_index = 0; node_index < skeleton->node_count; node_index++)
|
||||
{
|
||||
if (under & (1ULL << node_index))
|
||||
vr_carry(&matrices[node_index], &pivot, &pivot, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
/* a finger's joints (low, middle, tip) curled 0 (straight, a little bent
|
||||
at rest) to 1 (a fist), in the palm's frame: forward along the fingers,
|
||||
up the knuckles towards the index, palm out of the palm */
|
||||
static boolean vr_pose_finger(
|
||||
struct vr_skeleton const *skeleton,
|
||||
real_matrix4x3 *matrices,
|
||||
short hand,
|
||||
short const joints[3],
|
||||
int finger,
|
||||
real curl,
|
||||
real_vector3d const *palm,
|
||||
real_vector3d const *forward,
|
||||
real_vector3d const *up)
|
||||
{
|
||||
static real const rest[3] = { 0.12f, 0.15f, 0.10f };
|
||||
static real const bend[3] = { 1.25f, 1.6f, 1.1f };
|
||||
real_vector3d base, axis, direction, wanted;
|
||||
real angle = 0.0f, dot, rotation[3][3];
|
||||
int depth;
|
||||
|
||||
if (joints[0] == NONE || joints[1] == NONE || joints[2] == NONE)
|
||||
return FALSE;
|
||||
vr_point_minus(&matrices[joints[0]].position, &matrices[hand].position, &base);
|
||||
dot = dot_product3d(&base, palm);
|
||||
base.i -= dot * palm->i;
|
||||
base.j -= dot * palm->j;
|
||||
base.k -= dot * palm->k;
|
||||
if (finger == 0)
|
||||
{
|
||||
/* the thumb: up the handle, or across the palm */
|
||||
base.i = (up->i * 0.9f + forward->i * 0.3f) * (1.0f - curl) +
|
||||
(forward->i * 0.75f + palm->i * 0.55f + up->i * 0.1f) * curl;
|
||||
base.j = (up->j * 0.9f + forward->j * 0.3f) * (1.0f - curl) +
|
||||
(forward->j * 0.75f + palm->j * 0.55f + up->j * 0.1f) * curl;
|
||||
base.k = (up->k * 0.9f + forward->k * 0.3f) * (1.0f - curl) +
|
||||
(forward->k * 0.75f + palm->k * 0.55f + up->k * 0.1f) * curl;
|
||||
}
|
||||
if (!vr_unit_vector(&base))
|
||||
return FALSE;
|
||||
cross_product3d(&base, palm, &axis);
|
||||
if (!vr_unit_vector(&axis))
|
||||
return FALSE;
|
||||
for (depth = 0; depth < 3; depth++)
|
||||
{
|
||||
short joint = joints[depth];
|
||||
|
||||
if (depth < 2)
|
||||
{
|
||||
vr_point_minus(&matrices[joints[depth + 1]].position, &matrices[joint].position, &direction);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the tip: its own axis that the middle joint's bone runs along */
|
||||
real_vector3d previous;
|
||||
real_vector3d *axes[3];
|
||||
real_vector3d *last[3];
|
||||
real best = 0.8f, sign = 1.0f;
|
||||
int a, found = -1;
|
||||
|
||||
axes[0] = &matrices[joints[1]].forward;
|
||||
axes[1] = &matrices[joints[1]].left;
|
||||
axes[2] = &matrices[joints[1]].up;
|
||||
last[0] = &matrices[joint].forward;
|
||||
last[1] = &matrices[joint].left;
|
||||
last[2] = &matrices[joint].up;
|
||||
vr_point_minus(&matrices[joint].position, &matrices[joints[1]].position, &previous);
|
||||
if (!vr_unit_vector(&previous))
|
||||
return FALSE;
|
||||
for (a = 0; a < 3; a++)
|
||||
{
|
||||
real_vector3d unit = *axes[a];
|
||||
|
||||
if (!vr_unit_vector(&unit))
|
||||
continue;
|
||||
dot = dot_product3d(&unit, &previous);
|
||||
if (fabs(dot) > best)
|
||||
{
|
||||
best = (real)fabs(dot);
|
||||
found = a;
|
||||
sign = dot < 0.0f ? -1.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
if (found < 0)
|
||||
return TRUE;
|
||||
direction.i = last[found]->i * sign;
|
||||
direction.j = last[found]->j * sign;
|
||||
direction.k = last[found]->k * sign;
|
||||
}
|
||||
if (!vr_unit_vector(&direction))
|
||||
return FALSE;
|
||||
angle += finger == 0 ? (depth == 0 ? 0.0f : (depth == 1 ? 0.35f : 0.3f) * curl) :
|
||||
rest[depth] + bend[depth] * curl;
|
||||
vr_axis_rotation(&axis, angle, rotation);
|
||||
vr_rotate_vector(rotation, &base, &wanted);
|
||||
vr_rotation_between(&direction, &wanted, rotation);
|
||||
vr_turn_subtree(skeleton, matrices, joint, rotation);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vr_pose_fingers(
|
||||
struct vr_skeleton const *skeleton,
|
||||
real_matrix4x3 *matrices,
|
||||
short hand,
|
||||
short const joints[5][3],
|
||||
float const curls[4],
|
||||
real_vector3d const *palm,
|
||||
real_vector3d const *forward,
|
||||
real_vector3d const *up)
|
||||
{
|
||||
int finger;
|
||||
|
||||
for (finger = 0; finger < 5; finger++)
|
||||
vr_pose_finger(skeleton, matrices, hand, joints[finger], finger, curls[finger < 3 ? finger : 3], palm, forward, up);
|
||||
}
|
||||
|
||||
/* the finger's middle and tip turned this much (0..1) towards the line of
|
||||
its low joint: a finger lifted off the trigger (the weapon hand's index,
|
||||
whose low joint, and the rest of the hand, keep the weapon's grip) */
|
||||
void vr_straighten_finger(
|
||||
struct vr_skeleton const *skeleton,
|
||||
real_matrix4x3 *matrices,
|
||||
short const joints[3],
|
||||
real amount)
|
||||
{
|
||||
real_vector3d low, middle, axis;
|
||||
real rotation[3][3];
|
||||
real angle;
|
||||
|
||||
if (amount <= 0.0f || joints[0] == NONE || joints[1] == NONE || joints[2] == NONE)
|
||||
return;
|
||||
vr_point_minus(&matrices[joints[1]].position, &matrices[joints[0]].position, &low);
|
||||
vr_point_minus(&matrices[joints[2]].position, &matrices[joints[1]].position, &middle);
|
||||
if (!vr_unit_vector(&low) || !vr_unit_vector(&middle))
|
||||
return;
|
||||
cross_product3d(&middle, &low, &axis);
|
||||
if (!vr_unit_vector(&axis))
|
||||
return;
|
||||
angle = (real)acos(PIN(dot_product3d(&middle, &low), -1.0f, 1.0f)) * PIN(amount, 0.0f, 1.0f);
|
||||
vr_axis_rotation(&axis, angle, rotation);
|
||||
vr_turn_subtree(skeleton, matrices, joints[1], rotation);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -56,6 +56,21 @@ animated) shared by the forearm and the upper arm */
|
||||
void vr_distribute_arm_twist(real_matrix4x3 *matrices, short const bones[NUMBER_OF_VR_ARM_BONES],
|
||||
real_matrix4x3 const *old_fore, real_matrix4x3 const *old_hand, struct vr_limb_history *history);
|
||||
|
||||
/* a hand's fingers' joints (low, middle, tip; NONE where not found), by
|
||||
their names on that side ("l ", "r "): the thumb, index, middle, ring and
|
||||
little finger */
|
||||
void vr_finger_nodes(struct vr_skeleton const *skeleton, short hand, char const *side, short joints[5][3]);
|
||||
/* the fingers curled (halo_vr_finger_curls: the thumb, index, middle, the
|
||||
last two) in the palm's frame: forward along the fingers, up the knuckles
|
||||
towards the index, palm out of the palm */
|
||||
void vr_pose_fingers(struct vr_skeleton const *skeleton, real_matrix4x3 *matrices, short hand,
|
||||
short const joints[5][3], float const curls[4], real_vector3d const *palm, real_vector3d const *forward,
|
||||
real_vector3d const *up);
|
||||
/* a finger's middle and tip turned this much (0..1) into line with its low
|
||||
joint */
|
||||
void vr_straighten_finger(struct vr_skeleton const *skeleton, real_matrix4x3 *matrices, short const joints[3],
|
||||
real amount);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -125,7 +125,14 @@ int halo_vr_two_hand(short local_player_index, const float foregrip[3], const fl
|
||||
/* - the fingers of a hand (0 the left, 1 the right), from the controller's trigger,
|
||||
grip and touch: the thumb, index, middle finger and the last two, each
|
||||
curled 0 (straight) to 1; 0 when the hand is not tracked or vr.fingers
|
||||
is off; */
|
||||
is off, else HALO_VR_FINGERS_CURLED, and HALO_VR_FINGERS_TOUCH too when
|
||||
the controller tells where the fingers rest (else a finger off the
|
||||
trigger reads as one on it, unpressed); */
|
||||
enum
|
||||
{
|
||||
HALO_VR_FINGERS_CURLED = 1,
|
||||
HALO_VR_FINGERS_TOUCH = 2,
|
||||
};
|
||||
int halo_vr_finger_curls(short local_player_index, int hand, float curls[4]);
|
||||
/* - whether the free hand's arm bends at the elbow to reach it from the
|
||||
shoulder (vr.arm_ik); else it keeps the shape it has on the foregrip,
|
||||
|
||||
+1
-1
@@ -1068,7 +1068,7 @@ int halo_vr_finger_curls(short local_player_index, int hand, float curls[4])
|
||||
if (!state->active || !(state->flags & HALO_XR_POSE_VALID))
|
||||
return 0;
|
||||
memcpy(curls, vr.finger_curl[hand], sizeof(vr.finger_curl[hand]));
|
||||
return 1;
|
||||
return HALO_VR_FINGERS_CURLED | ((state->buttons & HALO_XR_BUTTON_TOUCH_KNOWN) ? HALO_VR_FINGERS_TOUCH : 0);
|
||||
}
|
||||
|
||||
int halo_vr_melee(void)
|
||||
|
||||
@@ -1236,6 +1236,10 @@ struct vr_arm_nodes
|
||||
short left_middle;
|
||||
short left_pinky;
|
||||
long barrel_logged_graph_index;
|
||||
/* the fingers' joints (vr_finger_nodes) of the skeleton they were
|
||||
found in: each hand's thumb, index, middle, ring, little finger */
|
||||
long fingers_graph_index;
|
||||
short fingers[2][5][3];
|
||||
/* the whole pose in the weapon camera's frame, outside a melee attack */
|
||||
boolean idle_pose_valid;
|
||||
short idle_pose_count;
|
||||
@@ -1243,7 +1247,7 @@ struct vr_arm_nodes
|
||||
};
|
||||
|
||||
static struct vr_arm_nodes vr_arm_nodes = { NONE, { NONE, NONE }, { NONE, NONE }, { NONE, NONE }, NONE, NONE, NONE, NONE,
|
||||
NONE };
|
||||
NONE, NONE };
|
||||
/* the skeleton this frame, and each arm's last (its elbow's swing and its
|
||||
forearm's twist run on from them) */
|
||||
static struct vr_skeleton vr_arm_skeleton;
|
||||
@@ -1485,6 +1489,58 @@ static void vr_laser_follows_barrel(
|
||||
halo_vr_set_laser(local_player_index, laser_start, laser_direction);
|
||||
}
|
||||
|
||||
/* The fingers (vr.fingers): the free left hand's from its controller's
|
||||
trigger, grip and touch (vr_pose_fingers); of the hand on the weapon, only
|
||||
the index finger, lifted a little off the trigger when the controller
|
||||
says it is (the rest keeps the weapon's grip). */
|
||||
static void first_person_weapon_vr_fingers(
|
||||
short local_player_index,
|
||||
real_matrix4x3 *node_matrices,
|
||||
boolean left_free,
|
||||
float const hand_forward[3],
|
||||
float const hand_up[3])
|
||||
{
|
||||
float curls[4];
|
||||
int fingers;
|
||||
|
||||
if (vr_arm_nodes.fingers_graph_index != vr_arm_skeleton.graph_index)
|
||||
{
|
||||
vr_arm_nodes.fingers_graph_index = vr_arm_skeleton.graph_index;
|
||||
vr_finger_nodes(&vr_arm_skeleton, vr_arm_nodes.wrist[0], "l ", vr_arm_nodes.fingers[0]);
|
||||
vr_finger_nodes(&vr_arm_skeleton, vr_arm_nodes.wrist[1], "r ", vr_arm_nodes.fingers[1]);
|
||||
}
|
||||
if (left_free && vr_arm_nodes.wrist[0] != NONE &&
|
||||
halo_vr_finger_curls(local_player_index, 0, curls))
|
||||
{
|
||||
/* the palm's frame: along the fingers, up the knuckles, and out of
|
||||
the left palm (inwards, to the right) */
|
||||
real_vector3d forward, up, palm;
|
||||
real along;
|
||||
|
||||
forward.i = hand_forward[0];
|
||||
forward.j = hand_forward[1];
|
||||
forward.k = hand_forward[2];
|
||||
up.i = hand_up[0];
|
||||
up.j = hand_up[1];
|
||||
up.k = hand_up[2];
|
||||
along = dot_product3d(&forward, &up);
|
||||
vr_vector_scale_add(&up, &forward, -along);
|
||||
if (normalize3d(&forward) > 1e-4f && normalize3d(&up) > 1e-4f)
|
||||
{
|
||||
cross_product3d(&forward, &up, &palm);
|
||||
vr_pose_fingers(&vr_arm_skeleton, node_matrices, vr_arm_nodes.wrist[0], vr_arm_nodes.fingers[0], curls,
|
||||
&palm, &forward, &up);
|
||||
}
|
||||
}
|
||||
fingers = halo_vr_finger_curls(local_player_index, 1, curls);
|
||||
if (vr_arm_nodes.wrist[1] != NONE && (fingers & HALO_VR_FINGERS_TOUCH))
|
||||
{
|
||||
/* (resting on the trigger the index curls 0.22 or more) */
|
||||
vr_straighten_finger(&vr_arm_skeleton, node_matrices, vr_arm_nodes.fingers[1][1],
|
||||
0.6f * PIN(1.f - curls[1] / 0.22f, 0.f, 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
static void first_person_weapon_vr_arms(
|
||||
short local_player_index,
|
||||
long graph_index,
|
||||
@@ -1515,6 +1571,7 @@ static void first_person_weapon_vr_arms(
|
||||
boolean gripping;
|
||||
boolean left_free;
|
||||
boolean rigid = !halo_vr_free_arm_bends();
|
||||
float hand_position[3], hand_forward[3], hand_up[3];
|
||||
|
||||
if (vr_arm_nodes.graph_index != graph_index)
|
||||
{
|
||||
@@ -1637,8 +1694,6 @@ static void first_person_weapon_vr_arms(
|
||||
}
|
||||
if (!gripping && vr_arm_nodes.wrist[0] != NONE)
|
||||
{
|
||||
float hand_position[3], hand_forward[3], hand_up[3];
|
||||
|
||||
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);
|
||||
@@ -1685,6 +1740,7 @@ static void first_person_weapon_vr_arms(
|
||||
vr_distribute_arm_twist(node_matrices, bones, &animated_forearm[side], &animated_wrist[side],
|
||||
&vr_arm_history[side]);
|
||||
}
|
||||
first_person_weapon_vr_fingers(local_player_index, node_matrices, left_free, hand_forward, hand_up);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user