Revision control
Copy as Markdown
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#ifndef PHYSICSWORLD_H
#define PHYSICSWORLD_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtQuick3DPhysics/qtquick3dphysicsglobal.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/QObject>
#include <QtCore/QTimerEvent>
#include <QtCore/QElapsedTimer>
#include <QtCore/QSpan>
#include <QtGui/QVector3D>
#include <QtQml/qqml.h>
#include <QBasicTimer>
#include <QtQuick3DPhysics/private/qquick3dphysicslocationhit_p.h>
#include <QtQuick3D/private/qquick3dviewport_p.h>
namespace physx {
class PxMaterial;
class PxPhysics;
class PxShape;
class PxRigidDynamic;
class PxRigidActor;
class PxRigidStatic;
struct PxCookingParams;
class PxControllerManager;
class PxConvexMesh;
class PxTriangleMesh;
class PxHeightField;
class PxJoint;
}
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQuick3dPhysics);
class QAbstractPhysicsNode;
class QAbstractCollisionShape;
class QAbstractRigidBody;
class QAbstractPhysXNode;
class QQuick3DModel;
class QQuick3DGeometry;
class QQuick3DPrincipledMaterial;
class QPhysXWorld;
class FrameAnimator;
class QPhysicsJoint;
class QRaycaster;
class Q_QUICK3DPHYSICS_EXPORT QPhysicsWorld : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QVector3D gravity READ gravity WRITE setGravity NOTIFY gravityChanged)
Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged)
Q_PROPERTY(bool forceDebugDraw READ forceDebugDraw WRITE setForceDebugDraw NOTIFY
forceDebugDrawChanged)
Q_PROPERTY(bool enableCCD READ enableCCD WRITE setEnableCCD NOTIFY enableCCDChanged)
Q_PROPERTY(float typicalLength READ typicalLength WRITE setTypicalLength NOTIFY
typicalLengthChanged)
Q_PROPERTY(
float typicalSpeed READ typicalSpeed WRITE setTypicalSpeed NOTIFY typicalSpeedChanged)
Q_PROPERTY(float defaultDensity READ defaultDensity WRITE setDefaultDensity NOTIFY
defaultDensityChanged)
Q_PROPERTY(QQuick3DNode *viewport READ viewport WRITE setViewport NOTIFY viewportChanged
REVISION(6, 5))
Q_PROPERTY(float minimumTimestep READ minimumTimestep WRITE setMinimumTimestep NOTIFY
minimumTimestepChanged REVISION(6, 5))
Q_PROPERTY(float maximumTimestep READ maximumTimestep WRITE setMaximumTimestep NOTIFY
maximumTimestepChanged REVISION(6, 5))
Q_PROPERTY(QQuick3DNode *scene READ scene WRITE setScene NOTIFY sceneChanged REVISION(6, 5))
Q_PROPERTY(int numThreads READ numThreads WRITE setNumThreads NOTIFY numThreadsChanged
REVISION(6, 7))
Q_PROPERTY(bool reportKinematicKinematicCollisions READ reportKinematicKinematicCollisions WRITE
setReportKinematicKinematicCollisions NOTIFY
reportKinematicKinematicCollisionsChanged FINAL REVISION(6, 7))
Q_PROPERTY(bool reportStaticKinematicCollisions READ reportStaticKinematicCollisions WRITE
setReportStaticKinematicCollisions NOTIFY
reportStaticKinematicCollisionsChanged FINAL REVISION(6, 7))
Q_PROPERTY(QueryStructure staticQueryStructure READ staticQueryStructure WRITE
setStaticQueryStructure NOTIFY staticQueryStructureChanged FINAL REVISION(6, 13))
Q_PROPERTY(QueryStructure dynamicQueryStructure READ dynamicQueryStructure WRITE
setDynamicQueryStructure NOTIFY dynamicQueryStructureChanged FINAL REVISION(6, 13))
QML_NAMED_ELEMENT(PhysicsWorld)
public:
enum class QueryStructure {
NoStructure, // eNONE
StaticTree, // eSTATIC_AABB_TREE
DynamicTree // eDYNAMIC_AABB_TREE
};
Q_ENUM(QueryStructure)
explicit QPhysicsWorld(QObject *parent = nullptr);
~QPhysicsWorld();
void classBegin() override;
void componentComplete() override;
QVector3D gravity() const;
bool running() const;
bool forceDebugDraw() const;
bool enableCCD() const;
float typicalLength() const;
float typicalSpeed() const;
float defaultDensity() const;
Q_REVISION(6, 5) float minimumTimestep() const;
Q_REVISION(6, 5) float maximumTimestep() const;
bool isNodeRemoved(QAbstractPhysicsNode *object);
static QPhysicsWorld *getWorld(QQuick3DNode *node);
static QPhysicsWorld *getWorld(QPhysicsJoint *joint);
static void registerNode(QAbstractPhysicsNode *physicsNode);
static void deregisterNode(QAbstractPhysicsNode *physicsNode);
static void registerJoint(QPhysicsJoint *joint);
static void deregisterJoint(QPhysicsJoint *joint);
void registerContact(QAbstractPhysicsNode *sender, QAbstractPhysicsNode *receiver,
const QVector<QVector3D> &positions, const QVector<QVector3D> &impulses,
const QVector<QVector3D> &normals);
Q_REVISION(6, 5) QQuick3DNode *viewport() const;
void setHasIndividualDebugDraw();
physx::PxControllerManager *controllerManager();
Q_REVISION(6, 5) QQuick3DNode *scene() const;
Q_REVISION(6, 7) int numThreads() const;
Q_REVISION(6, 7) bool reportKinematicKinematicCollisions() const;
Q_REVISION(6, 7)
void setReportKinematicKinematicCollisions(bool newReportKinematicKinematicCollisions);
Q_REVISION(6, 7) bool reportStaticKinematicCollisions() const;
Q_REVISION(6, 7)
void setReportStaticKinematicCollisions(bool newReportStaticKinematicCollisions);
void cleanupRemovedJoints();
Q_REVISION(6, 13) QueryStructure staticQueryStructure() const;
Q_REVISION(6, 13) void setStaticQueryStructure(QueryStructure newStaticQueryStructure);
Q_REVISION(6, 13) QueryStructure dynamicQueryStructure() const;
Q_REVISION(6, 13) void setDynamicQueryStructure(QueryStructure newDynamicQueryStructure);
Q_REVISION(6, 13) Q_INVOKABLE bool testRaycastQuery(const QVector3D &origin,
const QVector3D &direction,
float maxDistance,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE QQuick3DPhysicsLocationHit singleRaycastQuery(const QVector3D &origin,
const QVector3D &direction,
float maxDistance,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE QList<QQuick3DPhysicsLocationHit> multiRaycastQuery(const QVector3D &origin,
const QVector3D &direction,
float maxDistance,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE bool testSweepQuery(QAbstractCollisionShape *shape,
const QVector3D &direction,
float maxDistance,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE QQuick3DPhysicsLocationHit singleSweepQuery(QAbstractCollisionShape *shape,
const QVector3D &direction,
float maxDistance,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE QList<QQuick3DPhysicsLocationHit> multiSweepQuery(QAbstractCollisionShape *shape,
const QVector3D &direction,
float maxDistance,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE bool testOverlapQuery(QAbstractCollisionShape *shape,
bool includeStatic = true,
bool includeDynamic = true) const;
Q_REVISION(6, 13) Q_INVOKABLE QList<QQuick3DPhysicsQueryHit> multiOverlapQuery(QAbstractCollisionShape *shape,
bool includeStatic = true,
bool includeDynamic = true) const;
public slots:
void setGravity(QVector3D gravity);
void setRunning(bool running);
void setForceDebugDraw(bool forceDebugDraw);
void setEnableCCD(bool enableCCD);
void setTypicalLength(float typicalLength);
void setTypicalSpeed(float typicalSpeed);
void setDefaultDensity(float defaultDensity);
Q_REVISION(6, 5) void setViewport(QQuick3DNode *viewport);
Q_REVISION(6, 5) void setMinimumTimestep(float minTimestep);
Q_REVISION(6, 5) void setMaximumTimestep(float maxTimestep);
Q_REVISION(6, 5) void setScene(QQuick3DNode *newScene);
Q_REVISION(6, 7) void setNumThreads(int newNumThreads);
signals:
void gravityChanged(QVector3D gravity);
void runningChanged(bool running);
void enableCCDChanged(bool enableCCD);
void forceDebugDrawChanged(bool forceDebugDraw);
void typicalLengthChanged(float typicalLength);
void typicalSpeedChanged(float typicalSpeed);
void defaultDensityChanged(float defaultDensity);
Q_REVISION(6, 5) void viewportChanged(QQuick3DNode *viewport);
Q_REVISION(6, 5) void minimumTimestepChanged(float minimumTimestep);
Q_REVISION(6, 5) void maximumTimestepChanged(float maxTimestep);
Q_REVISION(6, 5) void frameDone(float timestep);
Q_REVISION(6, 5) void sceneChanged();
Q_REVISION(6, 7) void numThreadsChanged();
Q_REVISION(6, 7) void reportKinematicKinematicCollisionsChanged();
Q_REVISION(6, 7) void reportStaticKinematicCollisionsChanged();
Q_REVISION(6, 13) void staticQueryStructureChanged();
Q_REVISION(6, 13) void dynamicQueryStructureChanged();
private:
static void registerRaycaster(QRaycaster *raycaster);
static void deregisterRaycaster(QRaycaster *raycaster);
QQuick3DPhysicsLocationHit
closestRaycastHit(const QVector3D &origin, const QVector3D &direction, float maxDistance,
bool includeStatic, bool includeDynamic,
QSpan<const QAbstractPhysicsNode *const> excludedBodies) const;
void simulateFrame();
void frameFinished(float deltaTime);
void frameFinishedDesignStudio();
void initPhysics();
void invalidateTriggerOverlaps(QSpan<QAbstractPhysXNode *const> rebuiltBodies);
void dropUnreportedTriggerOverlaps();
void cleanupRemovedNodes();
void updateDebugDraw();
void updateDebugDrawDesignStudio();
void setupDebugMaterials(QQuick3DNode *sceneNode);
void disableDebugDraw();
void matchOrphanNodes();
void matchOrphanJoints();
void matchOrphanRaycasters();
void findPhysicsNodes();
void emitContactCallbacks();
struct BodyContact
{
QAbstractPhysicsNode *sender = nullptr;
QAbstractPhysicsNode *receiver = nullptr;
QVector<QVector3D> positions;
QVector<QVector3D> impulses;
QVector<QVector3D> normals;
};
struct DebugModelHolder
{
QQuick3DModel *model = nullptr;
QQuick3DGeometry *geometry = nullptr;
QVector3D data;
void *ptr = nullptr;
void releaseMeshPointer();
const QVector3D &halfExtents() const;
void setHalfExtents(const QVector3D &halfExtents);
float radius() const;
void setRadius(float radius);
float heightScale() const;
void setHeightScale(float heightScale);
float halfHeight() const;
void setHalfHeight(float halfHeight);
float rowScale() const;
void setRowScale(float rowScale);
float columnScale() const;
void setColumnScale(float columnScale);
physx::PxConvexMesh *getConvexMesh();
void setConvexMesh(physx::PxConvexMesh *mesh);
physx::PxTriangleMesh *getTriangleMesh();
void setTriangleMesh(physx::PxTriangleMesh *mesh);
physx::PxHeightField *getHeightField();
void setHeightField(physx::PxHeightField *hf);
};
QList<QAbstractPhysXNode *> m_physXBodies;
QList<QPhysicsJoint *> m_joints;
QList<QRaycaster *> m_raycasters;
QList<QAbstractPhysicsNode *> m_newPhysicsNodes;
QHash<QPair<QAbstractCollisionShape *, QAbstractPhysicsNode *>, DebugModelHolder>
m_DesignStudioDebugModels;
QHash<QPair<QAbstractCollisionShape *, QAbstractPhysXNode *>, DebugModelHolder>
m_collisionShapeDebugModels;
QSet<QAbstractPhysicsNode *> m_removedPhysicsNodes;
QSet<physx::PxJoint *> m_removedJoints;
// Whether any trigger is holding shape pairs that are waiting to be reported
// again after the shapes on one side of them were replaced.
bool m_triggerOverlapsInvalidated = false;
QList<BodyContact> m_registeredContacts;
QVector3D m_gravity = QVector3D(0.f, -981.f, 0.f);
float m_typicalLength = 100.f; // 100 cm
float m_typicalSpeed = 1000.f; // 1000 cm/s
float m_defaultDensity = 0.001f; // 1 g/cm^3
float m_minTimestep = 1.0f; // 1000 fps
float m_maxTimestep = 33.333f; // 30 fps
bool m_running = true;
bool m_forceDebugDraw = false;
// For performance, used to keep track if we have indiviually enabled debug drawing for any
// collision shape
bool m_hasIndividualDebugDraw = false;
bool m_physicsInitialized = false;
bool m_enableCCD = false;
QPhysXWorld *m_physx = nullptr;
QQuick3DNode *m_viewport = nullptr;
QVector<QQuick3DPrincipledMaterial *> m_debugMaterials;
friend class QQuick3DPhysicsMesh; // TODO: better internal API
friend class QTriangleMeshShape; //####
friend class QHeightFieldShape;
friend class QQuick3DPhysicsHeightField;
friend class SimulationEventCallback;
friend class ControllerCallback;
static physx::PxPhysics *getPhysics();
static const physx::PxCookingParams *getCookingParams();
FrameAnimator *m_frameAnimator = nullptr;
QQuick3DNode *m_scene = nullptr;
bool m_inDesignStudio = false;
int m_numThreads = -1;
bool m_reportKinematicKinematicCollisions = false;
bool m_reportStaticKinematicCollisions = false;
QElapsedTimer m_timer;
float m_currTimeStep = 0.f;
QList<float> m_frameTimings;
bool m_frameFetched = false;
QueryStructure m_staticQueryStructure = QueryStructure::DynamicTree;
QueryStructure m_dynamicQueryStructure = QueryStructure::DynamicTree;
friend class QRaycaster;
};
QT_END_NAMESPACE
#endif // PHYSICSWORLD_H