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
qjoint.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qjoint_p.h"
5
6#include "physxnode/qabstractphysxnode_p.h"
7#include "physxnode/qphysxactorbody_p.h"
12
13#include <extensions/PxJoint.h>
14
16
17/*!
18 \qmltype PhysicsJoint
19 \inqmlmodule QtQuick3D.Physics
20 \since 6.12
21 \brief Base type for joints.
22
23 This is the abstract base type for all joints.
24
25 All joints have two bodies, and for each body a position and an orientation of the joint
26 relative to its local frame. If one of the bodies is not set then the joint will be
27 connected to the world.
28
29 \note At least one of the bodies needs to be dynamic.
30
31 \sa {DistanceJoint}
32 \sa {FixedJoint}
33 \sa {PrismaticJoint}
34 \sa {RevoluteJoint}
35 \sa {SphericalJoint}
36*/
37
38/*!
39 \qmlproperty PhysicsBody* PhysicsJoint::bodyA
40 \since 6.12
41 \default null
42
43 This property defines the first of the bodies this joint connects to.
44*/
45
46/*!
47 \qmlproperty PhysicsBody* PhysicsJoint::bodyB
48 \since 6.12
49 \default null
50
51 This property defines the second of the bodies this joint connects to.
52*/
53
54/*!
55 \qmlproperty vector3d PhysicsJoint::positionA
56 \since 6.12
57 \default (0, 0, 0)
58
59 The position of the joint relative to PhysicsJoint::bodyA.
60*/
61
62/*!
63 \qmlproperty vector3d PhysicsJoint::positionB
64 \since 6.12
65 \default (0, 0, 0)
66
67 The position of the joint relative to PhysicsJoint::bodyB.
68*/
69
70/*!
71 \qmlproperty quaternion PhysicsJoint::orientationA
72 \since 6.12
73 \default (1, 0, 0, 0)
74
75 The orientation of the joint relative to PhysicsJoint::bodyA.
76*/
77
78/*!
79 \qmlproperty quaternion PhysicsJoint::orientationB
80 \since 6.12
81 \default (1, 0, 0, 0)
82
83 The orientation of the joint relative to PhysicsJoint::bodyB.
84*/
85
86QPhysicsJoint::QPhysicsJoint()
87{
88 QPhysicsWorld::registerJoint(this);
89};
90
91QPhysicsJoint::~QPhysicsJoint()
92{
93 QPhysicsWorld::deregisterJoint(this);
94};
95
96QAbstractPhysicsBody *QPhysicsJoint::bodyA() const
97{
98 return m_bodyA;
99}
100
101void QPhysicsJoint::setBodyA(QAbstractPhysicsBody *newBodyA)
102{
103 if (m_bodyA == newBodyA)
104 return;
105
106 if (m_bodyA)
107 m_bodyA->disconnect(this);
108 if (newBodyA)
109 connect(newBodyA, &QAbstractPhysicsBody::destroyed, this, &QPhysicsJoint::onBodyDestroyed);
110
111 m_bodyA = newBodyA;
112 m_needsRebuild = true;
113 emit bodyAChanged();
114}
115
116QAbstractPhysicsBody *QPhysicsJoint::bodyB() const
117{
118 return m_bodyB;
119}
120
121void QPhysicsJoint::setBodyB(QAbstractPhysicsBody *newBodyB)
122{
123 if (m_bodyB == newBodyB)
124 return;
125
126 if (m_bodyB)
127 m_bodyB->disconnect(this);
128 if (newBodyB)
129 connect(newBodyB, &QAbstractPhysicsBody::destroyed, this, &QPhysicsJoint::onBodyDestroyed);
130
131 m_bodyB = newBodyB;
132 m_needsRebuild = true;
133 emit bodyBChanged();
134}
135
136QVector3D QPhysicsJoint::positionA() const
137{
138 return m_positionA;
139}
140
141void QPhysicsJoint::setPositionA(const QVector3D &newPositionA)
142{
143 if (m_positionA == newPositionA)
144 return;
145 m_positionA = newPositionA;
146 m_needsRebuild = true;
147 emit positionAChanged();
148}
149
150QVector3D QPhysicsJoint::positionB() const
151{
152 return m_positionB;
153}
154
155void QPhysicsJoint::setPositionB(const QVector3D &newPositionB)
156{
157 if (m_positionB == newPositionB)
158 return;
159 m_positionB = newPositionB;
160 m_needsRebuild = true;
161 emit positionBChanged();
162}
163
164QQuaternion QPhysicsJoint::orientationA() const
165{
166 return m_orientationA;
167}
168
169void QPhysicsJoint::setOrientationA(const QQuaternion &newOrientationA)
170{
171 if (m_orientationA == newOrientationA)
172 return;
173 m_orientationA = newOrientationA;
174 m_needsRebuild = true;
175 emit orientationAChanged();
176}
177
178QQuaternion QPhysicsJoint::orientationB() const
179{
180 return m_orientationB;
181}
182
183void QPhysicsJoint::setOrientationB(const QQuaternion &newOrientationB)
184{
185 if (m_orientationB == newOrientationB)
186 return;
187 m_orientationB = newOrientationB;
188 m_needsRebuild = true;
189 emit orientationBChanged();
190}
191
192physx::PxJoint *QPhysicsJoint::getPhysXBackend() const
193{
194 return m_joint;
195}
196
197void QPhysicsJoint::onBodyDestroyed(QObject *body)
198{
199 if (!body)
200 return;
201 body->disconnect(this);
202 if (m_bodyA == body)
203 setBodyA(nullptr);
204 if (m_bodyB == body)
205 setBodyB(nullptr);
206}
207
208void QPhysicsJoint::updatePhysXBackend()
209{
210 if (!m_dirtyProperties && !m_needsRebuild)
211 return;
212
213 if (m_joint && m_needsRebuild) {
214 m_joint->release();
215 m_joint = nullptr;
216 }
217
218 if (!m_bodyA && !m_bodyB)
219 return;
220
221 QPhysXActorBody *actorBodyA = m_bodyA && m_bodyA->m_backendObject
222 ? qobject_cast<QPhysXActorBody *>(m_bodyA->m_backendObject)
223 : nullptr;
224 QPhysXActorBody *actorBodyB = m_bodyB && m_bodyB->m_backendObject
225 ? qobject_cast<QPhysXActorBody *>(m_bodyB->m_backendObject)
226 : nullptr;
227 physx::PxRigidActor *actorA = actorBodyA ? actorBodyA->actor : nullptr;
228 physx::PxRigidActor *actorB = actorBodyB ? actorBodyB->actor : nullptr;
229
230 if (!actorA && !actorB)
231 return;
232
233 Q_ASSERT(StaticPhysXObjects::getReference().physicsCreated);
234 Q_ASSERT(StaticPhysXObjects::getReference().physics);
235
236 // At least one body needs to be dynamic
237 const bool compatibleTypes =
238 (actorA && actorA->getType() == physx::PxActorType::Enum::eRIGID_DYNAMIC)
239 || (actorB && actorB->getType() == physx::PxActorType::Enum::eRIGID_DYNAMIC);
240
241 if (!compatibleTypes) {
242 qWarning() << "QPhysicsJoint: Incompatible body types used for joint.";
243 }
244
245 if (m_needsRebuild && compatibleTypes) {
246 const auto trfA = physx::PxTransform(QPhysicsUtils::toPhysXType(m_positionA),
247 QPhysicsUtils::toPhysXType(m_orientationA));
248 const auto trfB = physx::PxTransform(QPhysicsUtils::toPhysXType(m_positionB),
249 QPhysicsUtils::toPhysXType(m_orientationB));
250 m_joint = createPhysxJoint(actorA, actorB, trfA, trfB);
251 }
252
253 if (m_joint && (m_dirtyProperties || m_needsRebuild)) {
254 setJointProperties();
255 }
256
257 m_dirtyProperties = false;
258 m_needsRebuild = false;
259}
260
#define QT_BEGIN_NAMESPACE
#define QT_END_NAMESPACE
#define emit