Bullet Physics - Lancer un rayon directement depuis un corps rigide (caméra à la première personne)

10

J'ai mis en place une caméra à la première personne à l'aide de Bullet - c'est un corps rigide avec une forme de capsule. Je n'utilise Bullet que depuis quelques jours et les moteurs physiques sont nouveaux pour moi. Je l'utilise btRigidBody::setLinearVelocity()pour le déplacer et il entre parfaitement en contact avec le monde. Le seul problème est que la valeur Y se déplace librement, ce que j'ai résolu temporairement en définissant la valeur Y du vecteur de translation à zéro avant le déplacement du corps. Cela fonctionne dans tous les cas sauf en cas de chute de hauteur.

Lorsque le corps laisse tomber un objet de grande taille, vous pouvez toujours planer puisque la valeur Y du vecteur de translation est réglée sur zéro, jusqu'à ce que vous arrêtiez de bouger et tombiez au sol (la vitesse n'est définie que lors du déplacement). Donc, pour résoudre ce problème, je voudrais essayer de lancer un rayon vers le bas du corps pour déterminer la valeur Y du monde, et vérifier la différence entre cette valeur et la valeur Y du corps de la caméra, et désactiver ou ralentir le mouvement si la différence est assez grande.

Je suis un peu coincé à simplement lancer un rayon et à déterminer la valeur Y du monde où il a frappé. J'ai implémenté ce rappel:

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;
    }
};

Et dans la fonction de mouvement, j'ai ce code:

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);

J'ai donc le callback.m_hitPointWorldvecteur, qui semble simplement montrer la position de la caméra à chaque image. J'ai cherché sur Google des exemples de lancer de rayons, ainsi que la documentation de Bullet, et il a été difficile de trouver un exemple. Un exemple est vraiment tout ce dont j'ai besoin.

Ou peut-être existe-t-il une méthode dans Bullet pour garder le corps rigide au sol?

J'utilise Ogre3D comme moteur de rendu, et lancer un rayon vers le bas est assez simple avec cela, mais je veux garder tout le lancer de rayon dans Bullet pour plus de simplicité.

Quelqu'un pourrait-il m'orienter dans la bonne direction? Merci.

Blue Wizard
la source

Réponses:

10

Il s'avère que la solution est beaucoup plus simple que la tentative d'origine, et il n'est pas nécessaire de sous-classer si vous testez simplement une collision à un rayon.

Voici tout ce que vous devez faire pour récupérer le vecteur de collision:

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());
}
Blue Wizard
la source