Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qphysxactorbody.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
4#include "qphysxactorbody_p.h"
5
6#include "PxMaterial.h"
7#include "PxPhysics.h"
8#include "PxRigidDynamic.h"
9#include "PxRigidActor.h"
10#include "PxScene.h"
11
14#include "qheightfieldshape_p.h"
15#include "qphysicsutils_p.h"
16#include "qplaneshape_p.h"
18
19#define PHYSX_RELEASE(x) \
20 if (x != nullptr) { \
21 x->release(); \
22 x = nullptr; \
23 }
24
26
27static physx::PxTransform getPhysXLocalTransform(const QQuick3DNode *node)
28{
29 // Modify transforms to make the PhysX shapes match the QtQuick3D conventions
30 if (qobject_cast<const QPlaneShape *>(node) != nullptr) {
31 // Rotate the plane to make it match the built-in rectangle
33 return physx::PxTransform(QPhysicsUtils::toPhysXType(node->position()),
35 } else if (auto *hf = qobject_cast<const QHeightFieldShape *>(node)) {
36 // Shift the height field so it's centered at the origin
37 return physx::PxTransform(QPhysicsUtils::toPhysXType(node->position() + hf->hfOffset()),
39 }
40
41 const QQuaternion &rotation = node->rotation();
42 const QVector3D &localPosition = node->position();
43 const QVector3D &scale = node->sceneScale();
44 return physx::PxTransform(QPhysicsUtils::toPhysXType(localPosition * scale),
46}
47
49
51{
52 if (actor) {
53 physX->scene->removeActor(*actor);
55 }
57}
58
60{
62
63 createMaterial(physX);
64 createActor(physX);
65
66 actor->userData = reinterpret_cast<void *>(frontendNode);
67 physX->scene->addActor(*actor);
68 setShapesDirty(true);
69}
70
71void QPhysXActorBody::sync(float /*deltaTime*/,
72 QHash<QQuick3DNode *, QMatrix4x4> & /*transformCache*/)
73{
74 auto *body = static_cast<QAbstractPhysicsBody *>(frontendNode);
75 if (QPhysicsMaterial *qtMaterial = body->physicsMaterial()) {
76 const float staticFriction = qtMaterial->staticFriction();
77 const float dynamicFriction = qtMaterial->dynamicFriction();
78 const float restitution = qtMaterial->restitution();
79 if (material->getStaticFriction() != staticFriction)
80 material->setStaticFriction(staticFriction);
81 if (material->getDynamicFriction() != dynamicFriction)
82 material->setDynamicFriction(dynamicFriction);
83 if (material->getRestitution() != restitution)
84 material->setRestitution(restitution);
85 }
86}
87
89{
90 if (!frontendNode || !actor)
91 return;
92
93 // Go through the shapes and look for a change in pose (rotation, position)
94 // TODO: it is likely cheaper to connect a signal for changes on the position and rotation
95 // property and mark the node dirty then.
96 if (!shapesDirty()) {
97 const auto &collisionShapes = frontendNode->getCollisionShapesList();
98 const auto &physXShapes = shapes;
99
100 const int len = collisionShapes.size();
101 if (physXShapes.size() != len) {
102 // This should not really happen but check it anyway
103 setShapesDirty(true);
104 } else {
105 for (int i = 0; i < len; i++) {
106 auto poseNew = getPhysXLocalTransform(collisionShapes[i]);
107 auto poseOld = physXShapes[i]->getLocalPose();
108
109 if (!QPhysicsUtils::fuzzyEquals(poseNew, poseOld)) {
110 setShapesDirty(true);
111 break;
112 }
113 }
114 }
115 }
116}
117
119{
120 if (!shapesDirty())
121 return;
122 buildShapes(physX);
123 setShapesDirty(false);
124}
125
127{
128 auto &s_physx = StaticPhysXObjects::getReference();
129 const physx::PxTransform trf = QPhysicsUtils::toPhysXTransform(frontendNode->scenePosition(),
131 actor = s_physx.physics->createRigidDynamic(trf);
132}
133
135{
136 return true;
137}
138
140{
141 return actor->getGlobalPose();
142}
143
145{
146 auto body = actor;
147 for (auto *shape : shapes) {
148 body->detachShape(*shape);
149 PHYSX_RELEASE(shape);
150 }
151
152 // TODO: Only remove changed shapes?
153 shapes.clear();
154
155 for (const auto &collisionShape : frontendNode->getCollisionShapesList()) {
156 // TODO: shapes can be shared between multiple actors.
157 // Do we need to create new ones for every body?
158 auto *geom = collisionShape->getPhysXGeometry();
159 if (!geom || !material)
160 continue;
161
162 auto &s_physx = StaticPhysXObjects::getReference();
163 auto physXShape = s_physx.physics->createShape(*geom, *material);
164
165 if (useTriggerFlag()) {
166 physXShape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, false);
167 physXShape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, true);
168 }
169
170 { // Setup filtering
171 physx::PxFilterData filterData;
172 filterData.word0 = frontendNode->filterGroup();
173 filterData.word1 = frontendNode->filterIgnoreGroups();
174 physXShape->setSimulationFilterData(filterData);
175 }
176
177 shapes.push_back(physXShape);
178 physXShape->setLocalPose(getPhysXLocalTransform(collisionShape));
179 body->attachShape(*physXShape);
180 }
181
182 // Filters are always clean after building shapes
183 setFiltersDirty(false);
184}
185
187{
188 if (!filtersDirty())
189 return;
190
191 // Go through all shapes and set the filter group and mask.
192 // TODO: What about shared shapes on several actors?
193 for (auto &physXShape : shapes) {
194 physx::PxFilterData filterData;
195 filterData.word0 = frontendNode->filterGroup();
196 filterData.word1 = frontendNode->filterIgnoreGroups();
197 physXShape->setSimulationFilterData(filterData);
198 }
199
200 setFiltersDirty(false);
201}
202
QAbstractPhysicsNode * frontendNode
QVector< physx::PxShape * > shapes
virtual void cleanup(QPhysXWorld *)
physx::PxMaterial * material
void setShapesDirty(bool dirty)
void setFiltersDirty(bool dirty)
virtual void createMaterial(QPhysXWorld *physX)
virtual bool useTriggerFlag()
const QVector< QAbstractCollisionShape * > & getCollisionShapesList() const
void markDirtyShapes() override
void buildShapes(QPhysXWorld *physX)
void rebuildDirtyShapes(QPhysicsWorld *world, QPhysXWorld *physX) override
void init(QPhysicsWorld *world, QPhysXWorld *physX) override
bool debugGeometryCapability() override
QPhysXActorBody(QAbstractPhysicsNode *frontEnd)
void cleanup(QPhysXWorld *physX) override
physx::PxRigidActor * actor
virtual void createActor(QPhysXWorld *physX)
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
void updateFilters() override
physx::PxTransform getGlobalPose() override
The QQuaternion class represents a quaternion consisting of a vector and scalar.
QVector3D sceneScale
QVector3D scenePosition
QQuaternion rotation
QQuaternion sceneRotation
QVector3D position
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
Q_ALWAYS_INLINE physx::PxVec3 toPhysXType(const QVector3D &qvec)
Q_ALWAYS_INLINE bool fuzzyEquals(const physx::PxTransform &a, const physx::PxTransform &b)
const QQuaternion kMinus90YawRotation
Q_ALWAYS_INLINE physx::PxTransform toPhysXTransform(const QVector3D &position, const QQuaternion &rotation)
Combined button and popup list for selecting options.
#define PHYSX_RELEASE(x)
GLenum GLsizei len
GLenum GLenum GLenum GLenum GLenum scale
static QT_BEGIN_NAMESPACE physx::PxTransform getPhysXLocalTransform(const QQuick3DNode *node)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static StaticPhysXObjects & getReference()