Jolt Physics
A multi core friendly Game Physics Engine
Loading...
Searching...
No Matches
ContactConstraintPart.h
Go to the documentation of this file.
1// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2// SPDX-FileCopyrightText: 2026 Jorrit Rouwe
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
8
10
12template <EMotionType Type1>
14{
15public:
17 inline void Deactivate()
18 {
19 mEffectiveMass = 0.0f;
20 mTotalLambda = 0.0f;
21 }
22
24 inline bool IsActive() const
25 {
26 return mEffectiveMass != 0.0f;
27 }
28
30 inline void SetTotalLambda(float inLambda)
31 {
32 mTotalLambda = inLambda;
33 }
34
36 inline float GetTotalLambda() const
37 {
38 return mTotalLambda;
39 }
40
41protected:
42 // Note: Constructor will not be called
45 float mBias;
46};
47
48template <>
50{
51protected:
52 // Note: Constructor will not be called
54};
55
56template <>
57class ContactConstraintPart1<EMotionType::Dynamic> : public ContactConstraintPart1<EMotionType::Kinematic>
58{
59protected:
60 // Note: Constructor will not be called
62};
63
64template <EMotionType Type2>
68
69template <>
71{
72protected:
73 // Note: Constructor will not be called
75};
76
77template <>
78class ContactConstraintPart2<EMotionType::Dynamic> : public ContactConstraintPart2<EMotionType::Kinematic>
79{
80protected:
81 // Note: Constructor will not be called
83};
84
85static_assert(sizeof(ContactConstraintPart1<EMotionType::Kinematic>) == 3 * sizeof(float) + sizeof(Float3));
86static_assert(sizeof(ContactConstraintPart1<EMotionType::Dynamic>) == 3 * sizeof(float) + 2 * sizeof(Float3));
87static_assert(sizeof(ContactConstraintPart2<EMotionType::Kinematic>) == sizeof(Float3));
88static_assert(sizeof(ContactConstraintPart2<EMotionType::Dynamic>) == 2 * sizeof(Float3));
89
92template <EMotionType Type1, EMotionType Type2>
94{
95private:
97 JPH_INLINE bool ApplyVelocityStep(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inLambda) const
98 {
99 if (inLambda != 0.0f)
100 {
101 if constexpr (Type1 == EMotionType::Dynamic)
102 {
103 ioLinearVelocity1 -= (inLambda * inInvMass1) * inWorldSpaceAxis;
104 ioAngularVelocity1 -= inLambda * Vec3::sLoadFloat3Unsafe(this->mInvI1_R1PlusUxAxis);
105 }
106 if constexpr (Type2 == EMotionType::Dynamic)
107 {
108 ioLinearVelocity2 += (inLambda * inInvMass2) * inWorldSpaceAxis;
109 ioAngularVelocity2 += inLambda * Vec3::sLoadFloat3Unsafe(this->mInvI2_R2xAxis);
110 }
111 return true;
112 }
113
114 return false;
115 }
116
117public:
119 JPH_INLINE void CalculateConstraintProperties(float inInvMass1, Mat44Arg inInvI1, Vec3Arg inR1PlusU, float inInvMass2, Mat44Arg inInvI2, Vec3Arg inR2, Vec3Arg inWorldSpaceAxis, float inBias = 0.0f)
120 {
121 JPH_ASSERT(inWorldSpaceAxis.IsNormalized(1.0e-5f));
122
123 // Calculate inverse effective mass: K = J M^-1 J^T
124 float inv_effective_mass;
125
126 if constexpr (Type1 != EMotionType::Static)
127 {
128 Vec3 r1_plus_u_x_axis = inR1PlusU.Cross(inWorldSpaceAxis);
129 r1_plus_u_x_axis.StoreFloat3(&this->mR1PlusUxAxis);
130
131 if constexpr (Type1 == EMotionType::Dynamic)
132 {
133 Vec3 invi1_r1_plus_u_x_axis = inInvI1.Multiply3x3(r1_plus_u_x_axis);
134 invi1_r1_plus_u_x_axis.StoreFloat3(&this->mInvI1_R1PlusUxAxis);
135
136 inv_effective_mass = inInvMass1 + invi1_r1_plus_u_x_axis.Dot(r1_plus_u_x_axis);
137 }
138 else
139 inv_effective_mass = 0.0f;
140 }
141 else
142 inv_effective_mass = 0.0f;
143
144 if constexpr (Type2 != EMotionType::Static)
145 {
146 Vec3 r2_x_axis = inR2.Cross(inWorldSpaceAxis);
147 r2_x_axis.StoreFloat3(&this->mR2xAxis);
148
149 if constexpr (Type2 == EMotionType::Dynamic)
150 {
151 Vec3 invi2_r2_x_axis = inInvI2.Multiply3x3(r2_x_axis);
152 invi2_r2_x_axis.StoreFloat3(&this->mInvI2_R2xAxis);
153
154 inv_effective_mass += inInvMass2 + invi2_r2_x_axis.Dot(r2_x_axis);
155 }
156 }
157
158 if (inv_effective_mass == 0.0f)
159 this->Deactivate();
160 else
161 {
162 this->mEffectiveMass = 1.0f / inv_effective_mass;
163 this->mBias = inBias;
164 }
165 }
166
168 JPH_INLINE bool WarmStart(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inWarmStartImpulseRatio)
169 {
170 this->mTotalLambda *= inWarmStartImpulseRatio;
171
172 return ApplyVelocityStep(ioLinearVelocity1, ioAngularVelocity1, ioLinearVelocity2, ioAngularVelocity2, inInvMass1, inInvMass2, inWorldSpaceAxis, this->mTotalLambda);
173 }
174
176 JPH_INLINE float SolveVelocityConstraintGetTotalLambda(Vec3Arg inLinearVelocity1, Vec3Arg inAngularVelocity1, Vec3Arg inLinearVelocity2, Vec3Arg inAngularVelocity2, Vec3Arg inWorldSpaceAxis) const
177 {
178 // Calculate jacobian multiplied by linear velocity
179 float jv;
180 if constexpr (Type1 != EMotionType::Static && Type2 != EMotionType::Static)
181 jv = inWorldSpaceAxis.Dot(inLinearVelocity1 - inLinearVelocity2);
182 else if constexpr (Type1 != EMotionType::Static)
183 jv = inWorldSpaceAxis.Dot(inLinearVelocity1);
184 else if constexpr (Type2 != EMotionType::Static)
185 jv = inWorldSpaceAxis.Dot(-inLinearVelocity2);
186 else
187 JPH_ASSERT(false); // Static vs static is nonsensical!
188
189 // Calculate jacobian multiplied by angular velocity
190 if constexpr (Type1 != EMotionType::Static)
191 jv += Vec3::sLoadFloat3Unsafe(this->mR1PlusUxAxis).Dot(inAngularVelocity1);
192 if constexpr (Type2 != EMotionType::Static)
193 jv -= Vec3::sLoadFloat3Unsafe(this->mR2xAxis).Dot(inAngularVelocity2);
194
195 // Lagrange multiplier is:
196 //
197 // lambda = -K^-1 (J v + b)
198 float lambda = this->mEffectiveMass * (jv - this->mBias);
199
200 // Return the total accumulated lambda
201 return this->mTotalLambda + lambda;
202 }
203
205 JPH_INLINE bool SolveVelocityConstraintApplyLambda(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inTotalLambda)
206 {
207 float delta_lambda = inTotalLambda - this->mTotalLambda; // Calculate change in lambda
208 this->mTotalLambda = inTotalLambda; // Store accumulated impulse
209
210 return ApplyVelocityStep(ioLinearVelocity1, ioAngularVelocity1, ioLinearVelocity2, ioAngularVelocity2, inInvMass1, inInvMass2, inWorldSpaceAxis, delta_lambda);
211 }
212
214 JPH_INLINE bool SolveVelocityConstraint(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inMinLambda, float inMaxLambda)
215 {
216 float total_lambda = SolveVelocityConstraintGetTotalLambda(ioLinearVelocity1, ioAngularVelocity1, ioLinearVelocity2, ioAngularVelocity2, inWorldSpaceAxis);
217
218 // Clamp impulse to specified range
219 total_lambda = Clamp(total_lambda, inMinLambda, inMaxLambda);
220
221 return SolveVelocityConstraintApplyLambda(ioLinearVelocity1, ioAngularVelocity1, ioLinearVelocity2, ioAngularVelocity2, inInvMass1, inInvMass2, inWorldSpaceAxis, total_lambda);
222 }
223
225 JPH_INLINE bool SolvePositionConstraint(Body &ioBody1, float inInvMass1, Body &ioBody2, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inC, float inBaumgarte) const
226 {
227 if (inC != 0.0f)
228 {
229 float lambda = -this->mEffectiveMass * inBaumgarte * inC;
230 if constexpr (Type1 == EMotionType::Dynamic)
231 {
232 ioBody1.SubPositionStep((lambda * inInvMass1) * inWorldSpaceAxis);
233 ioBody1.SubRotationStep(lambda * Vec3::sLoadFloat3Unsafe(this->mInvI1_R1PlusUxAxis));
234 }
235 if constexpr (Type2 == EMotionType::Dynamic)
236 {
237 ioBody2.AddPositionStep((lambda * inInvMass2) * inWorldSpaceAxis);
238 ioBody2.AddRotationStep(lambda * Vec3::sLoadFloat3Unsafe(this->mInvI2_R2xAxis));
239 }
240 return true;
241 }
242
243 return false;
244 }
245};
246
247static_assert(sizeof(ContactConstraintPart<EMotionType::Dynamic, EMotionType::Dynamic>) == 3 * sizeof(float) + 4 * sizeof(Float3));
248static_assert(sizeof(ContactConstraintPart<EMotionType::Dynamic, EMotionType::Kinematic>) == 3 * sizeof(float) + 3 * sizeof(Float3));
249static_assert(sizeof(ContactConstraintPart<EMotionType::Dynamic, EMotionType::Static>) == 3 * sizeof(float) + 2 * sizeof(Float3));
250static_assert(sizeof(ContactConstraintPart<EMotionType::Kinematic, EMotionType::Kinematic>) == 3 * sizeof(float) + 2 * sizeof(Float3));
251static_assert(sizeof(ContactConstraintPart<EMotionType::Kinematic, EMotionType::Static>) == 3 * sizeof(float) + sizeof(Float3));
252static_assert(sizeof(ContactConstraintPart<EMotionType::Static, EMotionType::Dynamic>) == 3 * sizeof(float) + 2 * sizeof(Float3));
253static_assert(sizeof(ContactConstraintPart<EMotionType::Static, EMotionType::Kinematic>) == 3 * sizeof(float) + sizeof(Float3));
254static_assert(sizeof(ContactConstraintPart<EMotionType::Static, EMotionType::Static>) == 3 * sizeof(float));
255
258{
259public:
263
264 inline bool SolveVelocityConstraint(Body &inBody1, float inInvMass1, float inInvInertiaScale1, Vec3Arg inR1PlusU, Body &inBody2, float inInvMass2, float inInvInertiaScale2, Vec3Arg inR2, Vec3Arg inWorldSpaceAxis, float inBias, float inMinLambda, float inMaxLambda)
265 {
266 bool rv = false;
267 Vec3 linear_velocity1, angular_velocity1, linear_velocity2, angular_velocity2;
268
271
272 // Dispatch to the correct templated form
273 switch (inBody1.GetMotionType())
274 {
276 {
277 Mat44 inv_i1 = inInvInertiaScale1 * inBody1.GetInverseInertia();
278 linear_velocity1 = mp1->GetLinearVelocity();
279 angular_velocity1 = mp1->GetAngularVelocity();
280 switch (inBody2.GetMotionType())
281 {
283 mDD.CalculateConstraintProperties(inInvMass1, inv_i1, inR1PlusU, inInvMass2, inInvInertiaScale2 * inBody2.GetInverseInertia(), inR2, inWorldSpaceAxis, inBias);
284 linear_velocity2 = mp2->GetLinearVelocity();
285 angular_velocity2 = mp2->GetAngularVelocity();
286 rv = mDD.SolveVelocityConstraint(linear_velocity1, angular_velocity1, linear_velocity2, angular_velocity2, inInvMass1, inInvMass2, inWorldSpaceAxis, inMinLambda, inMaxLambda);
287 mp2->ApplyLinearVelocityStep(linear_velocity2);
288 mp2->ApplyAngularVelocityStep(angular_velocity2);
289 break;
290
292 mDK.CalculateConstraintProperties(inInvMass1, inv_i1, inR1PlusU, 0.0f /* Will not be used */, Mat44() /* Will not be used */, inR2, inWorldSpaceAxis, inBias);
293 linear_velocity2 = mp2->GetLinearVelocity();
294 angular_velocity2 = mp2->GetAngularVelocity();
295 rv = mDK.SolveVelocityConstraint(linear_velocity1, angular_velocity1, linear_velocity2, angular_velocity2, inInvMass1, 0.0f /* Will not be used */, inWorldSpaceAxis, inMinLambda, inMaxLambda);
296 break;
297
299 JPH_IF_DEBUG(linear_velocity2 = Vec3::sNaN();)
300 JPH_IF_DEBUG(angular_velocity2 = Vec3::sNaN();)
301 mDS.CalculateConstraintProperties(inInvMass1, inv_i1, inR1PlusU, 0.0f /* Will not be used */, Mat44() /* Will not be used */, inR2, inWorldSpaceAxis, inBias);
302 rv = mDS.SolveVelocityConstraint(linear_velocity1, angular_velocity1, linear_velocity2 /* Will not be used */, angular_velocity2 /* Will not be used */, inInvMass1, 0.0f /* Will not be used */, inWorldSpaceAxis, inMinLambda, inMaxLambda);
303 break;
304
305 default:
306 JPH_ASSERT(false);
307 break;
308 }
309 mp1->ApplyLinearVelocityStep(linear_velocity1);
310 mp1->ApplyAngularVelocityStep(angular_velocity1);
311 break;
312 }
313
315 JPH_ASSERT(inBody2.IsDynamic());
316 mKD.CalculateConstraintProperties(0 /* Will not be used */, Mat44() /* Will not be used */, inR1PlusU, inInvMass2, inInvInertiaScale2 * inBody2.GetInverseInertia(), inR2, inWorldSpaceAxis, inBias);
317 linear_velocity1 = mp1->GetLinearVelocity();
318 angular_velocity1 = mp1->GetAngularVelocity();
319 linear_velocity2 = mp2->GetLinearVelocity();
320 angular_velocity2 = mp2->GetAngularVelocity();
321 rv = mKD.SolveVelocityConstraint(linear_velocity1, angular_velocity1, linear_velocity2, angular_velocity2, 0.0f /* Will not be used */, inInvMass2, inWorldSpaceAxis, inMinLambda, inMaxLambda);
322 mp2->ApplyLinearVelocityStep(linear_velocity2);
323 mp2->ApplyAngularVelocityStep(angular_velocity2);
324 break;
325
327 JPH_ASSERT(inBody2.IsDynamic());
328 mSD.CalculateConstraintProperties(0 /* Will not be used */, Mat44() /* Will not be used */, inR1PlusU, inInvMass2, inInvInertiaScale2 * inBody2.GetInverseInertia(), inR2, inWorldSpaceAxis, inBias);
329 JPH_IF_DEBUG(linear_velocity1 = Vec3::sNaN();)
330 JPH_IF_DEBUG(angular_velocity1 = Vec3::sNaN();)
331 linear_velocity2 = mp2->GetLinearVelocity();
332 angular_velocity2 = mp2->GetAngularVelocity();
333 rv = mSD.SolveVelocityConstraint(linear_velocity1 /* Will not be used */, angular_velocity1 /* Will not be used */, linear_velocity2, angular_velocity2, 0.0f /* Unused */, inInvMass2, inWorldSpaceAxis, inMinLambda, inMaxLambda);
334 mp2->ApplyLinearVelocityStep(linear_velocity2);
335 mp2->ApplyAngularVelocityStep(angular_velocity2);
336 break;
337
338 default:
339 JPH_ASSERT(false);
340 break;
341 }
342
343 return rv;
344 }
345
346 inline float GetTotalLambda() const
347 {
348 return mDD.GetTotalLambda();
349 }
350
351private:
352 union
353 {
359 };
360 [[maybe_unused]] float mPadding; // Pad an extra float so that we can use Vec3::sLoadFloat3Unsafe on the last Float3 member without worrying about reading past the end of the struct
361};
362
#define JPH_IF_DEBUG(...)
Definition Core.h:569
#define JPH_NAMESPACE_END
Definition Core.h:428
#define JPH_NAMESPACE_BEGIN
Definition Core.h:422
#define JPH_ASSERT(...)
Definition IssueReporting.h:33
JPH_INLINE constexpr T Clamp(T inV, T inMin, T inMax)
Clamp a value between two values.
Definition Math.h:48
EMotionType
Motion type of a physics body.
Definition MotionType.h:11
@ Kinematic
Movable using velocities only, does not respond to forces.
@ Static
Non movable.
@ Dynamic
Responds to forces as a normal physics object.
Definition Body.h:39
EMotionType GetMotionType() const
Get the bodies motion type.
Definition Body.h:118
bool IsDynamic() const
Check if this body is dynamic, which means that it moves and forces can act on it.
Definition Body.h:67
void AddRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime)
Update rotation using an Euler step (used during position integrate & constraint solving)
Definition Body.inl:81
void SubPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime)
Definition Body.h:343
Mat44 GetInverseInertia() const
Get inverse inertia tensor in world space.
Definition Body.inl:120
void SubRotationStep(Vec3Arg inAngularVelocityTimesDeltaTime)
Definition Body.inl:100
const MotionProperties * GetMotionPropertiesUnchecked() const
Access to the motion properties (version that does not check if the object is kinematic or dynamic)
Definition Body.h:312
void AddPositionStep(Vec3Arg inLinearVelocityTimesDeltaTime)
Update position using an Euler step (used during position integrate & constraint solving)
Definition Body.h:342
Concrete contact constraint part that dispatches to the correct templated form based on the motion ty...
Definition ContactConstraintPart.h:258
ContactConstraintPart< EMotionType::Dynamic, EMotionType::Static > mDS
Definition ContactConstraintPart.h:356
float GetTotalLambda() const
Definition ContactConstraintPart.h:346
ContactConstraintPart< EMotionType::Dynamic, EMotionType::Kinematic > mDK
Definition ContactConstraintPart.h:355
bool SolveVelocityConstraint(Body &inBody1, float inInvMass1, float inInvInertiaScale1, Vec3Arg inR1PlusU, Body &inBody2, float inInvMass2, float inInvInertiaScale2, Vec3Arg inR2, Vec3Arg inWorldSpaceAxis, float inBias, float inMinLambda, float inMaxLambda)
Definition ContactConstraintPart.h:264
ConcreteContactConstraintPart()
Constructor / destructor.
Definition ContactConstraintPart.h:261
ContactConstraintPart< EMotionType::Dynamic, EMotionType::Dynamic > mDD
Definition ContactConstraintPart.h:354
ContactConstraintPart< EMotionType::Static, EMotionType::Dynamic > mSD
Definition ContactConstraintPart.h:358
ContactConstraintPart< EMotionType::Kinematic, EMotionType::Dynamic > mKD
Definition ContactConstraintPart.h:357
Float3 mInvI1_R1PlusUxAxis
Definition ContactConstraintPart.h:61
Float3 mR1PlusUxAxis
Definition ContactConstraintPart.h:53
Decide which members this constraint part needs based on motion type.
Definition ContactConstraintPart.h:14
float mBias
Definition ContactConstraintPart.h:45
float mEffectiveMass
Definition ContactConstraintPart.h:43
void Deactivate()
Deactivate this constraint.
Definition ContactConstraintPart.h:17
bool IsActive() const
Check if constraint is active.
Definition ContactConstraintPart.h:24
void SetTotalLambda(float inLambda)
Override total lagrange multiplier, can be used to set the initial value for warm starting.
Definition ContactConstraintPart.h:30
float mTotalLambda
Definition ContactConstraintPart.h:44
float GetTotalLambda() const
Return lagrange multiplier.
Definition ContactConstraintPart.h:36
Float3 mInvI2_R2xAxis
Definition ContactConstraintPart.h:82
Float3 mR2xAxis
Definition ContactConstraintPart.h:74
Definition ContactConstraintPart.h:66
Definition ContactConstraintPart.h:94
JPH_INLINE bool SolveVelocityConstraint(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inMinLambda, float inMaxLambda)
See: AxisConstraintPart::SolveVelocityConstraint.
Definition ContactConstraintPart.h:214
JPH_INLINE void CalculateConstraintProperties(float inInvMass1, Mat44Arg inInvI1, Vec3Arg inR1PlusU, float inInvMass2, Mat44Arg inInvI2, Vec3Arg inR2, Vec3Arg inWorldSpaceAxis, float inBias=0.0f)
See AxisConstraintPart::CalculateConstraintProperties.
Definition ContactConstraintPart.h:119
JPH_INLINE bool SolveVelocityConstraintApplyLambda(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inTotalLambda)
Part 2 of AxisConstraint::SolveVelocityConstraint: apply new lambda.
Definition ContactConstraintPart.h:205
JPH_INLINE bool SolvePositionConstraint(Body &ioBody1, float inInvMass1, Body &ioBody2, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inC, float inBaumgarte) const
See: AxisConstraintPart::SolvePositionConstraint.
Definition ContactConstraintPart.h:225
JPH_INLINE float SolveVelocityConstraintGetTotalLambda(Vec3Arg inLinearVelocity1, Vec3Arg inAngularVelocity1, Vec3Arg inLinearVelocity2, Vec3Arg inAngularVelocity2, Vec3Arg inWorldSpaceAxis) const
Part 1 of AxisConstraint::SolveVelocityConstraint: get the total lambda.
Definition ContactConstraintPart.h:176
JPH_INLINE bool WarmStart(Vec3 &ioLinearVelocity1, Vec3 &ioAngularVelocity1, Vec3 &ioLinearVelocity2, Vec3 &ioAngularVelocity2, float inInvMass1, float inInvMass2, Vec3Arg inWorldSpaceAxis, float inWarmStartImpulseRatio)
See AxisConstraintPart::WarmStart.
Definition ContactConstraintPart.h:168
Class that holds 3 floats. Used as a storage class. Convert to Vec3 for calculations.
Definition Float3.h:13
Holds a 4x4 matrix of floats, but supports also operations on the 3x3 upper left part of the matrix.
Definition Mat44.h:13
JPH_INLINE Vec3 Multiply3x3(Vec3Arg inV) const
Multiply vector by only 3x3 part of the matrix.
Definition Mat44.inl:384
The Body class only keeps track of state for static bodies, the MotionProperties class keeps the addi...
Definition MotionProperties.h:29
void ApplyAngularVelocityStep(Vec3Arg inAngularVelocity)
Definition MotionProperties.h:229
Vec3 GetLinearVelocity() const
Get world space linear velocity of the center of mass.
Definition MotionProperties.h:43
Vec3 GetAngularVelocity() const
Get world space angular velocity of the center of mass.
Definition MotionProperties.h:52
void ApplyLinearVelocityStep(Vec3Arg inLinearVelocity)
Definition MotionProperties.h:218
Definition Vec3.h:17
JPH_INLINE float Dot(Vec3Arg inV2) const
Dot product.
Definition Vec3.inl:943
JPH_INLINE Vec3 Cross(Vec3Arg inV2) const
Cross product.
Definition Vec3.inl:841
JPH_INLINE bool IsNormalized(float inTolerance=1.0e-6f) const
Test if vector is normalized.
Definition Vec3.inl:1128
JPH_INLINE void StoreFloat3(Float3 *outV) const
Store 3 floats to memory.
Definition Vec3.inl:1153
static JPH_INLINE Vec3 sLoadFloat3Unsafe(const Float3 &inV)
Load 3 floats from memory (reads 32 bits extra which it doesn't use)
Definition Vec3.inl:167
static JPH_INLINE Vec3 sNaN()
Vector with all NaN's.
Definition Vec3.inl:162