Bullet Physics - Casting sinar langsung ke bawah dari benda tegar (kamera orang pertama)

10

Saya sudah mengimplementasikan kamera orang pertama menggunakan Bullet - ini adalah tubuh yang kaku dengan bentuk kapsul. Saya hanya menggunakan Bullet selama beberapa hari dan mesin fisika baru bagi saya. Saya gunakan btRigidBody::setLinearVelocity()untuk memindahkannya dan bertabrakan dengan sempurna dengan dunia. Satu-satunya masalah adalah nilai-Y bergerak bebas, yang untuk sementara saya selesaikan dengan mengatur nilai-Y dari vektor terjemahan menjadi nol sebelum tubuh dipindahkan. Ini bekerja untuk semua kasus kecuali ketika jatuh dari ketinggian.

Saat tubuh menjatuhkan benda tinggi, Anda masih bisa meluncur karena nilai Y vektor terjemahan diatur ke nol, sampai Anda berhenti bergerak dan jatuh ke tanah (kecepatan hanya diatur saat bergerak). Jadi untuk menyelesaikan ini, saya ingin mencoba melemparkan sinar ke bawah dari tubuh untuk menentukan nilai-Y dunia, dan memeriksa perbedaan antara nilai itu dan nilai-Y dari tubuh kamera, dan menonaktifkan atau memperlambat gerakan jika perbedaannya cukup besar.

Saya agak terjebak pada hanya melempar sinar dan menentukan nilai-Y dari dunia di mana ia melanda. Saya sudah menerapkan panggilan balik ini:

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

Dan dalam fungsi pergerakan, saya memiliki kode ini:

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

Jadi saya punya callback.m_hitPointWorldvektor, yang sepertinya hanya menunjukkan posisi kamera setiap frame. Saya telah mencari Google untuk contoh sinar casting, serta dokumentasi Bullet, dan sulit untuk hanya menemukan contoh. Contoh adalah yang saya butuhkan.

Atau mungkin ada beberapa metode di Bullet untuk menjaga tubuh tetap kaku di tanah?

Saya menggunakan Ogre3D sebagai mesin rendering, dan casting sinar ke bawah cukup mudah dengan itu, namun saya ingin menyimpan semua pengecoran sinar dalam Bullet untuk kesederhanaan.

Adakah yang bisa mengarahkan saya ke arah yang benar? Terima kasih.

Wisaya Biru
sumber

Jawaban:

10

Ternyata solusinya jauh lebih sederhana daripada upaya awal, dan tidak perlu subklas jika Anda hanya menguji satu tabrakan sinar.

Inilah yang harus Anda lakukan untuk mengambil vektor tabrakan:

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());
}
Wisaya Biru
sumber