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
qdynamicrigidbody.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
7#include "physxnode/qphysxdynamicbody_p.h"
8
10
11/*!
12 \qmltype DynamicRigidBody
13 \inqmlmodule QtQuick3D.Physics
14 \inherits PhysicsBody
15 \since 6.4
16 \brief A physical body that can move or be moved.
17
18 This type defines a dynamic rigid body: an object that is part of the physics
19 scene and behaves like a physical object with mass and velocity.
20
21 \note \l{TriangleMeshShape}{triangle mesh}, \l{HeightFieldShape}{height field} and
22 \l{PlaneShape}{plane} geometry shapes are not allowed as collision shapes when
23 \l isKinematic is \c false.
24*/
25
26/*!
27 \qmlproperty real DynamicRigidBody::mass
28
29 This property defines the mass of the body. Note that this is only used when massMode is not
30 \c {DynamicRigidBody.CustomDensity} or \c {DynamicRigidBody.DefaultDensity}. Also note that
31 a value of 0 is interpreted as infinite mass and that negative numbers are not allowed.
32
33 Default value: \c 1
34
35 Range: \c{[0, inf]}
36
37 \sa massMode
38*/
39
40/*!
41 \qmlproperty real DynamicRigidBody::density
42
43 This property defines the density of the body. This is only used when massMode is set to \c
44 {DynamicRigidBody.CustomDensity}.
45
46 Default value: \c{0.001}
47
48 Range: \c{(0, inf]}
49 \sa massMode
50*/
51
52/*!
53 \qmlproperty AxisLock DynamicRigidBody::linearAxisLock
54
55 This property locks the linear velocity of the body along the axes defined by the
56 DynamicRigidBody.AxisLock enum. To lock several axes just bitwise-or their enum values.
57
58 Available options:
59
60 \value DynamicRigidBody.None
61 No axis lock.
62
63 \value DynamicRigidBody.LockX
64 Lock X axis.
65
66 \value DynamicRigidBody.LockY
67 Lock Y axis.
68
69 \value DynamicRigidBody.LockZ
70 Lock Z axis.
71
72 Default value: \c{DynamicRigidBody.None}
73*/
74
75/*!
76 \qmlproperty AxisLock DynamicRigidBody::angularAxisLock
77
78 This property locks the angular velocity of the body along the axes defined by the
79 DynamicRigidBody.AxisLock enum. To lock several axes just bitwise-or their enum values.
80
81 Available options:
82
83 \value DynamicRigidBody.None
84 No axis lock.
85
86 \value DynamicRigidBody.LockX
87 Lock X axis.
88
89 \value DynamicRigidBody.LockY
90 Lock Y axis.
91
92 \value DynamicRigidBody.LockZ
93 Lock Z axis.
94
95 Default value: \c{DynamicRigidBody.None}
96*/
97
98/*!
99 \qmlproperty bool DynamicRigidBody::isKinematic
100 This property defines whether the object is kinematic or not. A kinematic object does not get
101 influenced by external forces and can be seen as an object of infinite mass. If this property is
102 set then in every simulation frame the physical object will be moved to its target position
103 regardless of external forces. Note that to move and rotate the kinematic object you need to use
104 the kinematicPosition, kinematicRotation, kinematicEulerRotation and kinematicPivot properties.
105
106 Default value: \c{false}
107
108 \sa kinematicPosition, kinematicRotation, kinematicEulerRotation, kinematicPivot
109*/
110
111/*!
112 \qmlproperty bool DynamicRigidBody::gravityEnabled
113 This property defines whether the object is going to be affected by gravity or not.
114
115 Default value: \c{true}
116*/
117
118/*!
119 \qmlproperty MassMode DynamicRigidBody::massMode
120
121 This property holds the enum which describes how mass and inertia are calculated for this body.
122
123 Available options:
124
125 \value DynamicRigidBody.DefaultDensity
126 Use the density specified in the \l {PhysicsWorld::}{defaultDensity} property in
127 PhysicsWorld to calculate mass and inertia assuming a uniform density.
128
129 \value DynamicRigidBody.CustomDensity
130 Use specified density in the specified in the \l {DynamicRigidBody::}{density} to
131 calculate mass and inertia assuming a uniform density.
132
133 \value DynamicRigidBody.Mass
134 Use the specified mass to calculate inertia assuming a uniform density.
135
136 \value DynamicRigidBody.MassAndInertiaTensor
137 Use the specified mass value and inertia tensor.
138
139 \value DynamicRigidBody.MassAndInertiaMatrix
140 Use the specified mass value and calculate inertia from the specified inertia
141 matrix.
142
143 Default value: \c{DynamicRigidBody.DefaultDensity}
144*/
145
146/*!
147 \qmlproperty vector3d DynamicRigidBody::inertiaTensor
148
149 Defines the inertia tensor vector, using a parameter specified in mass space coordinates.
150
151 This is the diagonal vector of a 3x3 diagonal matrix, if you have a non diagonal world/actor
152 space inertia tensor then you should use \l{DynamicRigidBody::inertiaMatrix}{inertiaMatrix}
153 instead.
154
155 The inertia tensor components must be positive and a value of 0 in any component is
156 interpreted as infinite inertia along that axis. Note that this is only used when
157 massMode is set to \c DynamicRigidBody.MassAndInertiaTensor.
158
159 Default value: \c{(1, 1, 1)}
160
161 \sa massMode, inertiaMatrix
162*/
163
164/*!
165 \qmlproperty vector3d DynamicRigidBody::centerOfMassPosition
166
167 Defines the position of the center of mass relative to the body. Note that this is only used
168 when massMode is set to \c DynamicRigidBody.MassAndInertiaTensor.
169
170 Default value: \c{(0, 0, 0)}
171
172 \sa massMode, inertiaTensor
173*/
174
175/*!
176 \qmlproperty quaternion DynamicRigidBody::centerOfMassRotation
177
178 Defines the rotation of the center of mass pose, i.e. it specifies the orientation of the body's
179 principal inertia axes relative to the body. Note that this is only used when massMode is set to
180 \c DynamicRigidBody.MassAndInertiaTensor.
181
182 Default value: \c{(1, 0, 0, 0)}
183
184 \sa massMode, inertiaTensor
185*/
186
187/*!
188 \qmlproperty list<real> DynamicRigidBody::inertiaMatrix
189
190 Defines the inertia tensor matrix. This is a 3x3 matrix in column-major order. Note that this
191 matrix is expected to be diagonalizable. Note that this is only used when massMode is set to
192 \c DynamicRigidBody.MassAndInertiaMatrix.
193
194 Default value: A 3x3 identity matrix
195
196 \sa massMode, inertiaTensor
197*/
198
199/*!
200 \qmlproperty vector3d DynamicRigidBody::kinematicPosition
201 \since 6.5
202
203 Defines the position of the object when it is kinematic, i.e. when \l isKinematic is set to \c
204 true. On each iteration of the simulation the physical object will be updated according to this
205 value.
206
207 Default value: \c{(0, 0, 0)}
208
209 \sa isKinematic, kinematicRotation, kinematicEulerRotation, kinematicPivot
210*/
211
212/*!
213 \qmlproperty quaternion DynamicRigidBody::kinematicRotation
214 \since 6.5
215
216 Defines the rotation of the object when it is kinematic, i.e. when \l isKinematic is set to \c
217 true. On each iteration of the simulation the physical object will be updated according to this
218 value.
219
220 Default value: \c{(1, 0, 0, 0)}
221
222 \sa isKinematic, kinematicPosition, kinematicEulerRotation, kinematicPivot
223*/
224
225/*!
226 \qmlproperty vector3d DynamicRigidBody::kinematicEulerRotation
227 \since 6.5
228
229 Defines the euler rotation of the object when it is kinematic, i.e. when \l isKinematic is set to \c
230 true. On each iteration of the simulation the physical object will be updated according to this
231 value.
232
233 Default value: \c{(0, 0, 0)}
234
235 \sa isKinematic, kinematicPosition, kinematicEulerRotation, kinematicPivot
236*/
237
238/*!
239 \qmlproperty vector3d DynamicRigidBody::kinematicPivot
240 \since 6.5
241
242 Defines the pivot of the object when it is kinematic, i.e. when \l isKinematic is set to \c
243 true. On each iteration of the simulation the physical object will be updated according to this
244 value.
245
246 Default value: \c{(0, 0, 0)}
247
248 \sa isKinematic, kinematicPosition, kinematicEulerRotation, kinematicRotation
249*/
250
251/*!
252 \qmlproperty bool DynamicRigidBody::isSleeping
253 \since 6.9
254
255 Is set to \c{true} if the body is sleeping. While it is technically possible to set this property
256 it should be seen as a read-only property that is set on every frame the physics simulation is
257 running.
258*/
259
260/*!
261 \qmlmethod DynamicRigidBody::applyCentralForce(vector3d force)
262
263 Applies a \a force on the center of the body.
264*/
265
266/*!
267 \qmlmethod DynamicRigidBody::applyForce(vector3d force, vector3d position)
268
269 Applies a \a force at a \a position on the body.
270*/
271
272/*!
273 \qmlmethod DynamicRigidBody::applyTorque(vector3d torque)
274
275 Applies a \a torque on the body.
276*/
277
278/*!
279 \qmlmethod DynamicRigidBody::applyCentralImpulse(vector3d impulse)
280
281 Applies an \a impulse on the center of the body.
282*/
283
284/*!
285 \qmlmethod DynamicRigidBody::applyImpulse(vector3d impulse, vector3d position)
286
287 Applies an \a impulse at a \a position on the body.
288*/
289
290/*!
291 \qmlmethod DynamicRigidBody::applyTorqueImpulse(vector3d impulse)
292
293 Applies a torque \a impulse on the body.
294*/
295
296/*!
297 \qmlmethod DynamicRigidBody::setAngularVelocity(vector3d angularVelocity)
298
299 Sets the \a angularVelocity of the body.
300*/
301
302/*!
303 \qmlmethod DynamicRigidBody::setLinearVelocity(vector3d linearVelocity)
304
305 Sets the \a linearVelocity of the body.
306*/
307
308/*!
309 \qmlmethod DynamicRigidBody::reset(vector3d position, vector3d eulerRotation)
310
311 Resets the body's \a position and \a eulerRotation.
312*/
313
314QDynamicRigidBody::QDynamicRigidBody() = default;
315
316QDynamicRigidBody::~QDynamicRigidBody()
317{
318 qDeleteAll(m_commandQueue);
319 m_commandQueue.clear();
320}
321
322const QQuaternion &QDynamicRigidBody::centerOfMassRotation() const
323{
324 return m_centerOfMassRotation;
325}
326
327void QDynamicRigidBody::setCenterOfMassRotation(const QQuaternion &newCenterOfMassRotation)
328{
329 if (qFuzzyCompare(m_centerOfMassRotation, newCenterOfMassRotation))
330 return;
331 m_centerOfMassRotation = newCenterOfMassRotation;
332
333 // Only inertia tensor is using rotation
334 if (m_massMode == MassMode::MassAndInertiaTensor)
335 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaTensor(m_mass, m_inertiaTensor));
336
337 emit centerOfMassRotationChanged();
338}
339
340const QVector3D &QDynamicRigidBody::centerOfMassPosition() const
341{
342 return m_centerOfMassPosition;
343}
344
345void QDynamicRigidBody::setCenterOfMassPosition(const QVector3D &newCenterOfMassPosition)
346{
347 if (qFuzzyCompare(m_centerOfMassPosition, newCenterOfMassPosition))
348 return;
349
350 switch (m_massMode) {
351 case MassMode::MassAndInertiaTensor: {
352 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaTensor(m_mass, m_inertiaTensor));
353 break;
354 }
355 case MassMode::MassAndInertiaMatrix: {
356 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaMatrix(m_mass, m_inertiaMatrix));
357 break;
358 }
359 case MassMode::DefaultDensity:
360 case MassMode::CustomDensity:
361 case MassMode::Mass:
362 break;
363 }
364
365 m_centerOfMassPosition = newCenterOfMassPosition;
366 emit centerOfMassPositionChanged();
367}
368
369QDynamicRigidBody::MassMode QDynamicRigidBody::massMode() const
370{
371 return m_massMode;
372}
373
374void QDynamicRigidBody::setMassMode(const MassMode newMassMode)
375{
376 if (m_massMode == newMassMode)
377 return;
378
379 switch (newMassMode) {
380 case MassMode::DefaultDensity: {
381 auto world = QPhysicsWorld::getWorld(this);
382 if (world) {
383 m_commandQueue.enqueue(new QPhysicsCommandSetDensity(world->defaultDensity()));
384 } else {
385 qWarning() << "No physics world found, cannot set default density.";
386 }
387 break;
388 }
389 case MassMode::CustomDensity: {
390 m_commandQueue.enqueue(new QPhysicsCommandSetDensity(m_density));
391 break;
392 }
393 case MassMode::Mass: {
394 m_commandQueue.enqueue(new QPhysicsCommandSetMass(m_mass));
395 break;
396 }
397 case MassMode::MassAndInertiaTensor: {
398 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaTensor(m_mass, m_inertiaTensor));
399 break;
400 }
401 case MassMode::MassAndInertiaMatrix: {
402 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaMatrix(m_mass, m_inertiaMatrix));
403 break;
404 }
405 }
406
407 m_massMode = newMassMode;
408 emit massModeChanged();
409}
410
411const QVector3D &QDynamicRigidBody::inertiaTensor() const
412{
413 return m_inertiaTensor;
414}
415
416void QDynamicRigidBody::setInertiaTensor(const QVector3D &newInertiaTensor)
417{
418 if (qFuzzyCompare(m_inertiaTensor, newInertiaTensor))
419 return;
420 m_inertiaTensor = newInertiaTensor;
421
422 if (m_massMode == MassMode::MassAndInertiaTensor)
423 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaTensor(m_mass, m_inertiaTensor));
424
425 emit inertiaTensorChanged();
426}
427
428const QList<float> &QDynamicRigidBody::readInertiaMatrix() const
429{
430 return m_inertiaMatrixList;
431}
432
433static bool fuzzyEquals(const QList<float> &a, const QList<float> &b)
434{
435 if (a.length() != b.length())
436 return false;
437
438 const int length = a.length();
439 for (int i = 0; i < length; i++)
440 if (!qFuzzyCompare(a[i], b[i]))
441 return false;
442
443 return true;
444}
445
446void QDynamicRigidBody::setInertiaMatrix(const QList<float> &newInertiaMatrix)
447{
448 if (fuzzyEquals(m_inertiaMatrixList, newInertiaMatrix))
449 return;
450
451 m_inertiaMatrixList = newInertiaMatrix;
452 const int elemsToCopy = qMin(m_inertiaMatrixList.length(), 9);
453 memcpy(m_inertiaMatrix.data(), m_inertiaMatrixList.data(), elemsToCopy * sizeof(float));
454 memset(m_inertiaMatrix.data() + elemsToCopy, 0, (9 - elemsToCopy) * sizeof(float));
455
456 if (m_massMode == MassMode::MassAndInertiaMatrix)
457 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaMatrix(m_mass, m_inertiaMatrix));
458
459 emit inertiaMatrixChanged();
460}
461
462const QMatrix3x3 &QDynamicRigidBody::inertiaMatrix() const
463{
464 return m_inertiaMatrix;
465}
466
467float QDynamicRigidBody::mass() const
468{
469 return m_mass;
470}
471
472bool QDynamicRigidBody::isKinematic() const
473{
474 return m_isKinematic;
475}
476
477bool QDynamicRigidBody::gravityEnabled() const
478{
479 return m_gravityEnabled;
480}
481
482void QDynamicRigidBody::setMass(float mass)
483{
484 if (mass < 0.f || qFuzzyCompare(m_mass, mass))
485 return;
486
487 switch (m_massMode) {
488 case QDynamicRigidBody::MassMode::Mass:
489 m_commandQueue.enqueue(new QPhysicsCommandSetMass(mass));
490 break;
491 case QDynamicRigidBody::MassMode::MassAndInertiaTensor:
492 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaTensor(mass, m_inertiaTensor));
493 break;
494 case QDynamicRigidBody::MassMode::MassAndInertiaMatrix:
495 m_commandQueue.enqueue(new QPhysicsCommandSetMassAndInertiaMatrix(mass, m_inertiaMatrix));
496 break;
497 case QDynamicRigidBody::MassMode::DefaultDensity:
498 case QDynamicRigidBody::MassMode::CustomDensity:
499 break;
500 }
501
502 m_mass = mass;
503 emit massChanged(m_mass);
504}
505
506float QDynamicRigidBody::density() const
507{
508 return m_density;
509}
510
511void QDynamicRigidBody::setDensity(float density)
512{
513 if (qFuzzyCompare(m_density, density))
514 return;
515
516 if (m_massMode == MassMode::CustomDensity)
517 m_commandQueue.enqueue(new QPhysicsCommandSetDensity(density));
518
519 m_density = density;
520 emit densityChanged(m_density);
521}
522
523void QDynamicRigidBody::setIsKinematic(bool isKinematic)
524{
525 if (m_isKinematic == isKinematic)
526 return;
527
528 if (hasStaticShapes() && !isKinematic) {
529 qWarning()
530 << "Cannot make body containing trimesh/heightfield/plane non-kinematic, ignoring.";
531 return;
532 }
533
534 m_isKinematic = isKinematic;
535 m_commandQueue.enqueue(new QPhysicsCommandSetIsKinematic(m_isKinematic));
536 emit isKinematicChanged(m_isKinematic);
537}
538
539void QDynamicRigidBody::setGravityEnabled(bool gravityEnabled)
540{
541 if (m_gravityEnabled == gravityEnabled)
542 return;
543
544 m_gravityEnabled = gravityEnabled;
545 m_commandQueue.enqueue(new QPhysicsCommandSetGravityEnabled(m_gravityEnabled));
546 emit gravityEnabledChanged();
547}
548
549void QDynamicRigidBody::setAngularVelocity(const QVector3D &angularVelocity)
550{
551 m_commandQueue.enqueue(new QPhysicsCommandSetAngularVelocity(angularVelocity));
552}
553
554QDynamicRigidBody::AxisLock QDynamicRigidBody::linearAxisLock() const
555{
556 return m_linearAxisLock;
557}
558
559void QDynamicRigidBody::setLinearAxisLock(AxisLock newAxisLockLinear)
560{
561 if (m_linearAxisLock == newAxisLockLinear)
562 return;
563 m_linearAxisLock = newAxisLockLinear;
564 emit linearAxisLockChanged();
565}
566
567QDynamicRigidBody::AxisLock QDynamicRigidBody::angularAxisLock() const
568{
569 return m_angularAxisLock;
570}
571
572void QDynamicRigidBody::setAngularAxisLock(AxisLock newAxisLockAngular)
573{
574 if (m_angularAxisLock == newAxisLockAngular)
575 return;
576 m_angularAxisLock = newAxisLockAngular;
577 emit angularAxisLockChanged();
578}
579
580QQueue<QPhysicsCommand *> &QDynamicRigidBody::commandQueue()
581{
582 return m_commandQueue;
583}
584
585void QDynamicRigidBody::updateDefaultDensity(float defaultDensity)
586{
587 if (m_massMode == MassMode::DefaultDensity)
588 m_commandQueue.enqueue(new QPhysicsCommandSetDensity(defaultDensity));
589}
590
591void QDynamicRigidBody::applyCentralForce(const QVector3D &force)
592{
593 m_commandQueue.enqueue(new QPhysicsCommandApplyCentralForce(force));
594}
595
596void QDynamicRigidBody::applyForce(const QVector3D &force, const QVector3D &position)
597{
598 m_commandQueue.enqueue(new QPhysicsCommandApplyForce(force, position));
599}
600
601void QDynamicRigidBody::applyTorque(const QVector3D &torque)
602{
603 m_commandQueue.enqueue(new QPhysicsCommandApplyTorque(torque));
604}
605
606void QDynamicRigidBody::applyCentralImpulse(const QVector3D &impulse)
607{
608 m_commandQueue.enqueue(new QPhysicsCommandApplyCentralImpulse(impulse));
609}
610
611void QDynamicRigidBody::applyImpulse(const QVector3D &impulse, const QVector3D &position)
612{
613 m_commandQueue.enqueue(new QPhysicsCommandApplyImpulse(impulse, position));
614}
615
616void QDynamicRigidBody::applyTorqueImpulse(const QVector3D &impulse)
617{
618 m_commandQueue.enqueue(new QPhysicsCommandApplyTorqueImpulse(impulse));
619}
620
621void QDynamicRigidBody::setLinearVelocity(const QVector3D &linearVelocity)
622{
623 m_commandQueue.enqueue(new QPhysicsCommandSetLinearVelocity(linearVelocity));
624}
625
626void QDynamicRigidBody::reset(const QVector3D &position, const QVector3D &eulerRotation)
627{
628 m_commandQueue.enqueue(new QPhysicsCommandReset(position, eulerRotation));
629}
630
631void QDynamicRigidBody::setKinematicRotation(const QQuaternion &rotation)
632{
633 if (m_kinematicRotation == rotation)
634 return;
635
636 m_kinematicRotation = rotation;
637 emit kinematicRotationChanged(m_kinematicRotation);
638 emit kinematicEulerRotationChanged(m_kinematicRotation.getEulerRotation());
639}
640
641QQuaternion QDynamicRigidBody::kinematicRotation() const
642{
643 return m_kinematicRotation.getQuaternionRotation();
644}
645
646void QDynamicRigidBody::setKinematicEulerRotation(const QVector3D &rotation)
647{
648 if (m_kinematicRotation == rotation)
649 return;
650
651 m_kinematicRotation = rotation;
652 emit kinematicEulerRotationChanged(m_kinematicRotation);
653 emit kinematicRotationChanged(m_kinematicRotation.getQuaternionRotation());
654}
655
656QVector3D QDynamicRigidBody::kinematicEulerRotation() const
657{
658 return m_kinematicRotation.getEulerRotation();
659}
660
661void QDynamicRigidBody::setKinematicPivot(const QVector3D &pivot)
662{
663 m_kinematicPivot = pivot;
664 emit kinematicPivotChanged(m_kinematicPivot);
665}
666
667QVector3D QDynamicRigidBody::kinematicPivot() const
668{
669 return m_kinematicPivot;
670}
671
672bool QDynamicRigidBody::isSleeping() const
673{
674 return m_isSleeping;
675}
676
677void QDynamicRigidBody::setIsSleeping(bool newIsSleeping)
678{
679 if (m_isSleeping == newIsSleeping)
680 return;
681
682 m_isSleeping = newIsSleeping;
683 emit isSleepingChanged(newIsSleeping);
684}
685
686QAbstractPhysXNode *QDynamicRigidBody::createPhysXBackend()
687{
688 return new QPhysXDynamicBody(this);
689}
690
691void QDynamicRigidBody::setKinematicPosition(const QVector3D &position)
692{
693 m_kinematicPosition = position;
694 emit kinematicPositionChanged(m_kinematicPosition);
695}
696
697QVector3D QDynamicRigidBody::kinematicPosition() const
698{
699 return m_kinematicPosition;
700}
701
static bool fuzzyEquals(const QList< float > &a, const QList< float > &b)
#define QT_BEGIN_NAMESPACE
#define QT_END_NAMESPACE