Bullet Physics - Lanciare un raggio verso il basso da un corpo rigido (fotocamera in prima persona)


10

Ho implementato una fotocamera in prima persona usando Bullet: è un corpo rigido a forma di capsula. Uso Bullet da alcuni giorni e i motori della fisica sono nuovi per me. Lo uso btRigidBody::setLinearVelocity()per spostarlo e si scontra perfettamente con il mondo. L'unico problema è che il valore Y si muove liberamente, cosa che ho temporaneamente risolto impostando il valore Y del vettore di traslazione su zero prima di spostare il corpo. Funziona in tutti i casi tranne quando si cade da un'altezza.

Quando il corpo cade da un oggetto alto, puoi ancora planare poiché il valore Y del vettore di traslazione viene impostato su zero, fino a quando non smetti di muoverti e cadi a terra (la velocità viene impostata solo quando ti muovi). Quindi, per risolvere questo problema, vorrei provare a scagliare un raggio dal corpo per determinare il valore Y del mondo e controllare la differenza tra quel valore e il valore Y del corpo macchina, e disabilitare o rallentare il movimento se la differenza è abbastanza grande.

Sono un po 'bloccato semplicemente lanciando un raggio e determinando il valore Y del mondo in cui ha colpito. Ho implementato questo callback:

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

E nella funzione di movimento, ho questo codice:

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

Quindi ho il callback.m_hitPointWorldvettore, che sembra mostrare solo la posizione della telecamera per ogni fotogramma. Ho cercato su Google esempi di casting casting, nonché la documentazione Bullet, ed è stato difficile trovare un esempio. Un esempio è davvero tutto ciò di cui ho bisogno.

O forse c'è qualche metodo in Bullet per mantenere il corpo rigido a terra?

Sto usando Ogre3D come motore di rendering, e lanciare un raggio verso il basso è abbastanza semplice, tuttavia voglio mantenere tutto il casting dei raggi all'interno di Bullet per semplicità.

Qualcuno potrebbe indicarmi la giusta direzione? Grazie.

Risposte:


10

Si scopre che la soluzione è molto più semplice del tentativo originale e non è necessario eseguire la sottoclasse se si sta solo testando una collisione a raggi.

Ecco tutto ciò che devi fare per recuperare il vettore di collisione:

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());
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.