RavEngine
Loading...
Searching...
No Matches
ExtConstraintHelper.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_CONSTRAINT_HELPER_H
30#define EXT_CONSTRAINT_HELPER_H
31
32#include "foundation/PxAssert.h"
33#include "foundation/PxTransform.h"
34#include "foundation/PxMat33.h"
35#include "foundation/PxSIMDHelpers.h"
36#include "extensions/PxD6Joint.h"
37#include "ExtJointData.h"
38#include "foundation/PxVecMath.h"
39
40namespace physx
41{
42namespace Ext
43{
44 namespace joint
45 {
46 PX_INLINE void computeJointFrames(PxTransform& cA2w, PxTransform& cB2w, const JointData& data, const PxTransform& bA2w, const PxTransform& bB2w)
47 {
48 PX_ASSERT(bA2w.isValid() && bB2w.isValid());
49
50 cA2w = bA2w.transform(data.c2b[0]);
51 cB2w = bB2w.transform(data.c2b[1]);
52
53 PX_ASSERT(cA2w.isValid() && cB2w.isValid());
54 }
55
56 PX_INLINE void computeDerived(const JointData& data,
57 const PxTransform& bA2w, const PxTransform& bB2w,
58 PxTransform& cA2w, PxTransform& cB2w, PxTransform& cB2cA,
59 bool useShortestPath=true)
60 {
61 computeJointFrames(cA2w, cB2w, data, bA2w, bB2w);
62
63 if(useShortestPath)
64 {
65 if(cA2w.q.dot(cB2w.q)<0.0f) // minimum error quat
66 cB2w.q = -cB2w.q;
67 }
68
69 cB2cA = cA2w.transformInv(cB2w);
70 PX_ASSERT(cB2cA.isValid());
71 }
72
73 PX_INLINE PxVec3 truncateLinear(const PxVec3& in, PxReal tolerance, bool& truncated)
74 {
75 const PxReal m = in.magnitudeSquared();
76 truncated = m>tolerance * tolerance;
77 return truncated ? in * PxRecipSqrt(m) * tolerance : in;
78 }
79
80 PX_INLINE PxQuat truncateAngular(const PxQuat& in, PxReal sinHalfTol, PxReal cosHalfTol, bool& truncated)
81 {
82 truncated = false;
83
84 if(sinHalfTol > 0.9999f) // fixes numerical tolerance issue of projecting because quat is not exactly normalized
85 return in;
86
87 const PxQuat q = in.w>=0.0f ? in : -in;
88
89 const PxVec3 im = q.getImaginaryPart();
90 const PxReal m = im.magnitudeSquared();
91 truncated = m>sinHalfTol*sinHalfTol;
92 if(!truncated)
93 return in;
94
95 const PxVec3 outV = im * sinHalfTol * PxRecipSqrt(m);
96 return PxQuat(outV.x, outV.y, outV.z, cosHalfTol);
97 }
98
99 PX_FORCE_INLINE void projectTransforms(PxTransform& bA2w, PxTransform& bB2w,
100 const PxTransform& cA2w, const PxTransform& cB2w,
101 const PxTransform& cB2cA, const JointData& data, bool projectToA)
102 {
103 PX_ASSERT(cB2cA.isValid());
104
105 // normalization here is unfortunate: long chains of projected constraints can result in
106 // accumulation of error in the quaternion which eventually leaves the quaternion
107 // magnitude outside the validation range. The approach here is slightly overconservative
108 // in that we could just normalize the quaternions which are out of range, but since we
109 // regard projection as an occasional edge case it shouldn't be perf-sensitive, and
110 // this way we maintain the invariant (also maintained by the dynamics integrator) that
111 // body quats are properly normalized up to FP error.
112
113 if(projectToA)
114 {
115 bB2w = cA2w.transform(cB2cA.transform(data.c2b[1].getInverse()));
116 bB2w.q.normalize();
117 }
118 else
119 {
120 bA2w = cB2w.transform(cB2cA.transformInv(data.c2b[0].getInverse()));
121 bA2w.q.normalize();
122 }
123
124 PX_ASSERT(bA2w.isValid());
125 PX_ASSERT(bB2w.isValid());
126 }
127
128 PX_INLINE void computeJacobianAxes(PxVec3 row[3], const PxQuat& qa, const PxQuat& qb)
129 {
130 // Compute jacobian matrix for (qa* qb) [[* means conjugate in this expr]]
131 // d/dt (qa* qb) = 1/2 L(qa*) R(qb) (omega_b - omega_a)
132 // result is L(qa*) R(qb), where L(q) and R(q) are left/right q multiply matrix
133
134 const PxReal wa = qa.w, wb = qb.w;
135 const PxVec3 va(qa.x,qa.y,qa.z), vb(qb.x,qb.y,qb.z);
136
137 const PxVec3 c = vb*wa + va*wb;
138 const PxReal d0 = wa*wb;
139 const PxReal d1 = va.dot(vb);
140 const PxReal d = d0 - d1;
141
142 row[0] = (va * vb.x + vb * va.x + PxVec3(d, c.z, -c.y)) * 0.5f;
143 row[1] = (va * vb.y + vb * va.y + PxVec3(-c.z, d, c.x)) * 0.5f;
144 row[2] = (va * vb.z + vb * va.z + PxVec3(c.y, -c.x, d)) * 0.5f;
145
146 if((d0 + d1) != 0.0f) // check if relative rotation is 180 degrees which can lead to singular matrix
147 return;
148 else
149 {
150 row[0].x += PX_EPS_F32;
151 row[1].y += PX_EPS_F32;
152 row[2].z += PX_EPS_F32;
153 }
154 }
155
156 PX_FORCE_INLINE Px1DConstraint* _linear(const PxVec3& axis, const PxVec3& ra, const PxVec3& rb, PxReal posErr, PxConstraintSolveHint::Enum hint, Px1DConstraint* c)
157 {
158 c->solveHint = PxU16(hint);
159 c->linear0 = axis;
160 c->angular0 = ra.cross(axis);
161 c->linear1 = axis;
162 c->angular1 = rb.cross(axis);
163 c->geometricError = posErr;
164 PX_ASSERT(c->linear0.isFinite());
165 PX_ASSERT(c->linear1.isFinite());
166 PX_ASSERT(c->angular0.isFinite());
167 PX_ASSERT(c->angular1.isFinite());
168 return c;
169 }
170
171 PX_FORCE_INLINE Px1DConstraint* _angular(const PxVec3& axis, PxReal posErr, PxConstraintSolveHint::Enum hint, Px1DConstraint* c)
172 {
173 c->solveHint = PxU16(hint);
174 c->linear0 = PxVec3(0.0f);
175 c->angular0 = axis;
176 c->linear1 = PxVec3(0.0f);
177 c->angular1 = axis;
178 c->geometricError = posErr;
180 return c;
181 }
182
184 {
185 Px1DConstraint* mConstraints;
186 Px1DConstraint* mCurrent;
187 PxVec3 mRa, mRb;
188 PxVec3 mCA2w, mCB2w;
189
190 public:
191 ConstraintHelper(Px1DConstraint* c, const PxVec3& ra, const PxVec3& rb)
192 : mConstraints(c), mCurrent(c), mRa(ra), mRb(rb) {}
193
194 /*PX_NOINLINE*/ ConstraintHelper(Px1DConstraint* c, PxConstraintInvMassScale& invMassScale,
195 PxTransform& cA2w, PxTransform& cB2w, PxVec3p& body0WorldOffset,
196 const JointData& data, const PxTransform& bA2w, const PxTransform& bB2w)
197 : mConstraints(c), mCurrent(c)
198 {
199 using namespace aos;
200
201 V4StoreA(V4LoadA(&data.invMassScale.linear0), &invMassScale.linear0); //invMassScale = data.invMassScale;
202
203 computeJointFrames(cA2w, cB2w, data, bA2w, bB2w);
204
205 const PxVec3 ra = cB2w.p - bA2w.p;
206 body0WorldOffset = ra;
207
208 mRa = ra;
209 mRb = cB2w.p - bB2w.p;
210
211 mCA2w = cA2w.p;
212 mCB2w = cB2w.p;
213 }
214
215 PX_FORCE_INLINE const PxVec3& getRa() const { return mRa; }
216 PX_FORCE_INLINE const PxVec3& getRb() const { return mRb; }
217
218 // hard linear & angular
219 PX_FORCE_INLINE void linearHard(const PxVec3& axis, PxReal posErr)
220 {
221 Px1DConstraint* c = linear(axis, posErr, PxConstraintSolveHint::eEQUALITY);
223 }
224
225 PX_FORCE_INLINE void angularHard(const PxVec3& axis, PxReal posErr)
226 {
227 Px1DConstraint* c = angular(axis, posErr, PxConstraintSolveHint::eEQUALITY);
229 }
230
231 // limited linear & angular
232 PX_FORCE_INLINE void linearLimit(const PxVec3& axis, PxReal ordinate, PxReal limitValue, const PxJointLimitParameters& limit)
233 {
234 const PxReal pad = limit.isSoft() ? 0.0f : limit.contactDistance_deprecated;
235
236 if(ordinate + pad > limitValue)
237 addLimit(linear(axis, limitValue - ordinate, PxConstraintSolveHint::eNONE), limit);
238 }
239
240 PX_FORCE_INLINE void angularLimit(const PxVec3& axis, PxReal ordinate, PxReal limitValue, PxReal pad, const PxJointLimitParameters& limit)
241 {
242 if(limit.isSoft())
243 pad = 0.0f;
244
245 if(ordinate + pad > limitValue)
246 addLimit(angular(axis, limitValue - ordinate, PxConstraintSolveHint::eNONE), limit);
247 }
248
249 PX_FORCE_INLINE void angularLimit(const PxVec3& axis, PxReal error, const PxJointLimitParameters& limit)
250 {
251 addLimit(angular(axis, error, PxConstraintSolveHint::eNONE), limit);
252 }
253
254 PX_FORCE_INLINE void anglePair(PxReal angle, PxReal lower, PxReal upper, PxReal pad, const PxVec3& axis, const PxJointLimitParameters& limit)
255 {
256 PX_ASSERT(lower<upper);
257 if(limit.isSoft())
258 pad = 0;
259
260 if(angle < lower+pad)
261 angularLimit(-axis, -(lower - angle), limit);
262 if(angle > upper-pad)
263 angularLimit(axis, (upper - angle), limit);
264 }
265
266 // driven linear & angular
267
268 PX_FORCE_INLINE void linear(const PxVec3& axis, PxReal velTarget, PxReal error, const PxD6JointDrive& drive)
269 {
270 addDrive(linear(axis, error, PxConstraintSolveHint::eNONE), velTarget, drive);
271 }
272
273 PX_FORCE_INLINE void angular(const PxVec3& axis, PxReal velTarget, PxReal error, const PxD6JointDrive& drive, PxConstraintSolveHint::Enum hint = PxConstraintSolveHint::eNONE)
274 {
275 addDrive(angular(axis, error, hint), velTarget, drive);
276 }
277
278 PX_FORCE_INLINE PxU32 getCount() const { return PxU32(mCurrent - mConstraints); }
279
280 void prepareLockedAxes(const PxQuat& qA, const PxQuat& qB, const PxVec3& cB2cAp, PxU32 lin, PxU32 ang, PxVec3& raOut, PxVec3& rbOut)
281 {
282 Px1DConstraint* current = mCurrent;
283
284 PxVec3 errorVector(0.0f);
285
286 PxVec3 ra = mRa;
287 PxVec3 rb = mRb;
288 if(lin)
289 {
290 const PxMat33Padded axes(qA);
291
292 if(lin&1) errorVector -= axes.column0 * cB2cAp.x;
293 if(lin&2) errorVector -= axes.column1 * cB2cAp.y;
294 if(lin&4) errorVector -= axes.column2 * cB2cAp.z;
295
296 ra += errorVector;
297
298 if(lin&1) _linear(axes.column0, ra, rb, -cB2cAp.x, PxConstraintSolveHint::eEQUALITY, current++);
299 if(lin&2) _linear(axes.column1, ra, rb, -cB2cAp.y, PxConstraintSolveHint::eEQUALITY, current++);
300 if(lin&4) _linear(axes.column2, ra, rb, -cB2cAp.z, PxConstraintSolveHint::eEQUALITY, current++);
301 }
302
303 if (ang)
304 {
305 const PxQuat qB2qA = qA.getConjugate() * qB;
306
307 PxVec3 row[3];
308 computeJacobianAxes(row, qA, qB);
309 if (ang & 1) _angular(row[0], -qB2qA.x, PxConstraintSolveHint::eEQUALITY, current++);
310 if (ang & 2) _angular(row[1], -qB2qA.y, PxConstraintSolveHint::eEQUALITY, current++);
311 if (ang & 4) _angular(row[2], -qB2qA.z, PxConstraintSolveHint::eEQUALITY, current++);
312 }
313
314 raOut = ra;
315 rbOut = rb;
316
317 for(Px1DConstraint* front = mCurrent; front < current; front++)
318 front->flags |= Px1DConstraintFlag::eOUTPUT_FORCE;
319
320 mCurrent = current;
321 }
322
323 PX_FORCE_INLINE Px1DConstraint* getConstraintRow()
324 {
325 return mCurrent++;
326 }
327
328 private:
329 PX_FORCE_INLINE Px1DConstraint* linear(const PxVec3& axis, PxReal posErr, PxConstraintSolveHint::Enum hint)
330 {
331 return _linear(axis, mRa, mRb, posErr, hint, mCurrent++);
332 }
333
334 PX_FORCE_INLINE Px1DConstraint* angular(const PxVec3& axis, PxReal posErr, PxConstraintSolveHint::Enum hint)
335 {
336 return _angular(axis, posErr, hint, mCurrent++);
337 }
338
339 void addLimit(Px1DConstraint* c, const PxJointLimitParameters& limit)
340 {
341 PxU16 flags = PxU16(c->flags | Px1DConstraintFlag::eOUTPUT_FORCE);
342
343 if(limit.isSoft())
344 {
346 c->mods.spring.stiffness = limit.stiffness;
347 c->mods.spring.damping = limit.damping;
348 }
349 else
350 {
352 c->mods.bounce.restitution = limit.restitution;
353 c->mods.bounce.velocityThreshold = limit.bounceThreshold;
354 if(c->geometricError>0.0f)
356 if(limit.restitution>0.0f)
358 }
359
360 c->flags = flags;
361 c->minImpulse = 0.0f;
362 }
363
364 void addDrive(Px1DConstraint* c, PxReal velTarget, const PxD6JointDrive& drive)
365 {
366 c->velocityTarget = velTarget;
367
371 c->flags = flags;
372 c->mods.spring.stiffness = drive.stiffness;
373 c->mods.spring.damping = drive.damping;
374
375 c->minImpulse = -drive.forceLimit;
376 c->maxImpulse = drive.forceLimit;
377
378 PX_ASSERT(c->linear0.isFinite());
379 PX_ASSERT(c->angular0.isFinite());
380 }
381 };
382 }
383} // namespace
384
385}
386
387#endif
Definition ExtConstraintHelper.h:184
parameters for configuring the drive model of a PxD6Joint
Definition PxD6Joint.h:145
PxReal forceLimit
the force limit of the drive - may be an impulse or a force depending on PxConstraintFlag::eDRIVE_LIM...
Definition PxD6Joint.h:154
PxD6JointDriveFlags flags
the joint drive flags
Definition PxD6Joint.h:155
Describes the parameters for a joint limit.
Definition PxJointLimit.h:52
PxReal bounceThreshold
Definition PxJointLimit.h:84
PxReal restitution
Controls the amount of bounce when the joint hits a limit.
Definition PxJointLimit.h:79
PxReal damping
if spring is greater than zero, this is the damping of the limit spring
Definition PxJointLimit.h:100
PxReal stiffness
if greater than zero, the limit is soft, i.e. a spring pulls the joint back to the limit
Definition PxJointLimit.h:92
PxReal contactDistance_deprecated
The distance inside the limit value at which the limit will be considered to be active by the solver....
Definition PxJointLimit.h:119
A padded version of PxMat33, to safely load its data using SIMD.
Definition PxSIMDHelpers.h:41
This is a quaternion class. For more information on quaternion mathematics consult a mathematics sour...
Definition PxQuat.h:50
float x
Definition PxQuat.h:395
PxReal stiffness
the spring strength of the drive: that is, the force proportional to the position error
Definition PxJoint.h:394
PxReal damping
the damping strength of the drive: that is, the force proportional to the velocity error
Definition PxJoint.h:395
class representing a rigid euclidean transform as a quaternion and a vector
Definition PxTransform.h:49
A padded version of PxVec3, to safely load its data using SIMD.
Definition PxVec3.h:392
3 Element vector class.
Definition PxVec3.h:50
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
#define PX_INLINE
Definition PxPreprocessor.h:320
GLM_FUNC_DECL genType::row_type row(genType const &m, length_t index)
Definition matrix_access.inl:23
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_CUDA_CALLABLE PX_FORCE_INLINE float PxRecipSqrt(float a)
reciprocal square root.
Definition PxMath.h:158
Definition ExtJointData.h:39
@ eOUTPUT_FORCE
whether to accumulate the force value from this constraint in the force total that is reported for th...
Definition PxConstraintDesc.h:69
@ eANGULAR_CONSTRAINT
whether this is an angular or linear constraint
Definition PxConstraintDesc.h:71
@ eRESTITUTION
whether the restitution model should be applied to generate the target velocity. Mutually exclusive w...
Definition PxConstraintDesc.h:67
@ eKEEPBIAS
whether to keep the error term when solving for velocity. Ignored if restitution generates bounce,...
Definition PxConstraintDesc.h:68
@ eACCELERATION_SPRING
whether the constraint is a force or acceleration spring. Only valid if eSPRING is set.
Definition PxConstraintDesc.h:66
@ eSPRING
whether the constraint is a spring. Mutually exclusive with eRESTITUTION. If set, eKEEPBIAS is ignore...
Definition PxConstraintDesc.h:65
@ eHAS_DRIVE_LIMIT
whether the constraint has a drive force limit (which will be scaled by dt unless PxConstraintFlag::e...
Definition PxConstraintDesc.h:70
A one-dimensional constraint.
Definition PxConstraintDesc.h:134
Struct for specifying mass scaling for a pair of rigids.
Definition PxConstraintDesc.h:184
PxReal linear0
multiplier for inverse mass of body0
Definition PxConstraintDesc.h:192
Enum
Definition PxConstraintDesc.h:85
@ eNONE
no special properties
Definition PxConstraintDesc.h:86
@ eINEQUALITY
inequality constraints with (0, PX_MAX_FLT) force limits
Definition PxConstraintDesc.h:94
@ eEQUALITY
equality constraints with no force limit and no velocity target
Definition PxConstraintDesc.h:93
@ eACCELERATION
drive spring is for the acceleration at the joint (rather than the force)
Definition PxD6Joint.h:133