กระสุนฟิสิกส์ - หล่อเรย์ลงมาจากร่างแข็ง (กล้องคนแรก)


10

ฉันติดตั้งกล้องคนแรกด้วยกระสุนปืน - มันเป็นกล้องที่มีรูปร่างเหมือนแคปซูล ฉันใช้ 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 เพื่อรักษาร่างกายที่แข็งแรงไว้บนพื้น?

ฉันใช้ 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());
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.