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
qphysxdynamicbody.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include "PxRigidDynamic.h"
8
14
15#include <QtGui/qquaternion.h>
16
18
19static void processCommandQueue(QQueue<QPhysicsCommand *> &commandQueue,
20 const QDynamicRigidBody &rigidBody, physx::PxRigidBody &body)
21{
22 for (auto command : commandQueue) {
23 command->execute(rigidBody, body);
24 delete command;
25 }
26
27 commandQueue.clear();
28}
29
30static QMatrix4x4 calculateKinematicNodeTransform(QQuick3DNode *node,
31 QHash<QQuick3DNode *, QMatrix4x4> &transformCache)
32{
33 // already calculated transform
34 if (transformCache.contains(node))
35 return transformCache[node];
36
37 QMatrix4x4 localTransform;
38
39 // DynamicRigidBody vs StaticRigidBody use different values for calculating the local transform
40 if (auto drb = qobject_cast<const QDynamicRigidBody *>(node); drb != nullptr) {
41 if (!drb->isKinematic()) {
42 qWarning() << "Non-kinematic body as a parent of a kinematic body is unsupported";
43 }
44 localTransform = QSSGRenderNode::calculateTransformMatrix(
45 drb->kinematicPosition(), drb->scale(), drb->kinematicPivot(),
46 drb->kinematicRotation());
47 } else {
48 localTransform = QSSGRenderNode::calculateTransformMatrix(node->position(), node->scale(),
49 node->pivot(), node->rotation());
50 }
51
52 QQuick3DNode *parent = node->parentNode();
53 if (!parent) // no parent, local transform is scene transform
54 return localTransform;
55
56 // calculate the parent scene transform and apply the nodes local transform
57 QMatrix4x4 parentTransform = calculateKinematicNodeTransform(parent, transformCache);
58 QMatrix4x4 sceneTransform = parentTransform * localTransform;
59
60 transformCache[node] = sceneTransform;
61 return sceneTransform;
62}
63
64static physx::PxRigidDynamicLockFlags getLockFlags(QDynamicRigidBody *body)
65{
66 const auto lockAngular = body->angularAxisLock();
67 const auto lockLinear = body->linearAxisLock();
68 const int flags = (lockAngular & QDynamicRigidBody::AxisLock::LockX
69 ? physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_X
70 : 0)
71 | (lockAngular & QDynamicRigidBody::AxisLock::LockY
72 ? physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y
73 : 0)
74 | (lockAngular & QDynamicRigidBody::AxisLock::LockZ
75 ? physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z
76 : 0)
77 | (lockLinear & QDynamicRigidBody::AxisLock::LockX
78 ? physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_X
79 : 0)
80 | (lockLinear & QDynamicRigidBody::AxisLock::LockY
81 ? physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Y
82 : 0)
83 | (lockLinear & QDynamicRigidBody::AxisLock::LockZ
84 ? physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Z
85 : 0);
86 return static_cast<physx::PxRigidDynamicLockFlags>(flags);
87}
88
89static physx::PxTransform getPhysXWorldTransform(const QMatrix4x4 transform)
90{
91 auto rotationMatrix = transform;
92 QSSGUtils::mat44::normalize(rotationMatrix);
93 auto rotation =
94 QQuaternion::fromRotationMatrix(QSSGUtils::mat44::getUpper3x3(rotationMatrix)).normalized();
95 const QVector3D worldPosition = QSSGUtils::mat44::getPosition(transform);
96 return physx::PxTransform(QPhysicsUtils::toPhysXType(worldPosition),
97 QPhysicsUtils::toPhysXType(rotation));
98}
99
100QPhysXDynamicBody::QPhysXDynamicBody(QDynamicRigidBody *frontEnd) : QPhysXRigidBody(frontEnd) { }
101
103{
104 auto *dynamicRigidBody = static_cast<QDynamicRigidBody *>(frontendNode);
105 return dynamicRigidBody->isSleeping() ? DebugDrawBodyType::DynamicSleeping
107}
108
109void QPhysXDynamicBody::sync(float deltaTime, QHash<QQuick3DNode *, QMatrix4x4> &transformCache)
110{
111 auto *dynamicRigidBody = static_cast<QDynamicRigidBody *>(frontendNode);
112 // first update front end node from physx simulation
113 dynamicRigidBody->updateFromPhysicsTransform(actor->getGlobalPose());
114
115 auto *dynamicActor = static_cast<physx::PxRigidDynamic *>(actor);
116 processCommandQueue(dynamicRigidBody->commandQueue(), *dynamicRigidBody, *dynamicActor);
117 if (dynamicRigidBody->isKinematic()) {
118 // Since this is a kinematic body we need to calculate the transform by hand and since
119 // bodies can occur in other bodies we need to calculate the tranform recursively for all
120 // parents. To save some computation we cache these transforms in 'transformCache'.
121 QMatrix4x4 transform = calculateKinematicNodeTransform(dynamicRigidBody, transformCache);
122 dynamicActor->setKinematicTarget(getPhysXWorldTransform(transform));
123 } else {
124 dynamicActor->setRigidDynamicLockFlags(getLockFlags(dynamicRigidBody));
125 }
126
127 const bool disabledPrevious = actor->getActorFlags() & physx::PxActorFlag::eDISABLE_SIMULATION;
128 const bool disabled = !dynamicRigidBody->simulationEnabled();
129 if (disabled != disabledPrevious) {
130 actor->setActorFlag(physx::PxActorFlag::eDISABLE_SIMULATION, disabled);
131 if (!disabled && !dynamicRigidBody->isKinematic())
132 dynamicActor->wakeUp();
133 }
134
135 dynamicRigidBody->setIsSleeping(dynamicActor->isSleeping());
136
137 QPhysXActorBody::sync(deltaTime, transformCache);
138}
139
140void QPhysXDynamicBody::rebuildDirtyShapes(QPhysicsWorld *world, QPhysXWorld *physX)
141{
142 if (!shapesDirty())
143 return;
144
145 buildShapes(physX);
146
147 QDynamicRigidBody *drb = static_cast<QDynamicRigidBody *>(frontendNode);
148
149 // Density must be set after shapes so the inertia tensor is set
150 if (!drb->hasStaticShapes()) {
151 // Body with only dynamic shapes, set/calculate mass
152 QPhysicsCommand *command = nullptr;
153 switch (drb->massMode()) {
154 case QDynamicRigidBody::MassMode::DefaultDensity: {
155 command = new QPhysicsCommandSetDensity(world->defaultDensity());
156 break;
157 }
158 case QDynamicRigidBody::MassMode::CustomDensity: {
159 command = new QPhysicsCommandSetDensity(drb->density());
160 break;
161 }
162 case QDynamicRigidBody::MassMode::Mass: {
163 const float mass = qMax(drb->mass(), 0.f);
164 command = new QPhysicsCommandSetMass(mass);
165 break;
166 }
167 case QDynamicRigidBody::MassMode::MassAndInertiaTensor: {
168 const float mass = qMax(drb->mass(), 0.f);
169 command = new QPhysicsCommandSetMassAndInertiaTensor(mass, drb->inertiaTensor());
170 break;
171 }
172 case QDynamicRigidBody::MassMode::MassAndInertiaMatrix: {
173 const float mass = qMax(drb->mass(), 0.f);
174 command = new QPhysicsCommandSetMassAndInertiaMatrix(mass, drb->inertiaMatrix());
175 break;
176 }
177 }
178
179 drb->commandQueue().enqueue(command);
180 } else if (!drb->isKinematic()) {
181 // Body with static shapes that is not kinematic, this is disallowed
182 qWarning() << "Cannot make body containing trimesh/heightfield/plane non-kinematic, "
183 "forcing kinematic.";
184 drb->setIsKinematic(true);
185 }
186
187 const bool isKinematic = drb->isKinematic();
188 auto *dynamicBody = static_cast<physx::PxRigidDynamic *>(actor);
189 dynamicBody->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, isKinematic);
190
191 if (world->enableCCD()) {
192 // Regular sweep-based CCD is only available for non-kinematic bodies but speculative CCD
193 // is available for kinematic bodies so we use that.
194 dynamicBody->setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD, !isKinematic);
195 dynamicBody->setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD, isKinematic);
196 }
197
198 setShapesDirty(false);
199}
200
202{
203 QDynamicRigidBody *rigidBody = static_cast<QDynamicRigidBody *>(frontendNode);
204 rigidBody->updateDefaultDensity(density);
205}
206
void setShapesDirty(bool dirty)
void buildShapes(QPhysXWorld *physX)
void updateDefaultDensity(float density) override
QPhysXDynamicBody(QDynamicRigidBody *frontEnd)
DebugDrawBodyType getDebugDrawBodyType() override
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
void rebuildDirtyShapes(QPhysicsWorld *world, QPhysXWorld *physX) override
QPhysicsCommandSetMass(float inMass)
DebugDrawBodyType
static QMatrix4x4 calculateKinematicNodeTransform(QQuick3DNode *node, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache)
static physx::PxTransform getPhysXWorldTransform(const QMatrix4x4 transform)
static physx::PxRigidDynamicLockFlags getLockFlags(QDynamicRigidBody *body)
static QT_BEGIN_NAMESPACE void processCommandQueue(QQueue< QPhysicsCommand * > &commandQueue, const QDynamicRigidBody &rigidBody, physx::PxRigidBody &body)
#define QT_BEGIN_NAMESPACE
#define QT_END_NAMESPACE