A reimplementation of Mario Kart Wii's physics engine in C++
Loading...
Searching...
No Matches
KartDynamics.cc
1#include "KartDynamics.hh"
2
3#include <egg/math/Math.hh>
4
5namespace Kart {
6
8KartDynamics::KartDynamics() {
9 m_angVel0Factor = 1.0f;
10 m_inertiaTensor = EGG::Matrix34f::ident;
11 m_invInertiaTensor = EGG::Matrix34f::ident;
12 init();
13}
14
16KartDynamics::~KartDynamics() = default;
17
21 EGG::Vector3f top = m_mainRot.rotateVector(EGG::Vector3f::ey);
22 if (EGG::Mathf::abs(top.dot(m_top)) >= 0.9999f) {
23 return;
24 }
25
26 EGG::Quatf q;
29}
30
32void KartDynamics::init() {
33 m_pos = EGG::Vector3f::zero;
34 m_extVel = EGG::Vector3f::zero;
35 m_acceleration = EGG::Vector3f::zero;
36 m_angVel0 = EGG::Vector3f::zero;
37 m_movingObjVel = EGG::Vector3f::zero;
38 m_angVel1 = EGG::Vector3f::zero;
39 m_movingRoadVel = EGG::Vector3f::zero;
40 m_velocity = EGG::Vector3f::zero;
41 m_speedNorm = 0.0f;
42 m_angVel2 = EGG::Vector3f::zero;
43 m_mainRot = EGG::Quatf::ident;
44 m_fullRot = EGG::Quatf::ident;
45 m_totalForce = EGG::Vector3f::zero;
46 m_totalTorque = EGG::Vector3f::zero;
47 m_specialRot = EGG::Quatf::ident;
48 m_extraRot = EGG::Quatf::ident;
49 m_gravity = -1.0f;
50 m_intVel = EGG::Vector3f::zero;
51 m_top = EGG::Vector3f::ey;
52 m_forceUpright = true;
53 m_noGravity = false;
54 m_killExtVelY = false;
56 m_top_ = EGG::Vector3f::ey;
57 m_speedFix = 0.0f;
58 m_angVel0YFactor = 0.0f;
59 m_scale = EGG::Vector3f::unit;
60}
61
63void KartDynamics::setInertia(const EGG::Vector3f &m, const EGG::Vector3f &n) {
64 constexpr f32 TWELFTH = 1.0f / 12.0f;
65
66 m_inertiaTensor = EGG::Matrix34f::zero;
67 m_inertiaTensor[0, 0] = TWELFTH * (m.y * m.y + m.z * m.z) + (n.y * n.y + n.z * n.z);
68 m_inertiaTensor[1, 1] = TWELFTH * (m.z * m.z + m.x * m.x) + (n.z * n.z + n.x * n.x);
69 m_inertiaTensor[2, 2] = TWELFTH * (m.x * m.x + m.y * m.y) + (n.x * n.x + n.y * n.y);
71}
72
75void KartDynamics::setBspParams(f32 rotSpeed, const EGG::Vector3f &m, const EGG::Vector3f &n,
76 bool skipInertia) {
77 m_angVel0Factor = rotSpeed;
78
79 if (skipInertia) {
80 return;
81 }
82
83 setInertia(m, n);
84}
85
91void KartDynamics::calc(f32 dt, f32 maxSpeed, bool air) {
92 constexpr f32 TERMINAL_Y_VEL = 120.0f;
93
94 if (!m_noGravity) {
96 }
97
100
101 if (m_killExtVelY) {
102 m_extVel.y = std::min(0.0f, m_extVel.y);
103 }
104
105 m_extVel *= 0.998f;
106 m_angVel0 *= 0.98f;
107
108 EGG::Vector3f playerBack = m_mainRot.rotateVector(EGG::Vector3f::ez);
109 EGG::Vector3f playerBackHoriz = playerBack;
110 playerBackHoriz.y = 0.0f;
111
112 if (playerBackHoriz.squaredLength() > std::numeric_limits<f32>::epsilon()) {
113 playerBackHoriz.normalise();
114 const auto [proj, rej] = m_extVel.projAndRej(playerBackHoriz);
115 const EGG::Vector3f &speedBack = proj;
116 m_extVel = rej;
117
118 f32 norm = speedBack.squaredLength();
119 norm = norm > std::numeric_limits<f32>::epsilon() ? EGG::Mathf::sqrt(norm) : 0.0f;
120
121 m_speedFix = norm * playerBack.dot(playerBackHoriz);
122 if (speedBack.dot(playerBackHoriz) < 0.0f) {
123 m_speedFix = -m_speedFix;
124 }
125 }
126
127 if (air) {
128 m_intVel.y = std::min(TERMINAL_Y_VEL, m_intVel.y);
129 }
130
132
133 if (m_scale.z > 1.0f) {
134 maxSpeed *= m_scale.z;
135 }
136
137 m_speedNorm = std::min(m_velocity.normalise(), maxSpeed);
139 m_pos += m_velocity;
140
142 m_angVel0 += (t1 + m_invInertiaTensor.multVector33(t1 + m_totalTorque) * dt) * 0.5f;
143
144 m_angVel0.x = std::min(0.4f, std::max(-0.4f, m_angVel0.x));
145 m_angVel0.y = std::min(0.4f, std::max(-0.4f, m_angVel0.y)) * m_angVel0YFactor;
146 m_angVel0.z = std::min(0.8f, std::max(-0.8f, m_angVel0.z));
147
148 if (m_forceUpright) {
149 forceUpright();
150 }
151
153
154 if (angVelSum.squaredLength() > std::numeric_limits<f32>::epsilon()) {
155 m_mainRot += m_mainRot.multSwap(angVelSum) * (dt * 0.5f);
156
157 if (EGG::Mathf::abs(m_mainRot.squaredNorm()) > std::numeric_limits<f32>::epsilon()) {
159 } else {
160 m_mainRot = EGG::Quatf::ident;
161 }
162 }
163
164 if (m_forceUpright) {
165 stabilize();
166 }
167
168 if (EGG::Mathf::abs(m_mainRot.squaredNorm()) > std::numeric_limits<f32>::epsilon()) {
170 } else {
171 m_mainRot = EGG::Quatf::ident;
172 }
173
174 m_fullRot = m_extraRot.multSwap(m_mainRot).multSwap(m_specialRot);
176
177 m_totalForce.setZero();
178 m_totalTorque.setZero();
179 m_angVel2.setZero();
180}
181
183void KartDynamics::reset() {
184 m_extVel.setZero();
185 m_acceleration.setZero();
186 m_angVel0.setZero();
187 m_movingObjVel.setZero();
188 m_angVel1.setZero();
189 m_movingRoadVel.setZero();
190 m_angVel2.setZero();
191 m_totalForce.setZero();
192 m_totalTorque.setZero();
193 m_intVel.setZero();
194}
195
204 const EGG::Vector3f &Frot, bool ignoreX) {
205 m_totalForce.y += Flinear.y;
208 EGG::Vector3f torque = rBody.cross(fBody);
209
210 if (ignoreX) {
211 torque.x = 0.0f;
212 }
213 torque.y = 0.0f;
214 m_totalTorque += torque;
215}
216
221 m_totalForce += f;
222
223 EGG::Vector3f invForceRot = m_fullRot.rotateVectorInv(f);
224 EGG::Vector3f relPos = p - m_pos;
225 EGG::Vector3f invPosRot = m_fullRot.rotateVectorInv(relPos);
226
227 m_totalTorque += invPosRot.cross(invForceRot) * scale;
228}
229
230KartDynamicsBike::KartDynamicsBike() = default;
231
233KartDynamicsBike::~KartDynamicsBike() = default;
234
236void KartDynamicsBike::forceUpright() {
237 m_angVel0.z = 0.0f;
238}
239
244 EGG::Vector3f forward = m_top.cross(m_mainRot.rotateVector(EGG::Vector3f::ez)).cross(m_top);
245 forward.normalise();
246 EGG::Vector3f local_4c = forward.cross(m_top_.cross(forward));
247 local_4c.normalise();
248
249 EGG::Vector3f top = m_mainRot.rotateVector(EGG::Vector3f::ey);
250 if (EGG::Mathf::abs(top.dot(local_4c)) >= 0.9999f) {
251 return;
252 }
253
254 EGG::Quatf q;
255 q.makeVectorRotation(top, local_4c);
257}
258
259} // namespace Kart
Vector3f multVector33(const Vector3f &vec) const
Multiplies a 3x3 matrix by a vector.
Definition Matrix.cc:249
void inverseTo33(Matrix34f &out) const
Inverts the 3x3 portion of the 3x4 matrix.
Definition Matrix.cc:295
void stabilize() override
Stabilizes the bike by rotating towards the y-axis unit vector.
EGG::Quatf m_specialRot
Rotation from trick animations. Copied from KartPhysics.
EGG::Vector3f m_movingRoadVel
Velocity from Koopa Cape water.
f32 m_speedNorm
Min of the max speed and m_velocity magnitude.
bool m_killExtVelY
Caps external velocity at 0.
EGG::Vector3f m_angVel1
[Unused]
void setBspParams(f32 rotSpeed, const EGG::Vector3f &m, const EGG::Vector3f &n, bool skipInertia)
On init, takes elements from the kart's BSP and computes the moment of inertia tensor.
f32 m_angVel0YFactor
Scalar for damping angular velocity.
EGG::Quatf m_fullRot
The combination of the other rotations.
EGG::Vector3f m_velocity
Sum of the linear velocities.
EGG::Vector3f m_top_
Basically m_top biased towards absolute up.
EGG::Vector3f m_totalTorque
Torque from linear motion and rotation.
EGG::Matrix34f m_invInertiaTensor
The inverse of m_inertiaTensor.
void applySuspensionWrench(const EGG::Vector3f &p, const EGG::Vector3f &Flinear, const EGG::Vector3f &Frot, bool ignoreX)
Every frame, computes torque from linear motion and rotation.
EGG::Vector3f m_top
The unit vector pointing up from the vehicle.
EGG::Vector3f m_intVel
What you typically consider to be the vehicle's speed.
EGG::Vector3f m_acceleration
Basically just m_totalForce.
EGG::Quatf m_extraRot
[Unused]
void applyWrenchScaled(const EGG::Vector3f &p, const EGG::Vector3f &f, f32 scale)
Applies a force linearly and rotationally to the kart.
EGG::Vector3f m_totalForce
Basically just gravity.
bool m_noGravity
Disables gravity. Relevant when respawning.
EGG::Matrix34f m_inertiaTensor
Resistance to rotational change, as a 3x3 matrix.
EGG::Vector3f m_angVel0
Angular velocity from m_totalTorque.
EGG::Vector3f m_pos
The vehicle's position.
EGG::Vector3f m_angVel2
The main component of angular velocity.
f32 m_stabilizationFactor
Scalar for damping the main rotation.
EGG::Vector3f m_movingObjVel
Velocity from things like TF conveyers.
EGG::Vector3f m_extVel
Velocity induced by collisions.
bool m_forceUpright
Specifies if we should return the vehicle to upwards orientation.
EGG::Quatf m_mainRot
Rotation based on the angular velocities.
virtual void stabilize()
Stabilizes the kart by rotating towards the y-axis unit vector.
void calc(f32 dt, f32 maxSpeed, bool air)
Every frame, computes acceleration, velocity, position and rotation of the kart.
f32 m_angVel0Factor
Scalar for damping angular velocity.
f32 m_gravity
Usually -1.3f, also affected by KartMove::calcDive.
Pertains to kart-related functionality.
A quaternion, used to represent 3D rotation.
Definition Quat.hh:12
void normalise()
Scales the quaternion to a unit length.
Definition Quat.cc:28
Vector3f rotateVector(const Vector3f &vec) const
Rotates a vector based on the quat.
Definition Quat.cc:55
f32 squaredNorm() const
Computes .
Definition Quat.hh:97
Quatf slerpTo(const Quatf &q2, f32 t) const
Performs spherical linear interpolation.
Definition Quat.cc:84
Vector3f rotateVectorInv(const Vector3f &vec) const
Rotates a vector on the inverse quat.
Definition Quat.cc:69
void makeVectorRotation(const Vector3f &from, const Vector3f &to)
Captures rotation between two vectors.
Definition Quat.cc:40
A 3D float vector.
Definition Vector.hh:88
f32 normalise()
Normalizes the vector and returns the original length.
Definition Vector.cc:52
f32 dot(const Vector3f &rhs) const
The dot product between two vectors.
Definition Vector.hh:187
f32 squaredLength() const
The dot product between the vector and itself.
Definition Vector.hh:182