В физическом моделировании с использованием библиотеки Ammo.js важным аспектом является определение того, находится ли объект на поверхности (на земле) или находится в состоянии свободного падения. Это особенно критично для симуляции персонажей, транспортных средств и любых объектов, взаимодействующих с физической средой. Правильная реализация позволяет управлять поведением объектов, предотвращать “проваливание” сквозь поверхность и корректно обрабатывать коллизии.
Ammo.js опирается на систему RigidBody и Collision Shapes. Основная идея детектирования нахождения на земле состоит в проверке наличия контакта объекта с другими объектами сцены:
btBoxShape,
btCapsuleShape, btSphereShape).const rayFrom = new Ammo.btVector3(objPos.x, objPos.y, objPos.z);
const rayTo = new Ammo.btVector3(objPos.x, objPos.y - rayLength, objPos.z);
const rayCallback = new Ammo.ClosestRayResultCallback(rayFrom, rayTo);
physicsWorld.rayTest(rayFrom, rayTo, rayCallback);
if (rayCallback.hasHit()) {
const hitPoint = rayCallback.get_m_hitPointWorld();
const distanceToGround = objPos.y - hitPoint.y();
const isOnGround = distanceToGround <= epsilon;
}
Ключевые моменты:
rayLength должен быть достаточным, чтобы пересекать
потенциальное расстояние до поверхности.epsilon определяет максимальное расстояние, при котором
объект считается стоящим на земле.ClosestRayResultCallback позволяет
определить ближайшую точку пересечения с любой коллизионной
геометрией.Другой метод основан на получении информации из contact manifolds:
const dispatcher = physicsWorld.getDispatcher();
let isOnGround = false;
for (let i = 0; i < dispatcher.getNumManifolds(); i++) {
const manifold = dispatcher.getManifoldByIndexInternal(i);
const body0 = manifold.getBody0();
const body1 = manifold.getBody1();
if (body0 === playerBody || body1 === playerBody) {
const numContacts = manifold.getNumContacts();
for (let j = 0; j < numContacts; j++) {
const pt = manifold.getContactPoint(j);
if (pt.getDistance() < 0.0) {
const normal = pt.get_m_normalWorldOnB();
if (normal.y() > groundNormalThreshold) {
isOnGround = true;
break;
}
}
}
}
if (isOnGround) break;
}
Особенности метода:
getNumManifolds() возвращает количество всех активных
манифолдов.get_m_normalWorldOnB() позволяет определить направление
нормали, что важно для различения пола и стен.groundNormalThreshold задает минимальное значение
компоненты y нормали, при котором поверхность считается
горизонтальной.Этот метод более точный для динамических сцен, так как учитывает прямой контакт между объектами, а не только проверку через луч.
collisionFilterGroup и collisionFilterMask,
чтобы лучи или контактные проверки учитывали только нужные
поверхности.btCapsuleShape) — она
обеспечивает стабильное взаимодействие с неровной поверхностью.Детектирование нахождения на земле является фундаментальным элементом при реализации физически корректных игровых механик, таких как ходьба, прыжки, спуск по склонам и управление транспортом. Ammo.js предоставляет достаточно низкоуровневых инструментов, чтобы реализовать эти проверки эффективно, учитывая как производительность, так и точность симуляции.