Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qphysicscommands.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
9#include "PxPhysicsAPI.h"
10
11#include <QtGui/qquaternion.h>
12
14
15static bool isKinematicBody(physx::PxRigidDynamic &body)
16{
17 return static_cast<bool>(body.getRigidBodyFlags() & physx::PxRigidBodyFlag::eKINEMATIC);
18}
19
20// A body with its simulation disabled has no simulation object behind it, and the PhysX
21// functions that accumulate forces and impulses dereference that object without checking, so
22// they must not be called for such a body. Forces on a body that is not being simulated would
23// have no effect anyway.
24static bool isSimulationDisabled(physx::PxRigidBody &body)
25{
26 return static_cast<bool>(body.getActorFlags() & physx::PxActorFlag::eDISABLE_SIMULATION);
27}
28
29static void resolveCCDFlags(physx::PxRigidBody &body, QDynamicRigidBody::CCDType ccd,
30 bool isKinematic, bool worldEnableCCD)
31{
32 switch (ccd) {
33 case QDynamicRigidBody::CCDType::SweepBasedCCD: {
34 // Kinematic bodies only support speculative CCD
35 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, !isKinematic); // Sweep-based
36 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, isKinematic);
37 break;
38 }
39
40 case QDynamicRigidBody::CCDType::SpeculativeCCD: {
41 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, true);
42 break;
43 }
44
45 case QDynamicRigidBody::CCDType::None: {
46 if (worldEnableCCD) {
47 // Kinematic bodies only support speculative CCD
48 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, !isKinematic); // Sweep-based
49 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, isKinematic);
50 }
51 break;
52 }
53 }
54}
55
57 = default;
58
63
65 = default;
66
67void QPhysicsCommandApplyCentralForce::execute(const QDynamicRigidBody &rigidBody,
68 physx::PxRigidDynamic &body)
69{
70 Q_UNUSED(rigidBody)
71 if (isKinematicBody(body) || isSimulationDisabled(body))
72 return;
73 body.addForce(QPhysicsUtils::toPhysXType(force));
74}
75
77 const QVector3D &inPosition)
79{
80}
81
83 = default;
84
85void QPhysicsCommandApplyForce::execute(const QDynamicRigidBody &rigidBody,
86 physx::PxRigidDynamic &body)
87{
88 Q_UNUSED(rigidBody)
89 if (isKinematicBody(body) || isSimulationDisabled(body))
90 return;
91 physx::PxRigidBodyExt::addForceAtPos(body, QPhysicsUtils::toPhysXType(force),
92 QPhysicsUtils::toPhysXType(position));
93}
94
99
101 = default;
102
103void QPhysicsCommandApplyTorque::execute(const QDynamicRigidBody &rigidBody,
104 physx::PxRigidDynamic &body)
105{
106 Q_UNUSED(rigidBody)
107 if (isKinematicBody(body) || isSimulationDisabled(body))
108 return;
109 body.addTorque(QPhysicsUtils::toPhysXType(torque));
110}
111
116
118 = default;
119
120void QPhysicsCommandApplyCentralImpulse::execute(const QDynamicRigidBody &rigidBody,
121 physx::PxRigidDynamic &body)
122{
123 Q_UNUSED(rigidBody)
124 if (isKinematicBody(body) || isSimulationDisabled(body))
125 return;
126 body.addForce(QPhysicsUtils::toPhysXType(impulse), physx::PxForceMode::eIMPULSE);
127}
128
130 const QVector3D &inPosition)
132{
133}
134
136 = default;
137
138void QPhysicsCommandApplyImpulse::execute(const QDynamicRigidBody &rigidBody,
139 physx::PxRigidDynamic &body)
140{
141 Q_UNUSED(rigidBody)
142 if (isKinematicBody(body) || isSimulationDisabled(body))
143 return;
144 physx::PxRigidBodyExt::addForceAtPos(body, QPhysicsUtils::toPhysXType(impulse),
145 QPhysicsUtils::toPhysXType(position),
146 physx::PxForceMode::eIMPULSE);
147}
148
153
155 = default;
156
157void QPhysicsCommandApplyTorqueImpulse::execute(const QDynamicRigidBody &rigidBody,
158 physx::PxRigidDynamic &body)
159{
160 Q_UNUSED(rigidBody)
161 if (isKinematicBody(body) || isSimulationDisabled(body))
162 return;
163
164 body.addTorque(QPhysicsUtils::toPhysXType(impulse), physx::PxForceMode::eIMPULSE);
165}
166
172
174 = default;
175
176void QPhysicsCommandSetAngularVelocity::execute(const QDynamicRigidBody &rigidBody,
177 physx::PxRigidDynamic &body)
178{
179 Q_UNUSED(rigidBody)
180 body.setAngularVelocity(QPhysicsUtils::toPhysXType(angularVelocity));
181}
182
188
190 = default;
191
192void QPhysicsCommandSetLinearVelocity::execute(const QDynamicRigidBody &rigidBody,
193 physx::PxRigidDynamic &body)
194{
195 Q_UNUSED(rigidBody)
196 body.setLinearVelocity(QPhysicsUtils::toPhysXType(linearVelocity));
197}
198
200
202 = default;
203
204void QPhysicsCommandSetMass::execute(const QDynamicRigidBody &rigidBody, physx::PxRigidDynamic &body)
205{
206 if (rigidBody.hasStaticShapes()) {
207 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
208 "ignoring.";
209 return;
210 }
211
212 physx::PxRigidBodyExt::setMassAndUpdateInertia(body, mass);
213}
214
215void QPhysicsCommandSetMassAndInertiaTensor::execute(const QDynamicRigidBody &rigidBody,
216 physx::PxRigidDynamic &body)
217{
218 if (rigidBody.hasStaticShapes()) {
219 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
220 "ignoring.";
221 return;
222 }
223
224 body.setMass(mass);
225 body.setCMassLocalPose(
226 physx::PxTransform(QPhysicsUtils::toPhysXType(rigidBody.centerOfMassPosition()),
227 QPhysicsUtils::toPhysXType(rigidBody.centerOfMassRotation())));
228 body.setMassSpaceInertiaTensor(QPhysicsUtils::toPhysXType(inertia));
229}
230
232 float inMass, const QMatrix3x3 &inInertia)
233 : QPhysicsCommand(), mass(inMass), inertia(inInertia)
234{
235}
236
238 = default;
239
240void QPhysicsCommandSetMassAndInertiaMatrix::execute(const QDynamicRigidBody &rigidBody,
241 physx::PxRigidDynamic &body)
242{
243 if (rigidBody.hasStaticShapes()) {
244 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
245 "ignoring.";
246 return;
247 }
248
249 physx::PxQuat massFrame;
250 physx::PxVec3 diagTensor = physx::PxDiagonalize(QPhysicsUtils::toPhysXType(inertia), massFrame);
251 if (!QPhysicsUtils::isFinite(diagTensor) || diagTensor.x <= 0.0f || diagTensor.y <= 0.0f
252 || diagTensor.z <= 0.0f) {
253 qWarning() << "Invalid inertiaMatrix, does not diagonalize to a positive-definite "
254 "tensor, ignoring.";
255 return;
256 }
257
258 body.setCMassLocalPose(physx::PxTransform(
259 QPhysicsUtils::toPhysXType(rigidBody.centerOfMassPosition()), massFrame));
260 body.setMass(mass);
261 body.setMassSpaceInertiaTensor(diagTensor);
262}
263
265 : QPhysicsCommand(), density(inDensity)
266{
267}
268
270 = default;
271
272void QPhysicsCommandSetDensity::execute(const QDynamicRigidBody &rigidBody,
273 physx::PxRigidDynamic &body)
274{
275 if (rigidBody.hasStaticShapes()) {
276 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
277 "ignoring.";
278 return;
279 }
280
281 physx::PxRigidBodyExt::updateMassAndInertia(body, density);
282}
283
285 bool worldEnableCCD)
286 : QPhysicsCommand(), isKinematic(inIsKinematic), worldEnableCCD(worldEnableCCD)
287{
288}
289
291 = default;
292
293void QPhysicsCommandSetIsKinematic::execute(const QDynamicRigidBody &rigidBody,
294 physx::PxRigidDynamic &body)
295{
296 if (rigidBody.hasStaticShapes() && !isKinematic) {
297 qWarning() << "Cannot make a body containing trimesh/heightfield/plane non-kinematic, "
298 "ignoring.";
299 return;
300 }
301
302 // Clear CCD before flipping kinematic mode: PhysX rejects sweep-based CCD on
303 // kinematic bodies, so leaving a stale CCD flag set while eKINEMATIC changes
304 // would trigger a spurious warning regardless of transition direction.
305 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, false); // Sweep-based
306 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, false);
307 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, isKinematic);
308
309 // Sync CCD flags directly since changing kinematic mode alters supported CCD types
310 resolveCCDFlags(body, rigidBody.ccd(), isKinematic, worldEnableCCD);
311}
312
313QPhysicsCommandSetCCD::QPhysicsCommandSetCCD(QDynamicRigidBody::CCDType ccdType,
314 bool worldEnableCCD)
315 : QPhysicsCommand(), ccdType(ccdType), worldEnableCCD(worldEnableCCD)
316{
317}
318
320
321void QPhysicsCommandSetCCD::execute(const QDynamicRigidBody &rigidBody, physx::PxRigidDynamic &body)
322{
323 // Clear both flags first so the writes below can never collide with a stale
324 // flag from the previous ccd mode (PhysX rejects raising eENABLE_CCD while
325 // eENABLE_SPECULATIVE_CCD, or vice versa, is still set).
326 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, false); // Sweep-based
327 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, false);
328
329 resolveCCDFlags(body, ccdType, rigidBody.isKinematic(), worldEnableCCD);
330}
331
333 : QPhysicsCommand(), gravityEnabled(inGravityEnabled)
334{
335}
336
338 = default;
339
340void QPhysicsCommandSetGravityEnabled::execute(const QDynamicRigidBody &rigidBody,
341 physx::PxRigidDynamic &body)
342{
343 Q_UNUSED(rigidBody)
344 body.setActorFlag(physx::PxActorFlag::eDISABLE_GRAVITY, !gravityEnabled);
345}
346
347QPhysicsCommandReset::QPhysicsCommandReset(QVector3D inPosition, QVector3D inEulerRotation)
349{
350}
351
353 = default;
354
355void QPhysicsCommandReset::execute(const QDynamicRigidBody &rigidBody, physx::PxRigidDynamic &body)
356{
357 Q_UNUSED(rigidBody)
358 body.setLinearVelocity(physx::PxVec3(0, 0, 0));
359 body.setAngularVelocity(physx::PxVec3(0, 0, 0));
360
361 auto *parentNode = rigidBody.parentNode();
362 QVector3D scenePosition = parentNode ? parentNode->mapPositionToScene(position) : position;
363 // TODO: rotation also needs to be mapped
364
365 body.setGlobalPose(physx::PxTransform(
366 QPhysicsUtils::toPhysXType(scenePosition),
367 QPhysicsUtils::toPhysXType(QQuaternion::fromEulerAngles(eulerRotation))));
368}
369
371 float inMass, const QVector3D &inInertia)
372 : QPhysicsCommand(), mass(inMass), inertia(inInertia)
373{
374}
375
377 = default;
378
379QT_END_NAMESPACE
QPhysicsCommandApplyCentralForce(const QVector3D &inForce)
QPhysicsCommandApplyCentralImpulse(const QVector3D &inImpulse)
QPhysicsCommandApplyForce(const QVector3D &inForce, const QVector3D &inPosition)
~QPhysicsCommandApplyForce() override
~QPhysicsCommandApplyImpulse() override
QPhysicsCommandApplyImpulse(const QVector3D &inImpulse, const QVector3D &inPosition)
QPhysicsCommandApplyTorqueImpulse(const QVector3D &inImpulse)
~QPhysicsCommandApplyTorque() override
QPhysicsCommandApplyTorque(const QVector3D &inTorque)
~QPhysicsCommandReset() override
QPhysicsCommandReset(QVector3D inPosition, QVector3D inEulerRotation)
QPhysicsCommandSetAngularVelocity(const QVector3D &inAngularVelocity)
QPhysicsCommandSetCCD(QDynamicRigidBody::CCDType ccdType, bool worldEnableCCD)
~QPhysicsCommandSetCCD() override
QPhysicsCommandSetDensity(float inDensity)
~QPhysicsCommandSetDensity() override
QPhysicsCommandSetGravityEnabled(bool inGravityEnabled)
~QPhysicsCommandSetIsKinematic() override
QPhysicsCommandSetIsKinematic(bool inIsKinematic, bool worldEnableCCD)
QPhysicsCommandSetLinearVelocity(const QVector3D &inLinearVelocity)
QPhysicsCommandSetMassAndInertiaMatrix(float inMass, const QMatrix3x3 &inInertia)
QPhysicsCommandSetMassAndInertiaTensor(float inMass, const QVector3D &inInertia)
QPhysicsCommandSetMass(float inMass)
~QPhysicsCommandSetMass() override
virtual ~QPhysicsCommand()
static void resolveCCDFlags(physx::PxRigidBody &body, QDynamicRigidBody::CCDType ccd, bool isKinematic, bool worldEnableCCD)
static bool isSimulationDisabled(physx::PxRigidBody &body)
static QT_BEGIN_NAMESPACE bool isKinematicBody(physx::PxRigidDynamic &body)