Физика пули - излучение луча прямо от твердого тела (камера от первого лица)

10

Я реализовал камеру от первого лица с помощью Bullet - это твердое тело в форме капсулы. Я использую Bullet всего несколько дней, и физические движки для меня новы. Я использую, btRigidBody::setLinearVelocity()чтобы переместить это, и это отлично сталкивается с миром. Единственная проблема заключается в том, что значение Y перемещается свободно, что я временно решил, установив значение Y вектора переноса в ноль перед перемещением тела. Это работает для всех случаев, кроме падения с высоты.

Когда тело падает с высокого объекта, вы все равно можете скользить вокруг, так как Y-значение вектора перевода устанавливается в ноль, пока вы не перестанете двигаться и не упадете на землю (скорость устанавливается только при движении). Поэтому, чтобы решить эту проблему, я хотел бы попробовать навести луч вниз от тела, чтобы определить Y-значение мира, и проверить разницу между этим значением и Y-значением корпуса камеры, а также отключить или замедлить движение, если разница достаточно велика.

Я немного застрял при простом отбрасывании луча и определении значения Y в мире, где он ударил. Я реализовал этот обратный вызов:

struct AllRayResultCallback : public btCollisionWorld::RayResultCallback{
    AllRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld)
        : m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld), m_closestHitFraction(1.0){}

    btVector3   m_rayFromWorld;
    btVector3   m_rayToWorld;
    btVector3   m_hitNormalWorld;
    btVector3   m_hitPointWorld;
    float       m_closestHitFraction;

    virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
    {
        if(rayResult.m_hitFraction < m_closestHitFraction)
            m_closestHitFraction = rayResult.m_hitFraction;

        m_collisionObject = rayResult.m_collisionObject;
        if(normalInWorldSpace){
            m_hitNormalWorld = rayResult.m_hitNormalLocal;
        }
        else{
            m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis() * rayResult.m_hitNormalLocal;
        }

        m_hitPointWorld.setInterpolate3(m_rayFromWorld, m_rayToWorld, m_closestHitFraction);
        return 1.0f;
    }
};

И в функции движения у меня есть этот код:

btVector3 from(pos.x, pos.y + 1000, pos.z); // pos is the camera's rigid body position
btVector3 to(pos.x, 0, pos.z); // not sure if 0 is correct for Y

AllRayResultCallback callback(from, to);
Base::getSingletonPtr()->m_btWorld->rayTest(from, to, callback);

Так что у меня есть callback.m_hitPointWorldвектор, который, кажется, просто показывает положение камеры в каждом кадре. Я искал в Google примеры бросков лучей, а также документацию Bullet, и мне было трудно просто найти пример. Пример - это действительно все, что мне нужно.

Или, может быть, есть какой-то метод в Bullet, чтобы держать твердое тело на земле?

Я использую Ogre3D в качестве движка рендеринга, и приведение луча вниз довольно просто с этим, однако для простоты я хочу оставить все приведенные лучи внутри Bullet.

Может ли кто-нибудь указать мне правильное направление? Спасибо.

Синий волшебник
источник

Ответы:

10

Оказывается, решение намного проще, чем первоначальная попытка, и нет необходимости в создании подклассов, если вы просто тестируете столкновение с одним лучом.

Вот все, что вам нужно сделать, чтобы получить вектор столкновения:

btVector3 btFrom(camPos.x, camPos.y, camPos.z);
btVector3 btTo(camPos.x, -5000.0f, camPos.z);
btCollisionWorld::ClosestRayResultCallback res(btFrom, btTo);

Base::getSingletonPtr()->m_btWorld->rayTest(btFrom, btTo, res); // m_btWorld is btDiscreteDynamicsWorld

if(res.hasHit()){
    printf("Collision at: <%.2f, %.2f, %.2f>\n", res.m_hitPointWorld.getX(), res.m_hitPointWorld.getY(), res.m_hitPointWorld.getZ());
}
Синий волшебник
источник