Bullet Physics-リジッドボディから直接光線を投射する(一人称カメラ)


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

解決策は元の試みよりもはるかに単純であり、レイの衝突を1つだけテストする場合はサブクラス化の必要がないことがわかります。

衝突ベクトルを取得するために必要な作業は次のとおりです。

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());
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.