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