Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
VrGliderComponent.h
Go to the documentation of this file.
1#pragma once
5
6#include <glm/glm.hpp>
7#include <glm/gtc/quaternion.hpp>
8
9namespace EngineCore
10{
11 class Headset;
12} // namespace EngineCore
13
14namespace Input
15{
16 class XrInputHandler;
17 enum class Hand;
18} // namespace Input
19
20namespace Engine
21{
22 namespace Rendering
23 {
24 class Headset;
25 } // namespace Rendering
26
30 enum class GliderState
31 {
32 FALLING, // Normal gravity
33 GLIDING, // Arms spread - velocity control
34 STALLED, // Arms spread but too little momentum / too much climb
35 WALKING // On ground - thumbstick locomotion
36 };
37
42 {
44 float armSpreadHysteresis = 0.08f;
45 float tuckDistance = 0.45f;
46
47 float gravity = 3.0f;
49
50 float momentumDrag = 0.12f;
51 float highSpeedDrag = 0.005f;
52 float minGlideSink = 0.65f;
53 float maxClimbRate = 6.0f;
54 float climbMomentumCost = 0.48f;
55 float diveSinkRate = 7.0f;
56 float diveMomentumGain = 0.72f;
57 float windMomentumGain = 0.72f;
58 float windDiminishingSpeed = 12.0f;
59 float windAlignmentPower = 1.6f;
60 float crosswindTurnRate = 0.06f;
61 float headwindPenalty = 0.55f;
62 float glideTurnRate = 7.0f;
63 float stallSpeed = 3.5f;
64 float stallRecoverySpeed = 4.7f;
65 float stallSinkSpeed = 6.0f;
66 float stallDiveSinkScale = 0.35f;
67 float stallExtraDrag = 0.12f;
68 float stallRecoveryDelay = 0.18f;
69 float emergencyMaxSpeed = 80.0f;
70
71 float snapTurnDegrees = 30.0f;
72 float snapTurnThreshold = 0.7f;
73 float stickDeadzone = 0.15f;
74
75 glm::vec3 spawnPosition{ 0.0f, 10.0f, 0.0f };
76
77 float walkSpeed = 2.5f;
78 float groundRayLength = 1.5f;
79 float groundSmoothSpeed = 12.0f;
80 float maxStepHeight = 0.3f;
81 float maxWalkableSlope = 0.7f;
82 float groundHoverOffset = 0.01f;
84 float walkTakeoffMomentum = 4.0f;
87 float fallResetY = -350.0f;
89 float respawnHeightOffset = 1.0f;
90 };
91
92 namespace Components
93 {
94 class PhysicsBody;
95
96 // TODO: Documentation
100 class VrGlider : public Logic
101 {
102 public:
103 static constexpr bool IsUnique = true;
104 static constexpr const char* ComponentName = "VrGlider";
105 static constexpr float CAPSULE_RADIUS = 0.3f; // Must match GliderPlayerActor capsule
106 static constexpr float CAPSULE_HALF_HEIGHT = 0.7f; // Half of cylinder portion (1.4/2)
107 static constexpr float CAPSULE_TOTAL_HALF = 1.0f; // CAPSULE_RADIUS + CAPSULE_HALF_HEIGHT
108
110 {
111 bool tickSkipped = false;
112 bool missingHeadset = false;
114 bool missingPhysicsBody = false;
115
116 bool enabled = true;
117 bool frozen = true;
118 bool debugLogging = true;
121
122 float leftGrip = 0.0f;
123 float rightGrip = 0.0f;
124 bool bothGripsPressed = false;
126
127 float leftTrigger = 0.0f;
128 float rightTrigger = 0.0f;
129 bool leftTriggerPressed = false;
131 glm::vec2 rightThumbstick{ 0.0f };
132 bool snapTurnArmed = true;
133 bool snapTurnTriggered = false;
135
136 bool leftHandValid = false;
137 bool rightHandValid = false;
138 float leftHandDistance = 0.0f;
139 float rightHandDistance = 0.0f;
142 bool armsSpread = false;
144 bool handsTucked = false;
145
146 bool groundDetected = false;
147 bool isNearGround = false;
148 bool groundIsWalkable = false;
149 bool groundYInitialized = false;
150 float groundDistance = 9999.0f;
151 float groundHitFraction = 1.0f;
152 glm::vec3 groundHitPoint{ 0.0f };
153 glm::vec3 groundHitNormal{ 0.0f, 1.0f, 0.0f };
154 float smoothedGroundY = 0.0f;
155
156 glm::vec3 playerPosition{ 0.0f };
157 glm::vec3 headLocalPosition{ 0.0f };
158 glm::vec3 headWorldPosition{ 0.0f };
159 glm::vec3 headForward{ 0.0f, 0.0f, -1.0f };
160 glm::vec3 bodyForward{ 0.0f, 0.0f, -1.0f };
161 glm::vec3 horizontalAim{ 0.0f, 0.0f, -1.0f };
162
163 glm::vec3 velocityBeforeUpdate{ 0.0f };
164 glm::vec3 targetVelocity{ 0.0f };
165 glm::vec3 velocityAfterUpdate{ 0.0f };
166 glm::vec3 desiredPosition{ 0.0f };
167 glm::vec3 physicsBodyVelocity{ 0.0f };
168
169 float playerYawRadians = 0.0f;
170 float palmTilt = 0.0f;
171 float forwardAmount = 0.0f;
172 float rightAmount = 0.0f;
173 float momentum = 0.0f;
174 float verticalVelocity = 0.0f;
175 float climbDemand = 0.0f;
176 float diveDemand = 0.0f;
177 float windAlignment = 0.0f;
178 float windMomentumDelta = 0.0f;
179 float dragDelta = 0.0f;
180 float climbMomentumDelta = 0.0f;
181 float stallRecoveryTimer = 0.0f;
182 bool isBraking = false;
183 bool isClimbing = false;
184 bool isDiving = false;
185 bool isStalled = false;
186 bool enteredStall = false;
187 bool recoveredStall = false;
188
190 glm::vec3 windContribution{ 0.0f };
191
192 bool collisionTested = false;
193 bool collisionImpact = false;
194 bool collisionReset = false;
195 bool takeoffArmed = true;
196 bool takeoffRequested = false;
197 bool takeoffBlocked = false;
198 bool hasLastSafeLanding = false;
199 bool respawnTriggered = false;
200 glm::vec3 takeoffTestPosition{ 0.0f };
201 glm::vec3 lastSafeLandingPosition{ 0.0f };
202 glm::vec3 collisionTestPosition{ 0.0f };
203 glm::vec3 collisionPushOut{ 0.0f };
204 glm::vec3 collisionGroundNormal{ 0.0f };
207
211 };
212
221 Entities::Scene * owningScene,
222 Rendering::Headset * headset,
223 Input::XrInputHandler * inputHandler,
224 PhysicsBody * physicsBody
225 );
226
227 ~VrGlider() override = default;
228
229 [[nodiscard]] std::string getComponentName() const override { return ComponentName; }
230
231 void beginPlay() override;
232 void tick( double deltaTime ) override;
233 void endPlay() override;
234
238 [[nodiscard]] GliderState getState() const
239 {
240 return currentState_;
241 }
242
246 [[nodiscard]] glm::vec3 getVelocity() const
247 {
248 return velocity_;
249 }
250
254 [[nodiscard]] float getSpeed() const
255 {
256 return glm::length( velocity_ );
257 }
258
262 [[nodiscard]] const GliderConfig & getConfig() const
263 {
264 return config_;
265 }
266
271 {
272 return config_;
273 }
274
278 void setConfig( const GliderConfig & config )
279 {
280 config_ = config;
281 }
282
286 void setEnabled( bool enabled )
287 {
288 enabled_ = enabled;
289 }
290
294 [[nodiscard]] bool isEnabled() const
295 {
296 return enabled_;
297 }
298
302 void setFrozen( bool frozen );
303
305
306 [[nodiscard]] PhysicsBody * getPhysicsBody() const { return physicsBody_; }
307
308 [[nodiscard]] const DebugSnapshot & getDebugSnapshot() const { return debugSnapshot_; }
309
313 [[nodiscard]] bool isFrozen() const
314 {
315 return frozen_;
316 }
317
321 void setDebugLogging( bool enabled )
322 {
323 debugLogging_ = enabled;
324 }
325
329 [[nodiscard]] bool isDebugLogging() const
330 {
331 return debugLogging_;
332 }
333
337 [[nodiscard]] static const char * stateToString( GliderState state );
338
339 private:
343 struct HandData
344 {
345 glm::vec3 position{ 0.0f };
346 glm::vec3 relativePosition{ 0.0f };
347 glm::quat orientation{ 1.0f, 0.0f, 0.0f, 0.0f };
348 glm::vec3 palmNormal{ 0.0f, -1.0f, 0.0f };
349 glm::vec3 fingerDirection{ 0.0f, 0.0f, -1.0f };
350 glm::vec3 thumbDirection{ 0.0f, 1.0f, 0.0f };
351 float distanceFromHead = 0.0f;
352 bool isValid = false;
353 };
354
355 [[nodiscard]] HandData getHandData( Input::Hand hand ) const;
356
357 [[nodiscard]] bool areArmsSpread(
358 const HandData & leftHand,
359 const HandData & rightHand,
360 float hysteresis = 0.0f
361 ) const;
362
363 [[nodiscard]] bool areHandsTucked( const HandData & leftHand, const HandData & rightHand ) const;
364
365 void updateGlidingVelocity( const HandData & leftHand, const HandData & rightHand, float dt );
366
368
369 [[nodiscard]] glm::vec3 buildGlideDirection(
370 const HandData & leftHand,
371 const HandData & rightHand,
372 glm::vec3 & outBodyForward,
373 float & outForwardAmount,
374 float & outRightAmount
375 ) const;
376
380 [[nodiscard]] glm::vec3 getHeadWorldPosition() const;
381
385 [[nodiscard]] glm::quat getHeadOrientation() const;
386
390 [[nodiscard]] glm::vec3 getHeadForward() const;
391
392 bool canStartGlidingFromWalking( const glm::vec3 & currentPos, glm::vec3 & outTakeoffPos ) const;
393
394 bool handleFlightCollision( const glm::vec3 & currentPos, glm::vec3 & desiredPos );
395
397 const glm::vec3 & origin,
398 glm::vec3 & outHitPoint,
399 glm::vec3 & outHitNormal,
400 float & outHitFraction
401 ) const;
402
403 void updateWalkingInput( float dt );
404
405 glm::vec3 collideAndSlide( const glm::vec3 & startPos, const glm::vec3 & displacement );
406
407 void updateLastSafeLanding( const glm::vec3 & position, bool stableWalkableGround, float dt );
408
409 void teleportPlayer( const glm::vec3 & position );
410
412
414
418
421 bool takeoffArmed_ = true;
422
423 glm::vec3 velocity_{ 0.0f };
424 bool enabled_ = true;
425 bool frozen_ = true; // Start frozen so user can put on headset
426 bool debugLogging_ = true; // Enabled to diagnose flight tuning issues.
427 float debugLogTimer_ = 0.0f;
428 static constexpr float DEBUG_LOG_INTERVAL = 0.5f; // Log every 0.5 seconds
429
430 // Grip toggle detection (freeze/unfreeze)
432 static constexpr float GRIP_THRESHOLD = 0.8f; // Grip/trigger must be >80% to count as pressed
433
437 glm::vec3 lastSafeLandingPosition_{ 0.0f, 10.0f, 0.0f };
440
441 // Player yaw for right-stick snap turning (radians, applied to body forward)
442 float playerYaw_ = 0.0f;
444
445 // Walking state
446 float smoothedGroundY_ = 0.0f; // Lerp-smoothed ground height to prevent jitter
447 bool groundYInitialized_ = false; // Whether smoothedGroundY_ has been set from a sweep yet
448
449 // Sweep test constants
450 static constexpr float SKIN_WIDTH = 0.02f; // Small gap to prevent direct surface contact
451 static constexpr int MAX_SLIDE_ITERATIONS = 3; // Max collide-and-slide recursions
452 };
453 } // namespace Components
454
455} // namespace Engine
Logic(Entities::Scene *owningScene)
Component that manages a physics rigid body for an entity.
bool areArmsSpread(const HandData &leftHand, const HandData &rightHand, float hysteresis=0.0f) const
static constexpr float DEBUG_LOG_INTERVAL
glm::vec3 collideAndSlide(const glm::vec3 &startPos, const glm::vec3 &displacement)
void resetGliderStateTo(GliderState state)
static constexpr float GRIP_THRESHOLD
void updateWalkingInput(float dt)
void tick(double deltaTime) override
Called every frame if ticking is enabled.
void beginPlay() override
Called when the component is added to the scene or the game starts.
glm::vec3 getHeadForward() const
Getter.
const GliderConfig & getConfig() const
Getter.
bool sweepGround(const glm::vec3 &origin, glm::vec3 &outHitPoint, glm::vec3 &outHitNormal, float &outHitFraction) const
bool handleFlightCollision(const glm::vec3 &currentPos, glm::vec3 &desiredPos)
glm::vec3 buildGlideDirection(const HandData &leftHand, const HandData &rightHand, glm::vec3 &outBodyForward, float &outForwardAmount, float &outRightAmount) const
glm::vec3 getHeadWorldPosition() const
Getter.
static constexpr float CAPSULE_TOTAL_HALF
static constexpr int MAX_SLIDE_ITERATIONS
static constexpr float SKIN_WIDTH
static constexpr bool IsUnique
GliderState getState() const
Getter.
std::string getComponentName() const override
Gets the component type name for debugging/UI.
void setDebugLogging(bool enabled)
Setter.
bool isDebugLogging() const
Getter.
static const char * stateToString(GliderState state)
Returns string representation of a glider state.
PhysicsBody * getPhysicsBody() const
void updateLastSafeLanding(const glm::vec3 &position, bool stableWalkableGround, float dt)
Input::XrInputHandler * inputHandler_
bool areHandsTucked(const HandData &leftHand, const HandData &rightHand) const
void setConfig(const GliderConfig &config)
Setter.
const DebugSnapshot & getDebugSnapshot() const
void endPlay() override
Called when the component is removed or the game ends.
void setFrozen(bool frozen)
Pauses/unpauses physics integration.
void updateGlidingVelocity(const HandData &leftHand, const HandData &rightHand, float dt)
HandData getHandData(Input::Hand hand) const
static constexpr const char * ComponentName
glm::vec3 getVelocity() const
Getter.
static constexpr float CAPSULE_HALF_HEIGHT
void setEnabled(bool enabled)
Setter.
void teleportPlayer(const glm::vec3 &position)
VrGlider(Entities::Scene *owningScene, Rendering::Headset *headset, Input::XrInputHandler *inputHandler, PhysicsBody *physicsBody)
Constructs the VR glider component.
static constexpr float CAPSULE_RADIUS
~VrGlider() override=default
bool canStartGlidingFromWalking(const glm::vec3 &currentPos, glm::vec3 &outTakeoffPos) const
ArcadeGliderTuning makeFlightTuning() const
glm::quat getHeadOrientation() const
Getter.
GliderConfig & getConfig()
Getter.
A scene is the overarching structure which can spawn, contain and destroy actors or entities.
Definition Scene.h:56
Handles OpenXR input actions and controller state.
GliderState
Glider movement states.
Stores the config values for the glider. Can be used to change the flight behavior of the glider move...
Hand position and orientation data relative to head.
Configuration parameters for the VR glider system (distances in meters, speeds in m/s,...
A wind sample is the wind force at one point in the wind field.
Definition WindField.h:46