21#include "PxPhysicsAPI.h"
22#include "cooking/PxCooking.h"
24#include <QtQuick3D/private/qquick3dobject_p.h>
25#include <QtQuick3D/private/qquick3dnode_p.h>
26#include <QtQuick3D/private/qquick3dmodel_p.h>
27#include <QtQuick3D/private/qquick3ddefaultmaterial_p.h>
28#include <QtQuick3DUtils/private/qssgutils_p.h>
30#include <QtEnvironmentVariables>
32#define PHYSX_ENABLE_PVD 0
233 constexpr auto MILLIONTH = 0.000001;
237 while (deltaMS < minTimestep) {
238 auto sleepUSecs = (minTimestep - deltaMS) * 1000.f;
244 auto deltaSecs =
qMin(
float(deltaMS), maxTimestep) * 0.001f;
245 m_physx->
scene->simulate(deltaSecs);
246 m_physx->
scene->fetchResults(
true);
255 auto sleepUSecs = 16 * 1000.f;
271void QPhysicsWorld::DebugModelHolder::releaseMeshPointer()
273 if (
auto base =
static_cast<physx::PxBase *
>(ptr);
base)
278const QVector3D &QPhysicsWorld::DebugModelHolder::halfExtents()
const
282void QPhysicsWorld::DebugModelHolder::setHalfExtents(
const QVector3D &halfExtents)
286float QPhysicsWorld::DebugModelHolder::radius()
const
290void QPhysicsWorld::DebugModelHolder::setRadius(
float radius)
294float QPhysicsWorld::DebugModelHolder::heightScale()
const
298void QPhysicsWorld::DebugModelHolder::setHeightScale(
float heightScale)
300 data.setX(heightScale);
302float QPhysicsWorld::DebugModelHolder::halfHeight()
const
306void QPhysicsWorld::DebugModelHolder::setHalfHeight(
float halfHeight)
308 data.setY(halfHeight);
310float QPhysicsWorld::DebugModelHolder::rowScale()
const
314void QPhysicsWorld::DebugModelHolder::setRowScale(
float rowScale)
318float QPhysicsWorld::DebugModelHolder::columnScale()
const
322void QPhysicsWorld::DebugModelHolder::setColumnScale(
float columnScale)
324 data.setZ(columnScale);
326physx::PxConvexMesh *QPhysicsWorld::DebugModelHolder::getConvexMesh()
328 return static_cast<physx::PxConvexMesh *
>(
ptr);
330void QPhysicsWorld::DebugModelHolder::setConvexMesh(physx::PxConvexMesh *mesh)
332 ptr =
static_cast<void *
>(mesh);
334physx::PxTriangleMesh *QPhysicsWorld::DebugModelHolder::getTriangleMesh()
336 return static_cast<physx::PxTriangleMesh *
>(
ptr);
338void QPhysicsWorld::DebugModelHolder::setTriangleMesh(physx::PxTriangleMesh *mesh)
340 ptr =
static_cast<void *
>(mesh);
342physx::PxHeightField *QPhysicsWorld::DebugModelHolder::getHeightField()
344 return static_cast<physx::PxHeightField *
>(
ptr);
346void QPhysicsWorld::DebugModelHolder::setHeightField(physx::PxHeightField *hf)
348 ptr =
static_cast<physx::PxHeightField *
>(hf);
365 world->m_newPhysicsNodes.push_back(physicsNode);
374 world->m_newPhysicsNodes.removeAll(physicsNode);
376 if (physicsNode->m_backendObject) {
377 Q_ASSERT(physicsNode->m_backendObject->frontendNode == physicsNode);
378 physicsNode->m_backendObject->frontendNode =
nullptr;
379 physicsNode->m_backendObject->isRemoved =
true;
380 physicsNode->m_backendObject =
nullptr;
382 world->m_removedPhysicsNodes.insert(physicsNode);
389 const QVector<QVector3D> &impulses,
390 const QVector<QVector3D> &normals)
400 contact.receiver = receiver;
402 contact.impulses = impulses;
403 contact.normals = normals;
420 m_workerThread.
quit();
421 m_workerThread.
wait();
422 for (
auto body : m_physXBodies) {
423 body->cleanup(m_physx);
435 if ((!m_running && !m_inDesignStudio) || m_physicsInitialized)
453 return m_forceDebugDraw;
463 return m_typicalLength;
468 return m_typicalSpeed;
473 return m_removedPhysicsNodes.
contains(
object);
482 if (m_physx->
scene) {
494 if (!m_inDesignStudio) {
495 if (m_running && !m_physicsInitialized)
509 if (!m_forceDebugDraw)
523 m_hasIndividualDebugDraw =
true;
534 for (
auto material : m_debugMaterials)
536 m_debugMaterials.clear();
538 for (
auto &holder : m_collisionShapeDebugModels) {
539 holder.releaseMeshPointer();
542 m_collisionShapeDebugModels.
clear();
544 emit viewportChanged(m_viewport);
547void QPhysicsWorld::setMinimumTimestep(
float minTimestep)
552 if (minTimestep > m_maxTimestep) {
553 qWarning(
"Minimum timestep greater than maximum timestep, value clamped");
554 minTimestep =
qMin(minTimestep, m_maxTimestep);
557 if (minTimestep < 0.f) {
558 qWarning(
"Minimum timestep less than zero, value clamped");
559 minTimestep =
qMax(minTimestep, 0.f);
565 m_minTimestep = minTimestep;
566 emit minimumTimestepChanged(m_minTimestep);
569void QPhysicsWorld::setMaximumTimestep(
float maxTimestep)
574 if (maxTimestep < 0.f) {
575 qWarning(
"Maximum timestep less than zero, value clamped");
576 maxTimestep =
qMax(maxTimestep, 0.f);
582 m_maxTimestep = maxTimestep;
583 emit maximumTimestepChanged(maxTimestep);
586void QPhysicsWorld::setupDebugMaterials(
QQuick3DNode *sceneNode)
588 if (!m_debugMaterials.isEmpty())
591 const int lineWidth = m_inDesignStudio ? 1 : 3;
598 debugMaterial->setLineWidth(lineWidth);
599 debugMaterial->setParentItem(sceneNode);
600 debugMaterial->setParent(sceneNode);
601 debugMaterial->setDiffuseColor(
color);
604 m_debugMaterials.push_back(debugMaterial);
608void QPhysicsWorld::updateDebugDraw()
610 if (!(m_forceDebugDraw || m_hasIndividualDebugDraw)) {
612 for (
auto &holder : m_collisionShapeDebugModels) {
613 holder.releaseMeshPointer();
616 m_collisionShapeDebugModels.
clear();
621 auto sceneNode = m_viewport ? m_viewport : m_scene;
623 if (sceneNode ==
nullptr)
626 setupDebugMaterials(sceneNode);
627 m_hasIndividualDebugDraw =
false;
630 QSet<QPair<QAbstractCollisionShape *, QAbstractPhysXNode *>> currentCollisionShapes;
631 currentCollisionShapes.reserve(m_collisionShapeDebugModels.
size());
634 if (!node->debugGeometryCapability())
637 const auto &collisionShapes = node->frontendNode->getCollisionShapesList();
638 const int materialIdx =
static_cast<int>(node->getDebugDrawBodyType());
639 const int length = collisionShapes.length();
640 for (
int idx = 0; idx <
length; idx++) {
641 const auto collisionShape = collisionShapes[idx];
643 if (!m_forceDebugDraw && !collisionShape->enableDebugDraw())
646 DebugModelHolder &holder =
647 m_collisionShapeDebugModels[std::make_pair(collisionShape, node)];
648 auto &
model = holder.model;
650 currentCollisionShapes.insert(std::make_pair(collisionShape, node));
652 m_hasIndividualDebugDraw =
653 m_hasIndividualDebugDraw || collisionShape->enableDebugDraw();
658 model->setParentItem(sceneNode);
660 model->setCastsShadows(
false);
661 model->setReceivesShadows(
false);
662 model->setCastsReflections(
false);
665 model->setVisible(
true);
668 auto material = m_debugMaterials[materialIdx];
670 if (materialsRef.count() == 0 || materialsRef.at(0) != material) {
671 materialsRef.clear();
672 materialsRef.append(material);
678 if (qobject_cast<QCharacterController *>(node->frontendNode)) {
679 QCapsuleShape *capsuleShape = qobject_cast<QCapsuleShape *>(collisionShape);
683 const float radius = capsuleShape->diameter() * 0.5;
684 const float halfHeight = capsuleShape->height() * 0.5;
689 geom->setParent(
model);
690 model->setGeometry(geom);
691 holder.setRadius(radius);
692 holder.setHalfHeight(halfHeight);
695 model->setPosition(node->frontendNode->scenePosition());
696 model->setRotation(node->frontendNode->sceneRotation()
697 * QQuaternion::fromEulerAngles(0, 0, 90));
701 if (node->shapes.length() <
length)
704 const auto physXShape = node->shapes[idx];
705 auto localPose = physXShape->getLocalPose();
707 switch (physXShape->getGeometryType()) {
708 case physx::PxGeometryType::eBOX: {
709 physx::PxBoxGeometry boxGeometry;
710 physXShape->getBoxGeometry(boxGeometry);
711 const auto &halfExtentsOld = holder.halfExtents();
715 geom->setParent(
model);
716 model->setGeometry(geom);
717 holder.setHalfExtents(halfExtents);
723 case physx::PxGeometryType::eSPHERE: {
724 physx::PxSphereGeometry sphereGeometry;
725 physXShape->getSphereGeometry(sphereGeometry);
726 const float radius = holder.radius();
729 geom->setParent(
model);
730 model->setGeometry(geom);
731 holder.setRadius(sphereGeometry.radius);
736 case physx::PxGeometryType::eCAPSULE: {
737 physx::PxCapsuleGeometry capsuleGeometry;
738 physXShape->getCapsuleGeometry(capsuleGeometry);
739 const float radius = holder.radius();
740 const float halfHeight = holder.halfHeight();
745 capsuleGeometry.radius, capsuleGeometry.halfHeight);
746 geom->setParent(
model);
747 model->setGeometry(geom);
748 holder.setRadius(capsuleGeometry.radius);
749 holder.setHalfHeight(capsuleGeometry.halfHeight);
754 case physx::PxGeometryType::ePLANE:{
755 physx::PxPlaneGeometry planeGeometry;
756 physXShape->getPlaneGeometry(planeGeometry);
762 if (
model->geometry() ==
nullptr) {
764 geom->setParent(
model);
765 model->setGeometry(geom);
773 case physx::PxGeometryType::eHEIGHTFIELD: {
774 physx::PxHeightFieldGeometry heightFieldGeometry;
775 bool success = physXShape->getHeightFieldGeometry(heightFieldGeometry);
777 const float heightScale = holder.heightScale();
778 const float rowScale = holder.rowScale();
779 const float columnScale = holder.columnScale();
781 if (
auto heightField = holder.getHeightField();
782 heightField && heightField != heightFieldGeometry.heightField) {
783 heightField->release();
784 holder.setHeightField(
nullptr);
787 if (!
qFuzzyCompare(heightFieldGeometry.heightScale, heightScale)
789 || !
qFuzzyCompare(heightFieldGeometry.columnScale, columnScale)
790 || !holder.getHeightField()) {
791 if (!holder.getHeightField()) {
792 heightFieldGeometry.heightField->acquireReference();
793 holder.setHeightField(heightFieldGeometry.heightField);
796 heightFieldGeometry.heightField, heightFieldGeometry.heightScale,
797 heightFieldGeometry.rowScale, heightFieldGeometry.columnScale);
798 geom->setParent(
model);
799 model->setGeometry(geom);
800 holder.setHeightScale(heightFieldGeometry.heightScale);
801 holder.setRowScale(heightFieldGeometry.rowScale);
802 holder.setColumnScale(heightFieldGeometry.columnScale);
807 case physx::PxGeometryType::eCONVEXMESH: {
808 physx::PxConvexMeshGeometry convexMeshGeometry;
809 const bool success = physXShape->getConvexMeshGeometry(convexMeshGeometry);
811 const auto rotation = convexMeshGeometry.scale.rotation * localPose.q;
812 localPose = physx::PxTransform(localPose.p, rotation);
815 if (
auto convexMesh = holder.getConvexMesh();
816 convexMesh && convexMesh != convexMeshGeometry.convexMesh) {
817 convexMesh->release();
818 holder.setConvexMesh(
nullptr);
821 if (!
model->geometry() || !holder.getConvexMesh()) {
822 if (!holder.getConvexMesh()) {
823 convexMeshGeometry.convexMesh->acquireReference();
824 holder.setConvexMesh(convexMeshGeometry.convexMesh);
827 convexMeshGeometry.convexMesh);
828 geom->setParent(
model);
829 model->setGeometry(geom);
834 case physx::PxGeometryType::eTRIANGLEMESH: {
835 physx::PxTriangleMeshGeometry triangleMeshGeometry;
836 const bool success = physXShape->getTriangleMeshGeometry(triangleMeshGeometry);
838 const auto rotation = triangleMeshGeometry.scale.rotation * localPose.q;
839 localPose = physx::PxTransform(localPose.p, rotation);
842 if (
auto triangleMesh = holder.getTriangleMesh();
843 triangleMesh && triangleMesh != triangleMeshGeometry.triangleMesh) {
844 triangleMesh->release();
845 holder.setTriangleMesh(
nullptr);
848 if (!
model->geometry() || !holder.getTriangleMesh()) {
849 if (!holder.getTriangleMesh()) {
850 triangleMeshGeometry.triangleMesh->acquireReference();
851 holder.setTriangleMesh(triangleMeshGeometry.triangleMesh);
854 triangleMeshGeometry.triangleMesh);
855 geom->setParent(
model);
856 model->setGeometry(geom);
861 case physx::PxGeometryType::eINVALID:
862 case physx::PxGeometryType::eGEOMETRY_COUNT:
867 auto globalPose = node->getGlobalPose();
868 auto finalPose = globalPose.transform(localPose);
876 m_collisionShapeDebugModels.
removeIf(
877 [&](
QHash<QPair<QAbstractCollisionShape *, QAbstractPhysXNode *>,
878 DebugModelHolder>::iterator
it) {
879 if (!currentCollisionShapes.contains(
it.key())) {
880 auto holder = it.value();
881 holder.releaseMeshPointer();
892 if (
auto shape = qobject_cast<QAbstractPhysicsNode *>(node)) {
893 nodes.push_back(shape);
901void QPhysicsWorld::updateDebugDrawDesignStudio()
904 auto sceneNode = m_viewport ? m_viewport : m_scene;
906 if (sceneNode ==
nullptr)
909 setupDebugMaterials(sceneNode);
912 QSet<QPair<QAbstractCollisionShape *, QAbstractPhysicsNode *>> currentCollisionShapes;
913 currentCollisionShapes.reserve(m_collisionShapeDebugModels.
size());
915 QList<QAbstractPhysicsNode *> activePhysicsNodes;
916 activePhysicsNodes.reserve(m_collisionShapeDebugModels.
size());
921 const auto &collisionShapes = node->getCollisionShapesList();
922 const int materialIdx = 0;
923 const int length = collisionShapes.length();
925 const bool isCharacterController = qobject_cast<QCharacterController *>(node) !=
nullptr;
927 for (
int idx = 0; idx <
length; idx++) {
929 DebugModelHolder &holder =
930 m_DesignStudioDebugModels[std::make_pair(collisionShape, node)];
931 auto &
model = holder.model;
933 currentCollisionShapes.insert(std::make_pair(collisionShape, node));
935 m_hasIndividualDebugDraw =
936 m_hasIndividualDebugDraw || collisionShape->enableDebugDraw();
944 model->setParentItem(sceneNode);
946 model->setCastsShadows(
false);
947 model->setReceivesShadows(
false);
948 model->setCastsReflections(
false);
951 const bool hasGeometry = holder.geometry !=
nullptr;
952 QVector3D scenePosition = collisionShape->scenePosition();
953 QQuaternion sceneRotation = collisionShape->sceneRotation();
956 if (isCharacterController)
957 sceneRotation = sceneRotation * QQuaternion::fromEulerAngles(
QVector3D(0, 0, 90));
960 auto material = m_debugMaterials[materialIdx];
962 if (materialsRef.count() == 0 || materialsRef.at(0) != material) {
963 materialsRef.clear();
964 materialsRef.append(material);
968 if (
auto shape = qobject_cast<QBoxShape *>(collisionShape)) {
969 const auto &halfExtentsOld = holder.halfExtents();
970 const auto halfExtents = shape->sceneScale() * shape->extents() * 0.5f;
971 if (!
qFuzzyCompare(halfExtentsOld, halfExtents) || !hasGeometry) {
973 holder.setHalfExtents(halfExtents);
975 }
else if (
auto shape = qobject_cast<QSphereShape *>(collisionShape)) {
976 const float radiusOld = holder.radius();
977 const float radius = shape->sceneScale().x() * shape->diameter() * 0.5f;
980 holder.setRadius(radius);
982 }
else if (
auto shape = qobject_cast<QCapsuleShape *>(collisionShape)) {
983 const float radiusOld = holder.radius();
984 const float halfHeightOld = holder.halfHeight();
985 const float radius = shape->sceneScale().y() * shape->diameter() * 0.5f;
986 const float halfHeight = shape->sceneScale().x() * shape->height() * 0.5f;
991 holder.setRadius(radius);
992 holder.setHalfHeight(halfHeight);
994 }
else if (qobject_cast<QPlaneShape *>(collisionShape)) {
997 }
else if (
auto shape = qobject_cast<QHeightFieldShape *>(collisionShape)) {
998 physx::PxHeightFieldGeometry *heightFieldGeometry =
999 static_cast<physx::PxHeightFieldGeometry *
>(shape->getPhysXGeometry());
1000 const float heightScale = holder.heightScale();
1001 const float rowScale = holder.rowScale();
1002 const float columnScale = holder.columnScale();
1003 scenePosition += shape->hfOffset();
1004 if (!heightFieldGeometry) {
1005 qWarning() <<
"Could not get height field";
1006 }
else if (!
qFuzzyCompare(heightFieldGeometry->heightScale, heightScale)
1008 || !
qFuzzyCompare(heightFieldGeometry->columnScale, columnScale)
1011 heightFieldGeometry->heightField, heightFieldGeometry->heightScale,
1012 heightFieldGeometry->rowScale, heightFieldGeometry->columnScale);
1013 holder.setHeightScale(heightFieldGeometry->heightScale);
1014 holder.setRowScale(heightFieldGeometry->rowScale);
1015 holder.setColumnScale(heightFieldGeometry->columnScale);
1017 }
else if (
auto shape = qobject_cast<QConvexMeshShape *>(collisionShape)) {
1018 auto convexMeshGeometry =
1019 static_cast<physx::PxConvexMeshGeometry *
>(shape->getPhysXGeometry());
1020 if (!convexMeshGeometry) {
1021 qWarning() <<
"Could not get convex mesh";
1027 convexMeshGeometry->convexMesh);
1030 }
else if (
auto shape = qobject_cast<QTriangleMeshShape *>(collisionShape)) {
1031 physx::PxTriangleMeshGeometry *triangleMeshGeometry =
1032 static_cast<physx::PxTriangleMeshGeometry *
>(shape->getPhysXGeometry());
1033 if (!triangleMeshGeometry) {
1034 qWarning() <<
"Could not get triangle mesh";
1040 triangleMeshGeometry->triangleMesh);
1046 delete holder.geometry;
1047 holder.geometry = newGeometry;
1050 model->setGeometry(holder.geometry);
1051 model->setVisible(
true);
1053 model->setRotation(sceneRotation);
1054 model->setPosition(scenePosition);
1059 m_DesignStudioDebugModels.
removeIf(
1060 [&](
QHash<QPair<QAbstractCollisionShape *, QAbstractPhysicsNode *>,
1061 DebugModelHolder>::iterator
it) {
1062 if (!currentCollisionShapes.contains(
it.key())) {
1063 auto holder = it.value();
1064 holder.releaseMeshPointer();
1066 delete holder.geometry;
1067 delete holder.model;
1075void QPhysicsWorld::disableDebugDraw()
1077 m_hasIndividualDebugDraw =
false;
1080 const auto &collisionShapes = body->frontendNode->getCollisionShapesList();
1081 const int length = collisionShapes.length();
1082 for (
int idx = 0; idx <
length; idx++) {
1083 const auto collisionShape = collisionShapes[idx];
1084 if (collisionShape->enableDebugDraw()) {
1085 m_hasIndividualDebugDraw =
true;
1097 if (m_physicsInitialized) {
1099 <<
"Warning: Changing 'enableCCD' after physics is initialized will have no effect";
1113 qWarning() <<
"Warning: 'typicalLength' value less than zero, ignored";
1117 if (m_physicsInitialized) {
1118 qWarning() <<
"Warning: Changing 'typicalLength' after physics is initialized will have "
1133 if (m_physicsInitialized) {
1134 qWarning() <<
"Warning: Changing 'typicalSpeed' after physics is initialized will have "
1146 return m_defaultDensity;
1151 return m_minTimestep;
1156 return m_maxTimestep;
1167 body->updateDefaultDensity(m_defaultDensity);
1174void QPhysicsWorld::cleanupRemovedNodes()
1181 m_removedPhysicsNodes.
clear();
1184void QPhysicsWorld::initPhysics()
1195 if (m_inDesignStudio) {
1199 &QPhysicsWorld::frameFinishedDesignStudio);
1204 m_workerThread.
start();
1206 m_physicsInitialized =
true;
1209void QPhysicsWorld::frameFinished(
float deltaTime)
1212 emitContactCallbacks();
1213 cleanupRemovedNodes();
1214 for (
auto *node :
std::as_const(m_newPhysicsNodes)) {
1215 auto *body = node->createPhysXBackend();
1216 body->
init(
this, m_physx);
1219 m_newPhysicsNodes.
clear();
1221 QHash<QQuick3DNode *, QMatrix4x4> transformCache;
1224 for (
auto *physXBody :
std::as_const(m_physXBodies)) {
1225 physXBody->markDirtyShapes();
1226 physXBody->rebuildDirtyShapes(
this, m_physx);
1227 physXBody->updateFilters();
1230 physXBody->sync(deltaTime, transformCache);
1237 emit frameDone(deltaTime * 1000);
1240void QPhysicsWorld::frameFinishedDesignStudio()
1244 emitContactCallbacks();
1245 cleanupRemovedNodes();
1247 m_newPhysicsNodes.
clear();
1249 updateDebugDrawDesignStudio();
1257 if (!
world->m_scene) {
1264 if (nodeCurr ==
world->m_scene)
1267 while (nodeCurr->parentNode()) {
1268 nodeCurr = nodeCurr->parentNode();
1269 if (nodeCurr ==
world->m_scene)
1277void QPhysicsWorld::matchOrphanNodes()
1286 while (idx < numNodes) {
1289 if (
world ==
this) {
1290 world->m_newPhysicsNodes.push_back(node);
1292 worldManager.orphanNodes.swapItemsAt(idx, numNodes - 1);
1301void QPhysicsWorld::findPhysicsNodes()
1306 if (m_scene ==
nullptr)
1310 QList<QQuick3DObject *>
children = m_scene->childItems();
1313 if (
auto converted = qobject_cast<QAbstractPhysicsNode *>(
child); converted !=
nullptr) {
1315 if (converted->m_backendObject !=
nullptr) {
1316 qWarning() <<
"Warning: physics node already associated with a backend node.";
1327void QPhysicsWorld::emitContactCallbacks()
1329 for (
const QPhysicsWorld::BodyContact &contact : m_registeredContacts) {
1330 if (m_removedPhysicsNodes.
contains(contact.sender)
1331 || m_removedPhysicsNodes.
contains(contact.receiver))
1333 contact.receiver->registerContact(contact.sender, contact.positions, contact.impulses,
1337 m_registeredContacts.
clear();
1340physx::PxPhysics *QPhysicsWorld::getPhysics()
1345physx::PxCooking *QPhysicsWorld::getCooking()
1366 if (m_scene == newScene)
1372 for (
auto body : m_physXBodies) {
1377 bool sceneOK =
true;
1379 if (
world !=
this &&
world->scene() == newScene) {
1381 qWarning() <<
"Warning: scene already associated with physics world";
1387 emit sceneChanged();
1392 return m_numThreads;
1395void QPhysicsWorld::setNumThreads(
int newNumThreads)
1397 if (m_numThreads == newNumThreads)
1399 m_numThreads = newNumThreads;
1400 emit numThreadsChanged();
1405 return m_reportKinematicKinematicCollisions;
1409 bool newReportKinematicKinematicCollisions)
1411 if (m_reportKinematicKinematicCollisions == newReportKinematicKinematicCollisions)
1413 m_reportKinematicKinematicCollisions = newReportKinematicKinematicCollisions;
1414 emit reportKinematicKinematicCollisionsChanged();
1419 return m_reportStaticKinematicCollisions;
1424 if (m_reportStaticKinematicCollisions == newReportStaticKinematicCollisions)
1426 m_reportStaticKinematicCollisions = newReportStaticKinematicCollisions;
1427 emit reportStaticKinematicCollisionsChanged();
1432#include "qphysicsworld.moc"
QAbstractPhysicsNode * frontendNode
virtual void init(QPhysicsWorld *world, QPhysXWorld *physX)=0
bool cleanupIfRemoved(QPhysXWorld *physX)
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
qint64 nsecsElapsed() const noexcept
qsizetype size() const noexcept
Returns the number of items in the hash.
qsizetype removeIf(Predicate pred)
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
bool empty() const noexcept
void push_back(parameter_type t)
qsizetype removeIf(Predicate pred)
void append(parameter_type t)
const QObjectList & children() const
Returns a list of child objects.
QObject * parent() const
Returns a pointer to the parent object.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
QObject * sender() const
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; othe...
void setParent(QObject *parent)
Makes the object a child of parent.
bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL)
Changes the thread affinity for this object and its children and returns true on success.
void deleteLater()
\threadsafe
void createScene(float typicalLength, float typicalSpeed, const QVector3D &gravity, bool enableCCD, QPhysicsWorld *physicsWorld, unsigned int numThreads)
physx::PxControllerManager * controllerManager
void typicalSpeedChanged(float typicalSpeed)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void classBegin() override
Invoked after class creation, but before any properties have been set.
void setRunning(bool running)
QPhysicsWorld(QObject *parent=nullptr)
bool isNodeRemoved(QAbstractPhysicsNode *object)
void registerContact(QAbstractPhysicsNode *sender, QAbstractPhysicsNode *receiver, const QVector< QVector3D > &positions, const QVector< QVector3D > &impulses, const QVector< QVector3D > &normals)
void setDefaultDensity(float defaultDensity)
void forceDebugDrawChanged(bool forceDebugDraw)
bool reportKinematicKinematicCollisions
static QPhysicsWorld * getWorld(QQuick3DNode *node)
void setHasIndividualDebugDraw()
void enableCCDChanged(bool enableCCD)
void setTypicalLength(float typicalLength)
void runningChanged(bool running)
void setTypicalSpeed(float typicalSpeed)
void setForceDebugDraw(bool forceDebugDraw)
void typicalLengthChanged(float typicalLength)
void setEnableCCD(bool enableCCD)
physx::PxControllerManager * controllerManager()
void setReportStaticKinematicCollisions(bool newReportStaticKinematicCollisions)
void simulateFrame(float minTimestep, float maxTimestep)
void defaultDensityChanged(float defaultDensity)
void setReportKinematicKinematicCollisions(bool newReportKinematicKinematicCollisions)
void setGravity(QVector3D gravity)
static void registerNode(QAbstractPhysicsNode *physicsNode)
bool reportStaticKinematicCollisions
static void deregisterNode(QAbstractPhysicsNode *physicsNode)
void gravityChanged(QVector3D gravity)
The QQmlListReference class allows the manipulation of QQmlListProperty properties.
The QQuaternion class represents a quaternion consisting of a vector and scalar.
\qmltype Geometry \inherits Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DGeometry
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
bool contains(const T &value) const
void start(Priority=InheritPriority)
static int idealThreadCount() noexcept
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
static void usleep(unsigned long)
void finished(QPrivateSignal)
The QVector3D class represents a vector or vertex in 3D space.
void frameDone(float deltaTime)
void frameDoneDesignStudio()
void simulateFrame(float minTimestep, float maxTimestep)
SimulationWorker(QPhysXWorld *physx)
void simulateFrameDesignStudio(float minTimestep, float maxTimestep)
QSet< QString >::iterator it
constexpr QColor lightsalmon
constexpr QColor blueviolet
constexpr QColor chartreuse
QQuick3DGeometry * generateConvexMeshGeometry(physx::PxConvexMesh *convexMesh)
QQuick3DGeometry * generateSphereGeometry(const float radius)
QQuick3DGeometry * generateHeightFieldGeometry(physx::PxHeightField *heightField, float heightScale, float rowScale, float columnScale)
QQuick3DGeometry * generatePlaneGeometry()
QQuick3DGeometry * generateBoxGeometry(const QVector3D &halfExtents)
QQuick3DGeometry * generateCapsuleGeometry(const float radius, const float halfHeight)
QQuick3DGeometry * generateTriangleMeshGeometry(physx::PxTriangleMesh *triangleMesh)
Q_ALWAYS_INLINE physx::PxVec3 toPhysXType(const QVector3D &qvec)
const QQuaternion kMinus90YawRotation
Q_ALWAYS_INLINE QVector3D toQtType(const physx::PxVec3 &vec)
Combined button and popup list for selecting options.
static const QCssKnownValue positions[NumKnownPositionModes - 1]
static Q_CONSTINIT QBasicAtomicInt running
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
static QWorldManager worldManager
static void collectPhysicsNodes(QQuick3DObject *node, QList< QAbstractPhysicsNode * > &nodes)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
QSqlQueryModel * model
[16]
view viewport() -> scroll(dx, dy, deviceRect)
QLatin1StringView world("world")
QVector< QAbstractPhysicsNode * > orphanNodes
QVector< QPhysicsWorld * > worlds
static StaticPhysXObjects & getReference()