RavEngine
Loading...
Searching...
No Matches
ExtInertiaTensor.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef EXT_INERTIA_TENSOR_H
30#define EXT_INERTIA_TENSOR_H
31
32#include "foundation/PxMat33.h"
33#include "foundation/PxMathUtils.h"
34
35namespace physx
36{
37namespace Ext
38{
40 {
41 public:
42 InertiaTensorComputer(bool initTozero = true);
43 InertiaTensorComputer(const PxMat33& inertia, const PxVec3& com, PxReal mass);
45
46 PX_INLINE void zero(); //sets to zero mass
47 PX_INLINE void setDiagonal(PxReal mass, const PxVec3& diagonal); //sets as a diagonal tensor
48 PX_INLINE void rotate(const PxMat33& rot); //rotates the mass
49 void translate(const PxVec3& t); //translates the mass
50 PX_INLINE void transform(const PxTransform& transform); //transforms the mass
51 PX_INLINE void scaleDensity(PxReal densityScale); //scales by a density factor
52 PX_INLINE void add(const InertiaTensorComputer& it); //adds a mass
53 PX_INLINE void center(); //recenters inertia around center of mass
54
55 void setBox(const PxVec3& halfWidths); //sets as an axis aligned box
56 PX_INLINE void setBox(const PxVec3& halfWidths, const PxTransform* pose); //sets as an oriented box
57
58 void setSphere(PxReal radius);
59 PX_INLINE void setSphere(PxReal radius, const PxTransform* pose);
60
61 void setCylinder(int dir, PxReal r, PxReal l);
62 PX_INLINE void setCylinder(int dir, PxReal r, PxReal l, const PxTransform* pose);
63
64 void setCapsule(int dir, PxReal r, PxReal l);
65 PX_INLINE void setCapsule(int dir, PxReal r, PxReal l, const PxTransform* pose);
66
67 void setEllipsoid(PxReal rx, PxReal ry, PxReal rz);
68 PX_INLINE void setEllipsoid(PxReal rx, PxReal ry, PxReal rz, const PxTransform* pose);
69
70 PX_INLINE PxVec3 getCenterOfMass() const { return mG; }
71 PX_INLINE PxReal getMass() const { return mMass; }
72 PX_INLINE PxMat33 getInertia() const { return mI; }
73
74 private:
75 PxMat33 mI;
76 PxVec3 mG;
77 PxReal mMass;
78 };
79
80 //--------------------------------------------------------------
81 //
82 // Helper routines
83 //
84 //--------------------------------------------------------------
85
86 // Special version allowing 2D quads
87 PX_INLINE PxReal volume(const PxVec3& extents)
88 {
89 PxReal v = 1.0f;
90 if(extents.x != 0.0f) v*=extents.x;
91 if(extents.y != 0.0f) v*=extents.y;
92 if(extents.z != 0.0f) v*=extents.z;
93 return v;
94 }
95
96 // Sphere
97 PX_INLINE PxReal computeSphereRatio(PxReal radius) { return (4.0f/3.0f) * PxPi * radius * radius * radius; }
98 PxReal computeSphereMass(PxReal radius, PxReal density) { return density * computeSphereRatio(radius); }
99 PxReal computeSphereDensity(PxReal radius, PxReal mass) { return mass / computeSphereRatio(radius); }
100
101 // Box
102 PX_INLINE PxReal computeBoxRatio(const PxVec3& extents) { return volume(extents); }
103 PxReal computeBoxMass(const PxVec3& extents, PxReal density) { return density * computeBoxRatio(extents); }
104 PxReal computeBoxDensity(const PxVec3& extents, PxReal mass) { return mass / computeBoxRatio(extents); }
105
106 // Ellipsoid
107 PX_INLINE PxReal computeEllipsoidRatio(const PxVec3& extents) { return (4.0f/3.0f) * PxPi * volume(extents); }
108 PxReal computeEllipsoidMass(const PxVec3& extents, PxReal density) { return density * computeEllipsoidRatio(extents); }
109 PxReal computeEllipsoidDensity(const PxVec3& extents, PxReal mass) { return mass / computeEllipsoidRatio(extents); }
110
111 // Cylinder
112 PX_INLINE PxReal computeCylinderRatio(PxReal r, PxReal l) { return PxPi * r * r * (2.0f*l); }
113 PxReal computeCylinderMass(PxReal r, PxReal l, PxReal density) { return density * computeCylinderRatio(r, l); }
114 PxReal computeCylinderDensity(PxReal r, PxReal l, PxReal mass) { return mass / computeCylinderRatio(r, l); }
115
116 // Capsule
117 PX_INLINE PxReal computeCapsuleRatio(PxReal r, PxReal l) { return computeSphereRatio(r) + computeCylinderRatio(r, l);}
118 PxReal computeCapsuleMass(PxReal r, PxReal l, PxReal density) { return density * computeCapsuleRatio(r, l); }
119 PxReal computeCapsuleDensity(PxReal r, PxReal l, PxReal mass) { return mass / computeCapsuleRatio(r, l); }
120
121 // Cone
122 PX_INLINE PxReal computeConeRatio(PxReal r, PxReal l) { return PxPi * r * r * PxAbs(l)/3.0f; }
123 PxReal computeConeMass(PxReal r, PxReal l, PxReal density) { return density * computeConeRatio(r, l); }
124 PxReal computeConeDensity(PxReal r, PxReal l, PxReal mass) { return mass / computeConeRatio(r, l); }
125
126 void computeBoxInertiaTensor(PxVec3& inertia, PxReal mass, PxReal xlength, PxReal ylength, PxReal zlength);
127 void computeSphereInertiaTensor(PxVec3& inertia, PxReal mass, PxReal radius, bool hollow);
128 bool jacobiTransform(PxI32 n, PxF64 a[], PxF64 w[]);
129 bool diagonalizeInertiaTensor(const PxMat33& denseInertia, PxVec3& diagonalInertia, PxMat33& rotation);
130
131} // namespace Ext
132
133void Ext::computeBoxInertiaTensor(PxVec3& inertia, PxReal mass, PxReal xlength, PxReal ylength, PxReal zlength)
134{
135 //to model a hollow block, one would have to multiply coeff by up to two.
136 const PxReal coeff = mass/12;
137 inertia.x = coeff * (ylength*ylength + zlength*zlength);
138 inertia.y = coeff * (xlength*xlength + zlength*zlength);
139 inertia.z = coeff * (xlength*xlength + ylength*ylength);
140
141 PX_ASSERT(inertia.x != 0.0f);
142 PX_ASSERT(inertia.y != 0.0f);
143 PX_ASSERT(inertia.z != 0.0f);
144 PX_ASSERT(inertia.isFinite());
145}
146
147void Ext::computeSphereInertiaTensor(PxVec3& inertia, PxReal mass, PxReal radius, bool hollow)
148{
149 inertia.x = mass * radius * radius;
150 if (hollow)
151 inertia.x *= PxReal(2 / 3.0);
152 else
153 inertia.x *= PxReal(2 / 5.0);
154
155 inertia.z = inertia.y = inertia.x;
156 PX_ASSERT(inertia.isFinite());
157}
158
159//--------------------------------------------------------------
160//
161// InertiaTensorComputer implementation
162//
163//--------------------------------------------------------------
164
165Ext::InertiaTensorComputer::InertiaTensorComputer(bool initTozero)
166{
167 if (initTozero)
168 zero();
169}
170
171Ext::InertiaTensorComputer::InertiaTensorComputer(const PxMat33& inertia, const PxVec3& com, PxReal mass) :
172 mI(inertia),
173 mG(com),
174 mMass(mass)
175{
176}
177
178
179Ext::InertiaTensorComputer::~InertiaTensorComputer()
180{
181}
182
183PX_INLINE void Ext::InertiaTensorComputer::zero()
184{
185 mMass = 0.0f;
186 mI = PxMat33(PxZero);
187 mG = PxVec3(0);
188}
189
190PX_INLINE void Ext::InertiaTensorComputer::setDiagonal(PxReal mass, const PxVec3& diag)
191{
192 mMass = mass;
193 mI = PxMat33::createDiagonal(diag);
194 mG = PxVec3(0);
195 PX_ASSERT(mI.column0.isFinite() && mI.column1.isFinite() && mI.column2.isFinite());
196 PX_ASSERT(PxIsFinite(mMass));
197}
198
199void Ext::InertiaTensorComputer::setBox(const PxVec3& halfWidths)
200{
201 // Setup inertia tensor for a cube with unit density
202 const PxReal mass = 8.0f * computeBoxRatio(halfWidths);
203 const PxReal s =(1.0f/3.0f) * mass;
204
205 const PxReal x = halfWidths.x*halfWidths.x;
206 const PxReal y = halfWidths.y*halfWidths.y;
207 const PxReal z = halfWidths.z*halfWidths.z;
208
209 setDiagonal(mass, PxVec3(y+z, z+x, x+y) * s);
210}
211
212PX_INLINE void Ext::InertiaTensorComputer::rotate(const PxMat33& rot)
213{
214 //well known inertia tensor rotation expression is: RIR' -- this could be optimized due to symmetry, see code to do that in Body::updateGlobalInverseInertia
215 mI = rot * mI * rot.getTranspose();
216 PX_ASSERT(mI.column0.isFinite() && mI.column1.isFinite() && mI.column2.isFinite());
217 //com also needs to be rotated
218 mG = rot * mG;
219 PX_ASSERT(mG.isFinite());
220}
221
222void Ext::InertiaTensorComputer::translate(const PxVec3& t)
223{
224 if (!t.isZero()) //its common for this to be zero
225 {
226 PxMat33 t1, t2;
227
228 t1.column0 = PxVec3(0, mG.z, -mG.y);
229 t1.column1 = PxVec3(-mG.z, 0, mG.x);
230 t1.column2 = PxVec3(mG.y, -mG.x, 0);
231
232 PxVec3 sum = mG + t;
233 if (sum.isZero())
234 {
235 mI += (t1 * t1)*mMass;
236 }
237 else
238 {
239 t2.column0 = PxVec3(0, sum.z, -sum.y);
240 t2.column1 = PxVec3(-sum.z, 0, sum.x);
241 t2.column2 = PxVec3(sum.y, -sum.x, 0);
242 mI += (t1 * t1 - t2 * t2)*mMass;
243 }
244
245 //move center of mass
246 mG += t;
247
248 PX_ASSERT(mI.column0.isFinite() && mI.column1.isFinite() && mI.column2.isFinite());
249 PX_ASSERT(mG.isFinite());
250 }
251}
252
253PX_INLINE void Ext::InertiaTensorComputer::transform(const PxTransform& transform)
254{
255 rotate(PxMat33(transform.q));
257}
258
259PX_INLINE void Ext::InertiaTensorComputer::setBox(const PxVec3& halfWidths, const PxTransform* pose)
260{
261 setBox(halfWidths);
262 if (pose)
263 transform(*pose);
264}
265
266PX_INLINE void Ext::InertiaTensorComputer::scaleDensity(PxReal densityScale)
267{
268 mI *= densityScale;
269 mMass *= densityScale;
270 PX_ASSERT(mI.column0.isFinite() && mI.column1.isFinite() && mI.column2.isFinite());
271 PX_ASSERT(PxIsFinite(mMass));
272}
273
274PX_INLINE void Ext::InertiaTensorComputer::add(const InertiaTensorComputer& it)
275{
276 const PxReal TotalMass = mMass + it.mMass;
277 mG = (mG * mMass + it.mG * it.mMass) / TotalMass;
278
279 mMass = TotalMass;
280 mI += it.mI;
281 PX_ASSERT(mI.column0.isFinite() && mI.column1.isFinite() && mI.column2.isFinite());
282 PX_ASSERT(mG.isFinite());
283 PX_ASSERT(PxIsFinite(mMass));
284}
285
286PX_INLINE void Ext::InertiaTensorComputer::center()
287{
288 PxVec3 center = -mG;
289 translate(center);
290}
291
292void Ext::InertiaTensorComputer::setSphere(PxReal radius)
293{
294 // Compute mass of the sphere
295 const PxReal m = computeSphereRatio(radius);
296 // Compute moment of inertia
297 const PxReal s = m * radius * radius * (2.0f/5.0f);
298 setDiagonal(m,PxVec3(s,s,s));
299}
300
301PX_INLINE void Ext::InertiaTensorComputer::setSphere(PxReal radius, const PxTransform* pose)
302{
303 setSphere(radius);
304 if (pose)
305 transform(*pose);
306}
307
308void Ext::InertiaTensorComputer::setCylinder(int dir, PxReal r, PxReal l)
309{
310 // Compute mass of cylinder
311 const PxReal m = computeCylinderRatio(r, l);
312
313 const PxReal i1 = r*r*m/2.0f;
314 const PxReal i2 = (3.0f*r*r+4.0f*l*l)*m/12.0f;
315
316 switch(dir)
317 {
318 case 0: setDiagonal(m,PxVec3(i1,i2,i2)); break;
319 case 1: setDiagonal(m,PxVec3(i2,i1,i2)); break;
320 default: setDiagonal(m,PxVec3(i2,i2,i1)); break;
321 }
322}
323
324PX_INLINE void Ext::InertiaTensorComputer::setCylinder(int dir, PxReal r, PxReal l, const PxTransform* pose)
325{
326 setCylinder(dir, r, l);
327 if (pose)
328 transform(*pose);
329}
330
331void Ext::InertiaTensorComputer::setCapsule(int dir, PxReal r, PxReal l)
332{
333 // Compute mass of capsule
334 const PxReal m = computeCapsuleRatio(r, l);
335
336 const PxReal t = PxPi * r * r;
337 const PxReal i1 = t * ((r*r*r * 8.0f/15.0f) + (l*r*r));
338 const PxReal i2 = t * ((r*r*r * 8.0f/15.0f) + (l*r*r * 3.0f/2.0f) + (l*l*r * 4.0f/3.0f) + (l*l*l * 2.0f/3.0f));
339
340 switch(dir)
341 {
342 case 0: setDiagonal(m,PxVec3(i1,i2,i2)); break;
343 case 1: setDiagonal(m,PxVec3(i2,i1,i2)); break;
344 default: setDiagonal(m,PxVec3(i2,i2,i1)); break;
345 }
346}
347
348PX_INLINE void Ext::InertiaTensorComputer::setCapsule(int dir, PxReal r, PxReal l, const PxTransform* pose)
349{
350 setCapsule(dir, r, l);
351 if (pose)
352 transform(*pose);
353}
354
355void Ext::InertiaTensorComputer::setEllipsoid(PxReal rx, PxReal ry, PxReal rz)
356{
357 // Compute mass of ellipsoid
358 const PxReal m = computeEllipsoidRatio(PxVec3(rx, ry, rz));
359
360 // Compute moment of inertia
361 const PxReal s = m * (2.0f/5.0f);
362
363 // Setup inertia tensor for an ellipsoid centered at the origin
364 setDiagonal(m,PxVec3(ry*rz,rz*rx,rx*ry)*s);
365}
366
367PX_INLINE void Ext::InertiaTensorComputer::setEllipsoid(PxReal rx, PxReal ry, PxReal rz, const PxTransform* pose)
368{
369 setEllipsoid(rx,ry,rz);
370 if (pose)
371 transform(*pose);
372}
373
374}
375
376#endif
Definition ExtInertiaTensor.h:40
PX_CUDA_CALLABLE static PX_INLINE const PxMat33T createDiagonal(const PxVec3T< float > &d)
Construct from diagonal, off-diagonals are zero.
Definition PxMat33.h:186
3x3 matrix class
Definition PxMat33.h:91
class representing a rigid euclidean transform as a quaternion and a vector
Definition PxTransform.h:49
3 Element vector class.
Definition PxVec3.h:50
GLM_FUNC_DECL mat< 4, 4, T, Q > translate(mat< 4, 4, T, Q > const &m, vec< 3, T, Q > const &v)
Definition matrix_transform.inl:10
#define PX_INLINE
Definition PxPreprocessor.h:320
transform(pattern)
Definition docopt.py:72
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_INLINE void rotate(const Gu::Box &src, const PxMat34 &mtx, Gu::Box &obb)
recomputes the OBB after an arbitrary transform by a 4x4 matrix.
Definition GuBoxConversion.h:100
PX_CUDA_CALLABLE PX_FORCE_INLINE float PxAbs(float a)
abs returns the absolute value of its argument.
Definition PxMath.h:109
PX_CUDA_CALLABLE PX_FORCE_INLINE bool PxIsFinite(float f)
returns true if the passed number is a finite floating point number as opposed to INF,...
Definition PxMath.h:326