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::PxRigidBody &body)
16{
17 return static_cast<bool>(body.getRigidBodyFlags() & physx::PxRigidBodyFlag::eKINEMATIC);
18}
19
20static void resolveCCDFlags(physx::PxRigidBody &body, QDynamicRigidBody::CCDType ccd,
21 bool isKinematic, bool worldEnableCCD)
22{
23 switch (ccd) {
24 case QDynamicRigidBody::CCDType::SweepBasedCCD: {
25 // Kinematic bodies only support speculative CCD
26 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, !isKinematic); // Sweep-based
27 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, isKinematic);
28 break;
29 }
30
31 case QDynamicRigidBody::CCDType::SpeculativeCCD: {
32 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, true);
33 break;
34 }
35
36 case QDynamicRigidBody::CCDType::None: {
37 if (worldEnableCCD) {
38 // Kinematic bodies only support speculative CCD
39 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, !isKinematic); // Sweep-based
40 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, isKinematic);
41 }
42 break;
43 }
44 }
45}
46
48 = default;
49
54
56 = default;
57
58void QPhysicsCommandApplyCentralForce::execute(const QDynamicRigidBody &rigidBody,
59 physx::PxRigidBody &body)
60{
61 Q_UNUSED(rigidBody)
62 if (isKinematicBody(body))
63 return;
64 body.addForce(QPhysicsUtils::toPhysXType(force));
65}
66
68 const QVector3D &inPosition)
70{
71}
72
74 = default;
75
76void QPhysicsCommandApplyForce::execute(const QDynamicRigidBody &rigidBody,
77 physx::PxRigidBody &body)
78{
79 Q_UNUSED(rigidBody)
80 if (isKinematicBody(body))
81 return;
82 physx::PxRigidBodyExt::addForceAtPos(body, QPhysicsUtils::toPhysXType(force),
83 QPhysicsUtils::toPhysXType(position));
84}
85
90
92 = default;
93
94void QPhysicsCommandApplyTorque::execute(const QDynamicRigidBody &rigidBody,
95 physx::PxRigidBody &body)
96{
97 Q_UNUSED(rigidBody)
98 if (isKinematicBody(body))
99 return;
100 body.addTorque(QPhysicsUtils::toPhysXType(torque));
101}
102
107
109 = default;
110
111void QPhysicsCommandApplyCentralImpulse::execute(const QDynamicRigidBody &rigidBody,
112 physx::PxRigidBody &body)
113{
114 Q_UNUSED(rigidBody)
115 if (isKinematicBody(body))
116 return;
117 body.addForce(QPhysicsUtils::toPhysXType(impulse), physx::PxForceMode::eIMPULSE);
118}
119
121 const QVector3D &inPosition)
123{
124}
125
127 = default;
128
129void QPhysicsCommandApplyImpulse::execute(const QDynamicRigidBody &rigidBody,
130 physx::PxRigidBody &body)
131{
132 Q_UNUSED(rigidBody)
133 if (isKinematicBody(body))
134 return;
135 physx::PxRigidBodyExt::addForceAtPos(body, QPhysicsUtils::toPhysXType(impulse),
136 QPhysicsUtils::toPhysXType(position),
137 physx::PxForceMode::eIMPULSE);
138}
139
144
146 = default;
147
148void QPhysicsCommandApplyTorqueImpulse::execute(const QDynamicRigidBody &rigidBody,
149 physx::PxRigidBody &body)
150{
151 Q_UNUSED(rigidBody)
152 if (isKinematicBody(body))
153 return;
154
155 body.addTorque(QPhysicsUtils::toPhysXType(impulse), physx::PxForceMode::eIMPULSE);
156}
157
163
165 = default;
166
167void QPhysicsCommandSetAngularVelocity::execute(const QDynamicRigidBody &rigidBody,
168 physx::PxRigidBody &body)
169{
170 Q_UNUSED(rigidBody)
171 body.setAngularVelocity(QPhysicsUtils::toPhysXType(angularVelocity));
172}
173
179
181 = default;
182
183void QPhysicsCommandSetLinearVelocity::execute(const QDynamicRigidBody &rigidBody,
184 physx::PxRigidBody &body)
185{
186 Q_UNUSED(rigidBody)
187 body.setLinearVelocity(QPhysicsUtils::toPhysXType(linearVelocity));
188}
189
191
193 = default;
194
195void QPhysicsCommandSetMass::execute(const QDynamicRigidBody &rigidBody, physx::PxRigidBody &body)
196{
197 if (rigidBody.hasStaticShapes()) {
198 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
199 "ignoring.";
200 return;
201 }
202
203 physx::PxRigidBodyExt::setMassAndUpdateInertia(body, mass);
204}
205
206void QPhysicsCommandSetMassAndInertiaTensor::execute(const QDynamicRigidBody &rigidBody,
207 physx::PxRigidBody &body)
208{
209 if (rigidBody.hasStaticShapes()) {
210 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
211 "ignoring.";
212 return;
213 }
214
215 body.setMass(mass);
216 body.setCMassLocalPose(
217 physx::PxTransform(QPhysicsUtils::toPhysXType(rigidBody.centerOfMassPosition()),
218 QPhysicsUtils::toPhysXType(rigidBody.centerOfMassRotation())));
219 body.setMassSpaceInertiaTensor(QPhysicsUtils::toPhysXType(inertia));
220}
221
223 float inMass, const QMatrix3x3 &inInertia)
224 : QPhysicsCommand(), mass(inMass), inertia(inInertia)
225{
226}
227
229 = default;
230
231void QPhysicsCommandSetMassAndInertiaMatrix::execute(const QDynamicRigidBody &rigidBody,
232 physx::PxRigidBody &body)
233{
234 if (rigidBody.hasStaticShapes()) {
235 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
236 "ignoring.";
237 return;
238 }
239
240 physx::PxQuat massFrame;
241 physx::PxVec3 diagTensor = physx::PxDiagonalize(QPhysicsUtils::toPhysXType(inertia), massFrame);
242 if ((diagTensor.x <= 0.0f) || (diagTensor.y <= 0.0f) || (diagTensor.z <= 0.0f))
243 return; // FIXME: print error?
244
245 body.setCMassLocalPose(physx::PxTransform(
246 QPhysicsUtils::toPhysXType(rigidBody.centerOfMassPosition()), massFrame));
247 body.setMass(mass);
248 body.setMassSpaceInertiaTensor(diagTensor);
249}
250
252 : QPhysicsCommand(), density(inDensity)
253{
254}
255
257 = default;
258
259void QPhysicsCommandSetDensity::execute(const QDynamicRigidBody &rigidBody,
260 physx::PxRigidBody &body)
261{
262 if (rigidBody.hasStaticShapes()) {
263 qWarning() << "Cannot set mass or density on a body containing trimesh/heightfield/plane, "
264 "ignoring.";
265 return;
266 }
267
268 physx::PxRigidBodyExt::updateMassAndInertia(body, density);
269}
270
272 bool worldEnableCCD)
273 : QPhysicsCommand(), isKinematic(inIsKinematic), worldEnableCCD(worldEnableCCD)
274{
275}
276
278 = default;
279
280void QPhysicsCommandSetIsKinematic::execute(const QDynamicRigidBody &rigidBody,
281 physx::PxRigidBody &body)
282{
283 if (rigidBody.hasStaticShapes() && !isKinematic) {
284 qWarning() << "Cannot make a body containing trimesh/heightfield/plane non-kinematic, "
285 "ignoring.";
286 return;
287 }
288
289 // Clear CCD before flipping kinematic mode: PhysX rejects sweep-based CCD on
290 // kinematic bodies, so leaving a stale CCD flag set while eKINEMATIC changes
291 // would trigger a spurious warning regardless of transition direction.
292 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, false); // Sweep-based
293 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, false);
294 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, isKinematic);
295
296 // Sync CCD flags directly since changing kinematic mode alters supported CCD types
297 resolveCCDFlags(body, rigidBody.ccd(), isKinematic, worldEnableCCD);
298}
299
300QPhysicsCommandSetCCD::QPhysicsCommandSetCCD(QDynamicRigidBody::CCDType ccdType,
301 bool worldEnableCCD)
302 : QPhysicsCommand(), ccdType(ccdType), worldEnableCCD(worldEnableCCD)
303{
304}
305
307
308void QPhysicsCommandSetCCD::execute(const QDynamicRigidBody &rigidBody, physx::PxRigidBody &body)
309{
310 // Clear both flags first so the writes below can never collide with a stale
311 // flag from the previous ccd mode (PhysX rejects raising eENABLE_CCD while
312 // eENABLE_SPECULATIVE_CCD, or vice versa, is still set).
313 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, false); // Sweep-based
314 body.setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, false);
315
316 resolveCCDFlags(body, ccdType, rigidBody.isKinematic(), worldEnableCCD);
317}
318
320 : QPhysicsCommand(), gravityEnabled(inGravityEnabled)
321{
322}
323
325 = default;
326
327void QPhysicsCommandSetGravityEnabled::execute(const QDynamicRigidBody &rigidBody,
328 physx::PxRigidBody &body)
329{
330 Q_UNUSED(rigidBody)
331 body.setActorFlag(physx::PxActorFlag::eDISABLE_GRAVITY, !gravityEnabled);
332}
333
334QPhysicsCommandReset::QPhysicsCommandReset(QVector3D inPosition, QVector3D inEulerRotation)
336{
337}
338
340 = default;
341
342void QPhysicsCommandReset::execute(const QDynamicRigidBody &rigidBody, physx::PxRigidBody &body)
343{
344 Q_UNUSED(rigidBody)
345 body.setLinearVelocity(physx::PxVec3(0, 0, 0));
346 body.setAngularVelocity(physx::PxVec3(0, 0, 0));
347
348 auto *parentNode = rigidBody.parentNode();
349 QVector3D scenePosition = parentNode ? parentNode->mapPositionToScene(position) : position;
350 // TODO: rotation also needs to be mapped
351
352 body.setGlobalPose(physx::PxTransform(
353 QPhysicsUtils::toPhysXType(scenePosition),
354 QPhysicsUtils::toPhysXType(QQuaternion::fromEulerAngles(eulerRotation))));
355}
356
358 float inMass, const QVector3D &inInertia)
359 : QPhysicsCommand(), mass(inMass), inertia(inInertia)
360{
361}
362
364 = default;
365
366QT_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 QT_BEGIN_NAMESPACE bool isKinematicBody(physx::PxRigidBody &body)
static void resolveCCDFlags(physx::PxRigidBody &body, QDynamicRigidBody::CCDType ccd, bool isKinematic, bool worldEnableCCD)