77 Q_ASSERT(!controller);
79 auto *characterController =
static_cast<QCharacterController *>(frontendNode);
81 auto shapes = characterController->getCollisionShapesList();
82 if (shapes.length() != 1) {
83 qWarning() <<
"CharacterController: invalid collision shapes list.";
86 auto *capsule = qobject_cast<QCapsuleShape *>(shapes.first());
88 qWarning() <<
"CharacterController: collision shape is not a capsule.";
91 auto *mgr = world->controllerManager();
93 qWarning() <<
"QtQuick3DPhysics internal error: missing controller manager.";
99 const QVector3D scale = characterController->sceneScale();
100 const qreal heightScale = scale.y();
101 const qreal radiusScale = scale.x();
102 physx::PxCapsuleControllerDesc desc;
103 reportCallback =
new ControllerCallback(world);
104 desc.reportCallback = reportCallback;
105 desc.radius = 0.5f * radiusScale * capsule->diameter();
106 desc.height = heightScale * capsule->height();
107 desc.stepOffset = 0.25f * desc.height;
109 desc.material = material;
110 const QVector3D pos = characterController->scenePosition();
111 desc.position = { pos.x(), pos.y(), pos.z() };
114 controller =
static_cast<
physx::PxCapsuleController *>(mgr->createController(desc));
117 qWarning() <<
"QtQuick3DPhysics internal error: could not create controller.";
121 controller->setUserData(
static_cast<
void *>(frontendNode));
123 auto *actor = controller->getActor();
125 actor->userData = characterController;
127 qWarning() <<
"QtQuick3DPhysics internal error: CharacterController created without actor.";
137 QHash<QQuick3DNode *, QMatrix4x4> & )
139 if (controller ==
nullptr)
142 auto *characterController =
static_cast<QCharacterController *>(frontendNode);
145 const auto &shapes = characterController->getCollisionShapesList();
146 auto capsule = shapes.length() == 1 ? qobject_cast<QCapsuleShape *>(shapes.front()) :
nullptr;
148 if (shapes.length() != 1) {
149 qWarning() <<
"CharacterController: invalid collision shapes list.";
150 }
else if (!capsule) {
151 qWarning() <<
"CharacterController: collision shape is not a capsule.";
153 const QVector3D sceneScale = characterController->sceneScale();
154 const qreal heightScale = sceneScale.y();
155 const qreal radiusScale = sceneScale.x();
158 const float heightNew = heightScale * capsule->height();
160 const float radiusNew = 0.5f * radiusScale * capsule->diameter();
162 if (!qIsFinite(heightNew) || heightNew <= 0.f || !qIsFinite(radiusNew)
163 || radiusNew <= 0.f) {
164 qWarning() <<
"CharacterController: scaled capsule height/radius must be finite "
165 "and positive, ignoring.";
167 if (!qFuzzyCompare(controller->getHeight(), heightNew))
168 controller->resize(heightNew);
169 if (!qFuzzyCompare(controller->getRadius(), radiusNew))
170 controller->setRadius(radiusNew);
173 const float stepOffsetNew = 0.25f * heightNew;
174 if (!qFuzzyCompare(controller->getStepOffset(), stepOffsetNew))
175 controller->setStepOffset(stepOffsetNew);
179 QVector3D position = QPhysicsUtils::toQtType(physx::toVec3(controller->getPosition()));
180 const QQuick3DNode *parentNode =
static_cast<QQuick3DNode *>(characterController->parentItem());
183 characterController->setPosition(position);
185 characterController->setPosition(parentNode->mapPositionFromScene(position));
192 QVector3D teleportPos;
193 bool teleport = characterController->getTeleport(teleportPos);
195 controller->setPosition({ teleportPos.x(), teleportPos.y(), teleportPos.z() });
196 }
else if (deltaTime > 0) {
197 const auto displacement =
198 QPhysicsUtils::toPhysXType(characterController->getDisplacement(deltaTime));
200 controller->move(displacement, displacement.magnitude() / 100, deltaTime, {});
205 characterController->setCollisions(QCharacterController::Collisions(uint(collisions)));
215 if (updateMaterial() && material) {
216 physx::PxShape *shape =
nullptr;
217 auto *actor = controller->getActor();
219 if (actor && actor->getShapes(&shape, 1) == 1)
220 shape->setMaterials(&material, 1);