mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 02:00:14 +02:00
Mirror the right glove across the palm, not along the fingers
OpenXR's grip +X is normal to the palm but points away from it on the left hand and into it on the right, which is exactly what makes both grips carry the same orientation when the hands hold a wheel symmetrically. The fingers therefore run along -Y on both hands, and it is the geometry across the palm that mirrors. Building the right hand's fingers on +Y instead left them pointing at the player while the real hand faced forward. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fc0e927f9e
commit
4438a300b8
2 files changed
+22
-15
No files matched your search
@@ -94,34 +94,38 @@ inline void ellipsoid(std::vector<Vertex>& vertices,V center,V radii,V color) {
|
||||
}
|
||||
// Rounded palm and individually articulated fingers, in the controller's grip
|
||||
// space as OpenXR defines it: the origin is the palm centroid, -Z runs up the
|
||||
// tube the curled fingers form (little finger towards thumb), and +X is the
|
||||
// palm's outward normal, so the fingers close towards +X. +Y completes the
|
||||
// right-handed frame, which leaves it along the fingers on the right hand and
|
||||
// against them on the left. Building the fingers on any other axis bends them
|
||||
// out of the back of the hand (seen on a Quest 3 on 2026-09-22).
|
||||
// tube the curled fingers form (little finger towards thumb), and +X is normal
|
||||
// to the palm - *away* from it on the left hand, *into* it on the right. That
|
||||
// asymmetry is what makes both grips carry the same orientation when the hands
|
||||
// hold a wheel symmetrically, so the fingers run along -Y on both, and it is
|
||||
// the geometry across the palm that mirrors: fingers close towards +X on the
|
||||
// left hand and -X on the right, with the thumb on the same side. Building the
|
||||
// fingers on any other axis bends them out of the back of the hand (seen on a
|
||||
// Quest 3 on 2026-09-22) or, for the right hand alone, points them at the
|
||||
// player (seen on the PC on 2026-09-23).
|
||||
inline void glove(std::vector<Vertex>& v, const AuroraCockpitHand& hand, int side) {
|
||||
const size_t start=v.size();
|
||||
const V white{0.91f,0.95f,1.0f};
|
||||
const float forward=side==0?-1.0f:1.0f; // hand 0 is the left one
|
||||
const float palm=side==0?1.0f:-1.0f; // hand 0 is the left one
|
||||
const float curl=std::clamp(hand.held?0.85f:hand.squeeze,0.0f,1.0f);
|
||||
// Thin through the palm's normal, a little wider across the knuckles than
|
||||
// the palm is long.
|
||||
ellipsoid(v,{0,0,0},{0.018f,0.043f,0.041f},white);
|
||||
for(int finger=0;finger<4;++finger) {
|
||||
// Index finger nearest the thumb (-Z), little finger last.
|
||||
V a{0.0f,forward*0.030f,-0.025f+finger*0.017f};
|
||||
V a{0.0f,-0.030f,-0.025f+finger*0.017f};
|
||||
const float length=finger==0||finger==3?0.021f:0.026f;
|
||||
for(int joint=0;joint<3;++joint) {
|
||||
const float angle=curl*(0.55f+joint*0.8f);
|
||||
V b=add(a,{std::sin(angle)*length,forward*std::cos(angle)*length,0.0f});
|
||||
V b=add(a,{palm*std::sin(angle)*length,-std::cos(angle)*length,0.0f});
|
||||
tube(v,a,b,0.008f,white);
|
||||
ellipsoid(v,b,{0.008f,0.008f,0.008f},white);a=b;
|
||||
}
|
||||
}
|
||||
// Thumb: out of the palm's thumb side, closing across the fingers.
|
||||
const V thumbKnuckle{0.026f,forward*0.034f,-0.030f};
|
||||
tube(v,{0.010f,forward*0.012f,-0.034f},thumbKnuckle,0.010f,white);
|
||||
tube(v,thumbKnuckle,{0.030f+0.014f*curl,forward*(0.052f-0.016f*curl),-0.020f},0.009f,white);
|
||||
const V thumbKnuckle{palm*0.026f,-0.034f,-0.030f};
|
||||
tube(v,{palm*0.010f,-0.012f,-0.034f},thumbKnuckle,0.010f,white);
|
||||
tube(v,thumbKnuckle,{palm*(0.030f+0.014f*curl),-(0.052f-0.016f*curl),-0.020f},0.009f,white);
|
||||
for(size_t i=start;i<v.size();++i) v[i].position=point(hand.seatFromGrip,v[i].position);
|
||||
}
|
||||
inline void runtime_hand(std::vector<Vertex>& out, const AuroraCockpitHand& hand, const HandMesh& mesh) {
|
||||
|
||||
@@ -116,8 +116,11 @@ TEST_F(CockpitGeometry, TrackedHandDrawsAGloveAtItsGrip) {
|
||||
// thumb, +X out of the palm. So the fingers run along Y (+Y on the right hand,
|
||||
// -Y on the left) and close towards +X, never out of the back of the hand.
|
||||
TEST_F(CockpitGeometry, GloveFingersRunAlongTheHandAndCloseIntoThePalm) {
|
||||
// Both grips carry the same orientation when the hands hold a wheel symmetrically, so the fingers
|
||||
// run along -Y on both and it is the palm side that mirrors: +X on the left hand, -X on the right.
|
||||
// Building the right hand's fingers on +Y instead pointed them at the player (PC, 2026-09-23).
|
||||
for (int side = 0; side < 2; ++side) {
|
||||
const float forward = side == 0 ? -1.0f : 1.0f;
|
||||
const float palmSide = side == 0 ? 1.0f : -1.0f;
|
||||
const auto build = [&](float squeeze) {
|
||||
AuroraCockpit cockpit{};
|
||||
cockpit.nativeWheel = true;
|
||||
@@ -135,9 +138,9 @@ TEST_F(CockpitGeometry, GloveFingersRunAlongTheHandAndCloseIntoThePalm) {
|
||||
const auto measure = [&](const std::vector<Vertex>& vertices) {
|
||||
Extent e{};
|
||||
for (const auto& vertex : vertices) {
|
||||
e.reach = std::max(e.reach, vertex.position[1] * forward);
|
||||
e.palm = std::max(e.palm, vertex.position[0]);
|
||||
e.back = std::min(e.back, vertex.position[0]);
|
||||
e.reach = std::max(e.reach, -vertex.position[1]);
|
||||
e.palm = std::max(e.palm, vertex.position[0] * palmSide);
|
||||
e.back = std::min(e.back, vertex.position[0] * palmSide);
|
||||
e.across = std::max(e.across, std::abs(vertex.position[2]));
|
||||
}
|
||||
return e;
|
||||
|
||||
Reference in new issue
Block a user