15#include "PxPhysicsAPI.h"
19#include "cooking/PxCooking.h"
21#include "extensions/PxDefaultCpuDispatcher.h"
23#include <QtQuick3D/private/qquick3dobject_p.h>
24#include <QtQuick3D/private/qquick3dnode_p.h>
25#include <QtQuick3D/private/qquick3dmodel_p.h>
26#include <QtQuick3D/private/qquick3ddefaultmaterial_p.h>
27#include <QtQuick3DUtils/private/qssgutils_p.h>
29#define PHYSX_ENABLE_PVD 0
148static inline bool fuzzyEquals(
const physx::PxTransform &
a,
const physx::PxTransform &
b)
177 if (qobject_cast<const QPlaneShape *>(node) !=
nullptr) {
182 }
else if (
auto *hf = qobject_cast<const QHeightFieldShape *>(node)) {
195static physx::PxFilterFlags
197 physx::PxFilterData ,
198 physx::PxFilterObjectAttributes ,
199 physx::PxFilterData , physx::PxPairFlags &pairFlags,
200 const void * , physx::PxU32 )
203 const auto defaultCollisonFlags =
204 physx::PxPairFlag::eSOLVE_CONTACT | physx::PxPairFlag::eDETECT_DISCRETE_CONTACT;
207 const auto notifyTouchFlags =
208 physx::PxPairFlag::eNOTIFY_TOUCH_FOUND | physx::PxPairFlag::eNOTIFY_TOUCH_LOST;
211 const auto notifyContactFlags = physx::PxPairFlag::eNOTIFY_CONTACT_POINTS;
213 pairFlags = defaultCollisonFlags | notifyTouchFlags | notifyContactFlags;
214 return physx::PxFilterFlag::eDEFAULT;
217static physx::PxFilterFlags
219 physx::PxFilterData ,
220 physx::PxFilterObjectAttributes ,
221 physx::PxFilterData , physx::PxPairFlags &pairFlags,
222 const void * , physx::PxU32 )
225 const auto defaultCollisonFlags = physx::PxPairFlag::eSOLVE_CONTACT
226 | physx::PxPairFlag::eDETECT_DISCRETE_CONTACT | physx::PxPairFlag::eDETECT_CCD_CONTACT;
229 const auto notifyTouchFlags =
230 physx::PxPairFlag::eNOTIFY_TOUCH_FOUND | physx::PxPairFlag::eNOTIFY_TOUCH_LOST;
233 const auto notifyContactFlags = physx::PxPairFlag::eNOTIFY_CONTACT_POINTS;
235 pairFlags = defaultCollisonFlags | notifyTouchFlags | notifyContactFlags;
236 return physx::PxFilterFlag::eDEFAULT;
247 QMutexLocker locker(&world->m_removedPhysicsNodesMutex);
249 for (physx::PxU32
i = 0;
i <
count;
i++) {
252 & (physx::PxTriggerPairFlag::eREMOVED_SHAPE_TRIGGER
253 | physx::PxTriggerPairFlag::eREMOVED_SHAPE_OTHER))
257 static_cast<QTriggerBody *
>(pairs[
i].triggerActor->userData);
262 if (!triggerNode || !otherNode) {
263 qWarning() <<
"QtQuick3DPhysics internal error: null pointer in trigger collision.";
270 if (pairs->status == physx::PxPairFlag::eNOTIFY_TOUCH_FOUND) {
275 emit otherNode->enteredTriggerBody(triggerNode);
277 }
else if (pairs->status == physx::PxPairFlag::eNOTIFY_TOUCH_LOST) {
282 emit otherNode->exitedTriggerBody(triggerNode);
289 physx::PxU32 )
override {};
290 void onWake(physx::PxActor ** , physx::PxU32 )
override {};
291 void onSleep(physx::PxActor ** , physx::PxU32 )
override {};
292 void onContact(
const physx::PxContactPairHeader &pairHeader,
const physx::PxContactPair *pairs,
293 physx::PxU32 nbPairs)
override
295 QMutexLocker locker(&world->m_removedPhysicsNodesMutex);
296 constexpr physx::PxU32 bufferSize = 64;
297 physx::PxContactPairPoint contacts[bufferSize];
299 for (physx::PxU32
i = 0;
i < nbPairs;
i++) {
300 const physx::PxContactPair &contactPair = pairs[
i];
302 if (contactPair.events & physx::PxPairFlag::eNOTIFY_TOUCH_FOUND) {
308 if (!trigger || !
other || !trigger->m_backendObject || !
other->m_backendObject
312 const bool triggerReceive =
314 const bool otherReceive =
317 if (!triggerReceive && !otherReceive)
320 physx::PxU32 nbContacts = pairs[
i].extractContacts(contacts, bufferSize);
330 for (physx::PxU32
j = 0;
j < nbContacts;
j++) {
331 physx::PxVec3
position = contacts[
j].position;
332 physx::PxVec3 impulse = contacts[
j].impulse;
333 physx::PxVec3 normal = contacts[
j].normal;
349 other->registerContact(trigger,
positions, impulses, normalsInverted);
354 const physx::PxTransform * ,
355 const physx::PxU32 )
override {};
366 void onShapeHit(
const physx::PxControllerShapeHit &hit)
override
368 QMutexLocker locker(&world->m_removedPhysicsNodesMutex);
390#define PHYSX_RELEASE(x) \
391 if (x != nullptr) { \
401 physx::PxPvd *
pvd =
nullptr;
426 qFatal(
"PxCreateFoundation failed!");
431 s_physx.
pvd = PxCreatePvd(*m_physx->foundation);
432 s_physx.
transport = physx::PxDefaultPvdSocketTransportCreate(
"qt", 5425, 10);
433 s_physx.
pvd->connect(*m_physx->transport, physx::PxPvdInstrumentationFlag::eALL);
438 physx::PxCookingParams(physx::PxTolerancesScale()));
470 qWarning() <<
"Scene already created";
474 physx::PxTolerancesScale
scale;
475 scale.length = typicalLength;
476 scale.speed = typicalSpeed;
479 constexpr bool recordMemoryAllocations =
true;
483 qFatal(
"PxCreatePhysics failed!");
490 physx::PxSceneDesc sceneDesc(
scale);
496 sceneDesc.flags |= physx::PxSceneFlag::eENABLE_CCD;
500 sceneDesc.solverType = physx::PxSolverType::eTGS;
501 sceneDesc.simulationEventCallback =
callback;
527 node->m_backendObject =
this;
543 for (
auto *shape :
shapes)
587 physx::PxCapsuleController *controller =
nullptr;
613 physx::PxRigidActor *
actor =
nullptr;
660 if (
auto *rigidBody = qobject_cast<QDynamicRigidBody *>(node))
662 if (
auto *staticBody = qobject_cast<QStaticRigidBody *>(node))
664 if (
auto *triggerBody = qobject_cast<QTriggerBody *>(node))
666 if (
auto *controller = qobject_cast<QCharacterController *>(node))
740 delete reportCallback;
741 reportCallback =
nullptr;
751 auto shapes = characterController->getCollisionShapesList();
752 if (
shapes.length() != 1) {
753 qWarning() <<
"CharacterController: invalid collision shapes list.";
756 auto *capsule = qobject_cast<QCapsuleShape *>(
shapes.first());
758 qWarning() <<
"CharacterController: collision shape is not a capsule.";
761 auto *mgr =
world->controllerManager();
763 qWarning() <<
"QtQuick3DPhysics internal error: missing controller manager.";
772 physx::PxCapsuleControllerDesc
desc;
774 desc.reportCallback = reportCallback;
776 desc.height = heightScale * capsule->height();
777 desc.stepOffset = 0.25f *
desc.height;
780 const QVector3D pos = characterController->scenePosition();
784 controller =
static_cast<physx::PxCapsuleController *
>(mgr->createController(
desc));
787 qWarning() <<
"QtQuick3DPhysics internal error: could not create controller.";
791 controller->setUserData(
static_cast<void *
>(
frontendNode));
793 auto *actor = controller->getActor();
795 actor->userData = characterController;
797 qWarning() <<
"QtQuick3DPhysics internal error: CharacterController created without actor.";
808 auto dynamicActor =
static_cast<physx::PxRigidDynamic *
>(
actor);
823 const auto &physXShapes =
shapes;
825 const int len = collisionShapes.size();
826 if (physXShapes.size() !=
len) {
831 for (
int i = 0;
i <
len;
i++) {
833 auto poseOld = physXShapes[
i]->getLocalPose();
847 for (
auto *shape :
shapes) {
848 body->detachShape(*shape);
858 auto *geom = collisionShape->getPhysXGeometry();
864 physXShape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE,
false);
865 physXShape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE,
true);
868 shapes.push_back(physXShape);
870 body->attachShape(*physXShape);
905 const float mass =
qMax(drb->
mass(), 0.f);
910 const float mass =
qMax(drb->
mass(), 0.f);
915 const float mass =
qMax(drb->
mass(), 0.f);
924 qWarning() <<
"Cannot make body containing trimesh/heightfield/plane non-kinematic, "
925 "forcing kinematic.";
929 auto *dynamicBody =
static_cast<physx::PxRigidDynamic *
>(
actor);
930 dynamicBody->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, drb->
isKinematic());
933 dynamicBody->setRigidBodyFlag(physx::PxRigidBodyFlag::eENABLE_CCD,
true);
941 for (
auto command : commandQueue) {
942 command->execute(rigidBody, body);
946 commandQueue.
clear();
954 return transformCache[node];
959 if (
auto drb = qobject_cast<const QDynamicRigidBody *>(node); drb !=
nullptr) {
960 if (!drb->isKinematic()) {
961 qWarning() <<
"Non-kinematic body as a parent of a kinematic body is unsupported";
964 drb->kinematicPosition(), drb->scale(), drb->kinematicPivot(), drb->kinematicRotation());
972 return localTransform;
987 ? physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_X
990 ? physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Y
993 ? physx::PxRigidDynamicLockFlag::eLOCK_ANGULAR_Z
996 ? physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_X
999 ? physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Y
1002 ? physx::PxRigidDynamicLockFlag::eLOCK_LINEAR_Z
1004 return static_cast<physx::PxRigidDynamicLockFlags
>(
flags);
1008 physx::PxMaterial *physXMaterial)
1012 const float restitution = qtMaterial->
restitution();
1013 if (physXMaterial->getStaticFriction() != staticFriction)
1014 physXMaterial->setStaticFriction(staticFriction);
1015 if (physXMaterial->getDynamicFriction() != dynamicFriction)
1016 physXMaterial->setDynamicFriction(dynamicFriction);
1017 if (physXMaterial->getRestitution() != restitution)
1018 physXMaterial->setRestitution(restitution);
1046 auto *dynamicActor =
static_cast<physx::PxRigidDynamic *
>(
actor);
1048 if (dynamicRigidBody->isKinematic()) {
1055 dynamicActor->setRigidDynamicLockFlags(
getLockFlags(dynamicRigidBody));
1063 if (controller ==
nullptr)
1069 const auto &
shapes = characterController->getCollisionShapesList();
1070 auto capsule =
shapes.length() == 1 ? qobject_cast<QCapsuleShape *>(
shapes.front()) :
nullptr;
1072 if (
shapes.length() != 1) {
1073 qWarning() <<
"CharacterController: invalid collision shapes list.";
1074 }
else if (!capsule) {
1075 qWarning() <<
"CharacterController: collision shape is not a capsule.";
1077 const QVector3D sceneScale = characterController->sceneScale();
1078 const qreal heightScale = sceneScale.
y();
1082 const float heightNew = heightScale * capsule->height();
1084 controller->resize(heightNew);
1086 const float radiusNew = 0.5f *
radiusScale * capsule->diameter();
1088 controller->setRadius(radiusNew);
1090 const float stepOffsetNew = 0.25f * heightNew;
1091 if (!
qFuzzyCompare(controller->getStepOffset(), stepOffsetNew))
1092 controller->setStepOffset(stepOffsetNew);
1106 bool teleport = characterController->getTeleport(teleportPos);
1108 controller->setPosition({ teleportPos.
x(), teleportPos.
y(), teleportPos.
z() });
1109 }
else if (deltaTime > 0) {
1112 controller->move(displacement, displacement.magnitude() / 100, deltaTime, {});
1113 characterController->setCollisions(QCharacterController::Collisions(
uint(collisions)));
1129 const physx::PxTransform poseOld =
actor->getGlobalPose();
1133 actor->setGlobalPose(poseNew);
1155 constexpr auto MILLIONTH = 0.000001;
1159 while (deltaMS < minTimestep) {
1160 auto sleepUSecs = (minTimestep - deltaMS) * 1000.f;
1166 auto deltaSecs =
qMin(
float(deltaMS), maxTimestep) * 0.001f;
1167 m_physx->
scene->simulate(deltaSecs);
1168 m_physx->
scene->fetchResults(
true);
1195 world->m_newPhysicsNodes.push_back(physicsNode);
1204 world->m_newPhysicsNodes.removeAll(physicsNode);
1205 if (physicsNode->m_backendObject) {
1206 physicsNode->m_backendObject->
isRemoved =
true;
1207 physicsNode->m_backendObject =
nullptr;
1210 world->m_removedPhysicsNodes.insert(physicsNode);
1226 m_workerThread.
quit();
1227 m_workerThread.
wait();
1228 for (
auto body : m_physXBodies) {
1229 body->cleanup(m_physx);
1241 if (!m_running || m_physicsInitialized)
1259 return m_forceDebugDraw;
1269 return m_typicalLength;
1274 return m_typicalSpeed;
1279 return m_removedPhysicsNodes.
contains(
object);
1288 if (m_physx->
scene) {
1300 if (m_running && !m_physicsInitialized)
1313 if (!m_forceDebugDraw)
1327 m_hasIndividualDebugDraw =
true;
1338 for (
auto material : m_debugMaterials)
1340 m_debugMaterials.clear();
1342 for (
auto &holder : m_collisionShapeDebugModels) {
1343 delete holder.model;
1345 m_collisionShapeDebugModels.
clear();
1347 emit viewportChanged(m_viewport);
1350void QPhysicsWorld::setMinimumTimestep(
float minTimestep)
1355 if (minTimestep > m_maxTimestep) {
1356 qWarning(
"Minimum timestep greater than maximum timestep, value clamped");
1357 minTimestep =
qMin(minTimestep, m_maxTimestep);
1360 if (minTimestep < 0.f) {
1361 qWarning(
"Minimum timestep less than zero, value clamped");
1362 minTimestep =
qMax(minTimestep, 0.f);
1368 m_minTimestep = minTimestep;
1369 emit minimumTimestepChanged(m_minTimestep);
1372void QPhysicsWorld::setMaximumTimestep(
float maxTimestep)
1377 if (maxTimestep < 0.f) {
1378 qWarning(
"Maximum timestep less than zero, value clamped");
1379 maxTimestep =
qMax(maxTimestep, 0.f);
1385 m_maxTimestep = maxTimestep;
1386 emit maximumTimestepChanged(maxTimestep);
1389void QPhysicsWorld::updateDebugDraw()
1391 if (!(m_forceDebugDraw || m_hasIndividualDebugDraw)) {
1393 if (!m_collisionShapeDebugModels.
isEmpty()) {
1394 for (
const auto& holder :
std::as_const(m_collisionShapeDebugModels))
1396 m_collisionShapeDebugModels.
clear();
1402 auto sceneNode = m_viewport ? m_viewport : m_scene;
1404 if (sceneNode ==
nullptr)
1407 if (m_debugMaterials.isEmpty()) {
1413 debugMaterial->setLineWidth(3);
1414 debugMaterial->setParentItem(sceneNode);
1415 debugMaterial->setParent(sceneNode);
1416 debugMaterial->setDiffuseColor(
color);
1419 m_debugMaterials.push_back(debugMaterial);
1423 m_hasIndividualDebugDraw =
false;
1427 currentCollisionShapes.
reserve(m_collisionShapeDebugModels.
size());
1430 if (!node->debugGeometryCapability())
1433 const auto &collisionShapes = node->frontendNode->getCollisionShapesList();
1434 const int materialIdx =
static_cast<int>(node->getDebugDrawBodyType());
1435 const int length = collisionShapes.length();
1436 if (node->shapes.length() <
length)
1438 for (
int idx = 0; idx <
length; idx++) {
1439 const auto collisionShape = collisionShapes[idx];
1441 if (!m_forceDebugDraw && !collisionShape->enableDebugDraw())
1444 const auto physXShape = node->shapes[idx];
1445 DebugModelHolder &
holder =
1446 m_collisionShapeDebugModels[std::make_pair(collisionShape, node)];
1449 currentCollisionShapes.
insert(std::make_pair(collisionShape, node));
1451 m_hasIndividualDebugDraw =
1452 m_hasIndividualDebugDraw || collisionShape->enableDebugDraw();
1454 auto localPose = physXShape->getLocalPose();
1459 model->setParentItem(sceneNode);
1461 model->setCastsShadows(
false);
1462 model->setReceivesShadows(
false);
1463 model->setCastsReflections(
false);
1467 auto material = m_debugMaterials[materialIdx];
1469 if (materialsRef.count() == 0 || materialsRef.at(0) != material) {
1470 materialsRef.clear();
1471 materialsRef.append(material);
1475 switch (physXShape->getGeometryType()) {
1476 case physx::PxGeometryType::eBOX: {
1477 physx::PxBoxGeometry boxGeometry;
1478 physXShape->getBoxGeometry(boxGeometry);
1479 const auto &halfExtentsOld =
holder.halfExtents();
1483 geom->setParent(
model);
1484 model->setGeometry(geom);
1485 holder.setHalfExtents(halfExtents);
1491 case physx::PxGeometryType::eSPHERE: {
1492 physx::PxSphereGeometry sphereGeometry;
1493 physXShape->getSphereGeometry(sphereGeometry);
1494 const float radius =
holder.radius();
1497 geom->setParent(
model);
1498 model->setGeometry(geom);
1499 holder.setRadius(sphereGeometry.radius);
1504 case physx::PxGeometryType::eCAPSULE: {
1505 physx::PxCapsuleGeometry capsuleGeometry;
1506 physXShape->getCapsuleGeometry(capsuleGeometry);
1507 const float radius =
holder.radius();
1508 const float halfHeight =
holder.halfHeight();
1511 || !
qFuzzyCompare(capsuleGeometry.halfHeight, halfHeight)) {
1513 capsuleGeometry.radius, capsuleGeometry.halfHeight);
1514 geom->setParent(
model);
1515 model->setGeometry(geom);
1516 holder.setRadius(capsuleGeometry.radius);
1517 holder.setHalfHeight(capsuleGeometry.halfHeight);
1522 case physx::PxGeometryType::ePLANE:{
1523 physx::PxPlaneGeometry planeGeometry;
1524 physXShape->getPlaneGeometry(planeGeometry);
1530 if (
model->geometry() ==
nullptr) {
1532 geom->setParent(
model);
1533 model->setGeometry(geom);
1538 case physx::PxGeometryType::eHEIGHTFIELD: {
1539 physx::PxHeightFieldGeometry heightFieldGeometry;
1540 physXShape->getHeightFieldGeometry(heightFieldGeometry);
1541 const float heightScale =
holder.heightScale();
1542 const float rowScale =
holder.rowScale();
1543 const float columnScale =
holder.columnScale();
1545 if (!
qFuzzyCompare(heightFieldGeometry.heightScale, heightScale)
1547 || !
qFuzzyCompare(heightFieldGeometry.columnScale, columnScale)) {
1550 heightFieldGeometry.heightField, heightFieldGeometry.heightScale,
1551 heightFieldGeometry.rowScale, heightFieldGeometry.columnScale);
1552 geom->setParent(
model);
1553 model->setGeometry(geom);
1554 holder.setHeightScale(heightFieldGeometry.heightScale);
1555 holder.setRowScale(heightFieldGeometry.rowScale);
1556 holder.setColumnScale(heightFieldGeometry.columnScale);
1561 case physx::PxGeometryType::eCONVEXMESH: {
1562 physx::PxConvexMeshGeometry convexMeshGeometry;
1563 physXShape->getConvexMeshGeometry(convexMeshGeometry);
1564 const auto rotation = convexMeshGeometry.scale.rotation * localPose.q;
1565 localPose = physx::PxTransform(localPose.p, rotation);
1568 if (
model->geometry() ==
nullptr) {
1570 convexMeshGeometry.convexMesh);
1571 geom->setParent(
model);
1572 model->setGeometry(geom);
1577 case physx::PxGeometryType::eTRIANGLEMESH: {
1578 physx::PxTriangleMeshGeometry triangleMeshGeometry;
1579 physXShape->getTriangleMeshGeometry(triangleMeshGeometry);
1580 const auto rotation = triangleMeshGeometry.scale.rotation * localPose.q;
1581 localPose = physx::PxTransform(localPose.p, rotation);
1584 if (
model->geometry() ==
nullptr) {
1586 triangleMeshGeometry.triangleMesh);
1587 geom->setParent(
model);
1588 model->setGeometry(geom);
1593 case physx::PxGeometryType::eINVALID:
1594 case physx::PxGeometryType::eGEOMETRY_COUNT:
1599 model->setVisible(
true);
1601 auto globalPose = node->getGlobalPose();
1602 auto finalPose = globalPose.transform(localPose);
1610 m_collisionShapeDebugModels.
removeIf(
1612 DebugModelHolder>::iterator
it) {
1613 if (!currentCollisionShapes.
contains(
it.key())) {
1614 auto holder = it.value();
1616 delete holder.model;
1623void QPhysicsWorld::disableDebugDraw()
1625 m_hasIndividualDebugDraw =
false;
1628 const auto &collisionShapes = body->frontendNode->getCollisionShapesList();
1629 const int length = collisionShapes.length();
1630 for (
int idx = 0; idx <
length; idx++) {
1631 const auto collisionShape = collisionShapes[idx];
1632 if (collisionShape->enableDebugDraw()) {
1633 m_hasIndividualDebugDraw =
true;
1645 if (m_physicsInitialized) {
1647 <<
"Warning: Changing 'enableCCD' after physics is initialized will have no effect";
1661 qWarning() <<
"Warning: 'typicalLength' value less than zero, ignored";
1665 if (m_physicsInitialized) {
1666 qWarning() <<
"Warning: Changing 'typicalLength' after physics is initialized will have "
1681 if (m_physicsInitialized) {
1682 qWarning() <<
"Warning: Changing 'typicalSpeed' after physics is initialized will have "
1694 return m_defaultDensity;
1699 return m_minTimestep;
1704 return m_maxTimestep;
1715 body->updateDefaultDensity(m_defaultDensity);
1722void QPhysicsWorld::cleanupRemovedNodes()
1729 m_removedPhysicsNodes.
clear();
1732void QPhysicsWorld::initPhysics()
1736 m_physx->
createScene(m_typicalLength, m_typicalSpeed, m_gravity, m_enableCCD,
this);
1744 m_workerThread.
start();
1746 m_physicsInitialized =
true;
1749void QPhysicsWorld::frameFinished(
float deltaTime)
1752 cleanupRemovedNodes();
1753 for (
auto *node :
std::as_const(m_newPhysicsNodes)) {
1755 body->
init(
this, m_physx);
1758 m_newPhysicsNodes.
clear();
1763 for (
auto *physXBody :
std::as_const(m_physXBodies)) {
1764 physXBody->markDirtyShapes();
1765 physXBody->rebuildDirtyShapes(
this, m_physx);
1768 physXBody->sync(deltaTime, transformCache);
1775 emit frameDone(deltaTime * 1000);
1781 if (!
world->m_scene) {
1788 if (nodeCurr ==
world->m_scene)
1793 if (nodeCurr ==
world->m_scene)
1801void QPhysicsWorld::matchOrphanNodes()
1810 while (idx < numNodes) {
1813 if (
world ==
this) {
1814 world->m_newPhysicsNodes.push_back(node);
1825void QPhysicsWorld::findPhysicsNodes()
1830 if (m_scene ==
nullptr)
1837 if (
auto converted = qobject_cast<QAbstractPhysicsNode *>(
child); converted !=
nullptr) {
1839 if (converted->m_backendObject !=
nullptr) {
1840 qWarning() <<
"Warning: physics node already associated with a backend node.";
1851physx::PxPhysics *QPhysicsWorld::getPhysics()
1856physx::PxCooking *QPhysicsWorld::getCooking()
1877 if (m_scene == newScene)
1883 for (
auto body : m_physXBodies) {
1888 bool sceneOK =
true;
1890 if (
world !=
this &&
world->scene() == newScene) {
1892 qWarning() <<
"Warning: scene already associated with physics world";
1898 emit sceneChanged();
1903#include "qphysicsworld.moc"
void onShapeHit(const physx::PxControllerShapeHit &hit) override
void onControllerHit(const physx::PxControllersHit &) override
ControllerCallback(QPhysicsWorld *worldIn)
void onObstacleHit(const physx::PxControllerObstacleHit &) override
virtual bool useTriggerFlag()
virtual void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache)=0
QAbstractPhysicsNode * frontendNode
QVector< physx::PxShape * > shapes
virtual void createMaterial(PhysXWorld *physX)
virtual void cleanup(PhysXWorld *)
physx::PxMaterial * material
QAbstractPhysXNode(QAbstractPhysicsNode *node)
virtual physx::PxTransform getGlobalPose()
void setShapesDirty(bool dirty)
virtual DebugDrawBodyType getDebugDrawBodyType()
void createMaterialFromQtMaterial(PhysXWorld *physX, QPhysicsMaterial *qtMaterial)
virtual void init(QPhysicsWorld *world, PhysXWorld *physX)=0
virtual void updateDefaultDensity(float)
virtual void markDirtyShapes()
bool cleanupIfRemoved(PhysXWorld *physX)
virtual bool debugGeometryCapability()
static physx::PxMaterial * defaultMaterial
virtual void rebuildDirtyShapes(QPhysicsWorld *, PhysXWorld *)
virtual ~QAbstractPhysXNode()
const QVector< QAbstractCollisionShape * > & getCollisionShapesList() const
bool receiveTriggerReports
void updateFromPhysicsTransform(const physx::PxTransform &transform)
bool hasStaticShapes() const
bool receiveContactReports
void registerContact(QAbstractPhysicsNode *body, const QVector< QVector3D > &positions, const QVector< QVector3D > &impulses, const QVector< QVector3D > &normals)
void shapeHit(QAbstractPhysicsNode *body, const QVector3D &position, const QVector3D &impulse, const QVector3D &normal)
bool enableShapeHitCallback
QQueue< QPhysicsCommand * > & commandQueue()
QList< float > inertiaMatrix
void setIsKinematic(bool isKinematic)
void updateDefaultDensity(float defaultDensity)
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
qsizetype size() const noexcept
Returns the number of items in the hash.
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
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 isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
qsizetype size() const noexcept
bool empty() const noexcept
void push_back(parameter_type t)
qsizetype removeIf(Predicate pred)
void reserve(qsizetype size)
void append(parameter_type t)
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
const QObjectList & children() const
Returns a list of child objects.
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void setParent(QObject *parent)
Makes the object a child of parent.
void deleteLater()
\threadsafe
void markDirtyShapes() override
virtual void createActor(PhysXWorld *physX)
bool debugGeometryCapability() override
QPhysXActorBody(QAbstractPhysicsNode *frontEnd)
void buildShapes(PhysXWorld *physX)
void rebuildDirtyShapes(QPhysicsWorld *world, PhysXWorld *physX) override
physx::PxRigidActor * actor
void cleanup(PhysXWorld *physX) override
void init(QPhysicsWorld *world, PhysXWorld *physX) override
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
physx::PxTransform getGlobalPose() override
QPhysXCharacterController(QCharacterController *frontEnd)
void init(QPhysicsWorld *world, PhysXWorld *physX) override
void cleanup(PhysXWorld *physX) override
void createMaterial(PhysXWorld *physX) override
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
void updateDefaultDensity(float density) override
void rebuildDirtyShapes(QPhysicsWorld *world, PhysXWorld *physX) override
QPhysXDynamicBody(QDynamicRigidBody *frontEnd)
DebugDrawBodyType getDebugDrawBodyType() override
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
static QAbstractPhysXNode * createBackend(QAbstractPhysicsNode *node)
QPhysXRigidBody(QAbstractPhysicsBody *frontEnd)
void createMaterial(PhysXWorld *physX) override
void createActor(PhysXWorld *physX) override
QPhysXStaticBody(QStaticRigidBody *frontEnd)
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
DebugDrawBodyType getDebugDrawBodyType() override
DebugDrawBodyType getDebugDrawBodyType() override
QPhysXTriggerBody(QTriggerBody *frontEnd)
void sync(float deltaTime, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache) override
bool useTriggerFlag() override
static constexpr float defaultDynamicFriction
static constexpr float defaultStaticFriction
static constexpr float defaultRestitution
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 setDefaultDensity(float defaultDensity)
void forceDebugDrawChanged(bool forceDebugDraw)
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 simulateFrame(float minTimestep, float maxTimestep)
void defaultDensityChanged(float defaultDensity)
void setGravity(QVector3D gravity)
static void registerNode(QAbstractPhysicsNode *physicsNode)
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.
static QQuaternion fromEulerAngles(const QVector3D &eulerAngles)
static QQuaternion fromRotationMatrix(const QMatrix3x3 &rot3x3)
QQuaternion normalized() const
Returns the normalized unit form of this quaternion.
void enqueue(const T &t)
Adds value t to the tail of the queue.
Q_INVOKABLE QVector3D mapPositionFromScene(const QVector3D &scenePosition) const
\qmlmethod vector3d QtQuick3D::Node::mapPositionFromScene(vector3d scenePosition)
void setPosition(const QVector3D &position)
QQuick3DNode * parentNode() const
QQuaternion sceneRotation
void reserve(qsizetype size)
bool contains(const T &value) const
iterator insert(const T &value)
void start(Priority=InheritPriority)
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
static void usleep(unsigned long)
void finished(QPrivateSignal)
void registerCollision(QAbstractPhysicsNode *collision)
void deregisterCollision(QAbstractPhysicsNode *collision)
The QVector3D class represents a vector or vertex in 3D space.
constexpr float y() const noexcept
Returns the y coordinate of this point.
constexpr float x() const noexcept
Returns the x coordinate of this point.
constexpr float z() const noexcept
Returns the z coordinate of this point.
SimulationEventCallback(QPhysicsWorld *worldIn)
void onConstraintBreak(physx::PxConstraintInfo *, physx::PxU32) override
virtual ~SimulationEventCallback()=default
void onContact(const physx::PxContactPairHeader &pairHeader, const physx::PxContactPair *pairs, physx::PxU32 nbPairs) override
void onAdvance(const physx::PxRigidBody *const *, const physx::PxTransform *, const physx::PxU32) override
void onWake(physx::PxActor **, physx::PxU32) override
void onTrigger(physx::PxTriggerPair *pairs, physx::PxU32 count) override
void onSleep(physx::PxActor **, physx::PxU32) override
SimulationWorker(PhysXWorld *physx)
void frameDone(float deltaTime)
void simulateFrame(float minTimestep, float maxTimestep)
QSet< QString >::iterator it
constexpr QColor lightsalmon
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)
Q_ALWAYS_INLINE QVector3D toQtType(const physx::PxVec3 &vec)
Combined button and popup list for selecting options.
struct QT_BEGIN_NAMESPACE::Holder holder
QMatrix3x3 Q_QUICK3DUTILS_EXPORT getUpper3x3(const QMatrix4x4 &m)
void Q_QUICK3DUTILS_EXPORT normalize(QMatrix4x4 &m)
QVector3D Q_QUICK3DUTILS_EXPORT getPosition(const QMatrix4x4 &m)
std::pair< T1, T2 > QPair
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,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLuint GLenum GLenum transform
GLenum GLenum GLenum GLenum GLenum scale
StaticPhysXObjects s_physx
static physx::PxTransform getPhysXWorldTransform(const QQuick3DNode *node)
static physx::PxFilterFlags contactReportFilterShaderCCD(physx::PxFilterObjectAttributes, physx::PxFilterData, physx::PxFilterObjectAttributes, physx::PxFilterData, physx::PxPairFlags &pairFlags, const void *, physx::PxU32)
static physx::PxFilterFlags contactReportFilterShader(physx::PxFilterObjectAttributes, physx::PxFilterData, physx::PxFilterObjectAttributes, physx::PxFilterData, physx::PxPairFlags &pairFlags, const void *, physx::PxU32)
static QWorldManager worldManager
static bool fuzzyEquals(const physx::PxTransform &a, const physx::PxTransform &b)
static QMatrix4x4 calculateKinematicNodeTransform(QQuick3DNode *node, QHash< QQuick3DNode *, QMatrix4x4 > &transformCache)
static physx::PxTransform getPhysXLocalTransform(const QQuick3DNode *node)
static const QQuaternion kMinus90YawRotation
static void updatePhysXMaterial(const QPhysicsMaterial *qtMaterial, physx::PxMaterial *physXMaterial)
static physx::PxRigidDynamicLockFlags getLockFlags(QDynamicRigidBody *body)
static void processCommandQueue(QQueue< QPhysicsCommand * > &commandQueue, const QDynamicRigidBody &rigidBody, physx::PxRigidBody &body)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QSqlQueryModel * model
[16]
rect sceneTransform().map(QPointF(0
view viewport() -> scroll(dx, dy, deviceRect)
QLatin1StringView world("world")
SimulationEventCallback * callback
physx::PxControllerManager * controllerManager
void createScene(float typicalLength, float typicalSpeed, const QVector3D &gravity, bool enableCCD, QPhysicsWorld *physicsWorld)
static QMatrix4x4 calculateTransformMatrix(QVector3D position, QVector3D scale, QVector3D pivot, QQuaternion rotation)
QVector< QAbstractPhysicsNode * > orphanNodes
QVector< QPhysicsWorld * > worlds
physx::PxDefaultErrorCallback defaultErrorCallback
physx::PxDefaultAllocator defaultAllocatorCallback
physx::PxCooking * cooking
unsigned int foundationRefCount
physx::PxFoundation * foundation
physx::PxPvdTransport * transport
physx::PxDefaultCpuDispatcher * dispatcher
physx::PxPhysics * physics
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent