mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 05:00:27 +02:00
Add the VR cockpit overlay to Aurora's eye replay
A stereo packet can now carry an AuroraCockpit: tracked hands and, when the vehicle's own wheel cannot be animated, a synthetic steering wheel or handlebar, all in metres in the seated frame. Each eye draws it inside the scene's pass just before the first virtual-screen draw, depth-tested with the world's own depth mapping (captured from a full-view world draw), so the kart and track occlude the hands and the 2D layer cannot hide them. Hands use a runtime-provided hand mesh when one is supplied and a procedural glove otherwise. aurora_set_stereo_scene_anchor_scaled lets the sealed frame own its world scale: each eye's head translation is rescaled from the packet's scale to the frame's. A non-finite cockpit is dropped with one warning; the frame still renders. Ported from heurazy's mario-kart-wii-VR-port (GPL-3.0-or-later).
This commit is contained in:
1 parent
f3d7277ff3
commit
21b8d209dd
8 files changed
+749
No files matched your search
@@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// VR cockpit overlay geometry: what the synthetic wheel, handlebar and hands
|
||||
// build in the seated frame, without a GPU.
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "gfx/cockpit.hpp"
|
||||
|
||||
namespace {
|
||||
using aurora::gfx::cockpit::V;
|
||||
using aurora::gfx::cockpit::Vertex;
|
||||
|
||||
bool all_finite(const std::vector<Vertex>& vertices) {
|
||||
for (const auto& vertex : vertices) {
|
||||
for (float value : vertex.position) {
|
||||
uint32_t bits = 0;
|
||||
std::memcpy(&bits, &value, sizeof(bits));
|
||||
if ((bits & 0x7f800000u) == 0x7f800000u) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_identity(float (&matrix)[12], V translation) {
|
||||
const auto identity = aurora::gfx::cockpit::identity();
|
||||
std::memcpy(matrix, identity.data(), sizeof(matrix));
|
||||
matrix[3] = translation[0];
|
||||
matrix[7] = translation[1];
|
||||
matrix[11] = translation[2];
|
||||
}
|
||||
|
||||
class CockpitGeometry : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override { clear_meshes(); }
|
||||
void TearDown() override { clear_meshes(); }
|
||||
static void clear_meshes() {
|
||||
std::lock_guard lock(aurora::gfx::cockpit::meshMutex);
|
||||
aurora::gfx::cockpit::meshes = {};
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CockpitGeometry, NativeWheelWithoutHandsDrawsNothing) {
|
||||
AuroraCockpit cockpit{};
|
||||
cockpit.nativeWheel = true;
|
||||
EXPECT_TRUE(aurora::gfx::cockpit::geometry(cockpit).empty());
|
||||
}
|
||||
|
||||
TEST_F(CockpitGeometry, SyntheticKartWheelSitsOnItsRim) {
|
||||
AuroraCockpit cockpit{};
|
||||
const auto vertices = aurora::gfx::cockpit::geometry(cockpit);
|
||||
ASSERT_FALSE(vertices.empty());
|
||||
ASSERT_TRUE(all_finite(vertices));
|
||||
// The rim, spokes and hub stay within the 0.18 m wheel plus its tube, around
|
||||
// the wheel centre the input side uses (steering_wheel.h).
|
||||
for (const auto& vertex : vertices) {
|
||||
const float x = vertex.position[0];
|
||||
const float y = vertex.position[1] + 0.30f;
|
||||
EXPECT_LE(std::hypot(x, y), 0.18f + 0.02f);
|
||||
EXPECT_NEAR(vertex.position[2], -0.42f, 0.04f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CockpitGeometry, SyntheticWheelTurnsWithTheAngle) {
|
||||
AuroraCockpit cockpit{};
|
||||
const auto straight = aurora::gfx::cockpit::geometry(cockpit);
|
||||
cockpit.wheelAngle = 0.5f;
|
||||
const auto turned = aurora::gfx::cockpit::geometry(cockpit);
|
||||
ASSERT_EQ(straight.size(), turned.size());
|
||||
bool moved = false;
|
||||
for (size_t i = 0; i < straight.size() && !moved; ++i) {
|
||||
moved = std::abs(straight[i].position[0] - turned[i].position[0]) > 1e-3f;
|
||||
}
|
||||
EXPECT_TRUE(moved);
|
||||
}
|
||||
|
||||
TEST_F(CockpitGeometry, SyntheticHandlebarFollowsItsFrame) {
|
||||
AuroraCockpit cockpit{};
|
||||
cockpit.bike = true;
|
||||
cockpit.handlebarRadius = 0.25f;
|
||||
// Bar axis along seat +X, centred 0.3 m down and 0.42 m ahead.
|
||||
const float pose[12]{1, 0, 0, 0, 0, 0, 1, -0.3f, 0, -1, 0, -0.42f};
|
||||
std::memcpy(cockpit.seatFromHandlebar, pose, sizeof(pose));
|
||||
const auto vertices = aurora::gfx::cockpit::geometry(cockpit);
|
||||
ASSERT_FALSE(vertices.empty());
|
||||
ASSERT_TRUE(all_finite(vertices));
|
||||
float minX = 1e9f;
|
||||
float maxX = -1e9f;
|
||||
for (const auto& vertex : vertices) {
|
||||
minX = std::min(minX, vertex.position[0]);
|
||||
maxX = std::max(maxX, vertex.position[0]);
|
||||
}
|
||||
EXPECT_NEAR(minX, -0.25f, 0.03f);
|
||||
EXPECT_NEAR(maxX, 0.25f, 0.03f);
|
||||
}
|
||||
|
||||
TEST_F(CockpitGeometry, TrackedHandDrawsAGloveAtItsGrip) {
|
||||
AuroraCockpit cockpit{};
|
||||
cockpit.nativeWheel = true;
|
||||
cockpit.hands[1].tracked = true;
|
||||
cockpit.hands[1].squeeze = 1.0f;
|
||||
set_identity(cockpit.hands[1].seatFromGrip, {0.2f, -0.3f, -0.4f});
|
||||
const auto vertices = aurora::gfx::cockpit::geometry(cockpit);
|
||||
ASSERT_FALSE(vertices.empty());
|
||||
ASSERT_TRUE(all_finite(vertices));
|
||||
for (const auto& vertex : vertices) {
|
||||
EXPECT_LT(std::abs(vertex.position[0] - 0.2f), 0.15f);
|
||||
EXPECT_LT(std::abs(vertex.position[1] + 0.3f), 0.15f);
|
||||
EXPECT_LT(std::abs(vertex.position[2] + 0.4f), 0.15f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CockpitGeometry, RuntimeHandMeshIsSkinnedWithoutNans) {
|
||||
using namespace aurora::gfx::cockpit;
|
||||
auto mesh = std::make_shared<HandMesh>();
|
||||
// A 26-joint chain, each joint 1 cm past its parent; one triangle on the tip.
|
||||
for (int j = 0; j < 26; ++j) {
|
||||
mesh->bind[j] = identity();
|
||||
mesh->bind[j][11] = -0.01f * float(j);
|
||||
mesh->inverseBind[j] = inverse(mesh->bind[j]);
|
||||
mesh->parents[j] = j - 1;
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
AuroraVRHandVertex vertex{};
|
||||
vertex.position[0] = 0.01f * float(i);
|
||||
vertex.position[2] = -0.25f;
|
||||
vertex.joints[0] = 25;
|
||||
vertex.joints[1] = vertex.joints[2] = vertex.joints[3] = -1;
|
||||
vertex.weights[0] = 1.0f;
|
||||
mesh->vertices.push_back(vertex);
|
||||
mesh->indices.push_back(uint16_t(i));
|
||||
}
|
||||
{
|
||||
std::lock_guard lock(meshMutex);
|
||||
meshes[0] = mesh;
|
||||
}
|
||||
AuroraCockpit cockpit{};
|
||||
cockpit.nativeWheel = true;
|
||||
cockpit.hands[0].tracked = true;
|
||||
cockpit.hands[0].held = true;
|
||||
set_identity(cockpit.hands[0].seatFromGrip, {-0.2f, -0.3f, -0.4f});
|
||||
const auto vertices = geometry(cockpit);
|
||||
ASSERT_EQ(vertices.size(), 3u) << "the runtime mesh replaces the glove";
|
||||
EXPECT_TRUE(all_finite(vertices));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in new issue
Block a user