使用Bullet检测碰撞

4
我使用Ogre3D制作了一个应用程序,已经生成了bullet物体,现在我需要做的就是检测物体之间的碰撞。我查看了CollisionInterfaceDemo演示,但它并不符合我的需求。如果要检测3个球之间的碰撞,只需要知道是否会发生碰撞(不关心碰撞点),需要哪些步骤呢?我只知道可以通过设置变换来移动CollisionObject。

1
你不能使用数学来进行碰撞检测吗? - Ivaylo Strandjev
如果我有很多实体,我需要一些物理引擎,可以选择大多数球体,以跳过很多加法/乘法。我想这被称为bulletphysics中的broadphase。 - jokoon
https://dev59.com/TV_Va4cB1Zd3GeqPY_wR || http://gamedev.stackexchange.com/questions/22442/how-get-collision-callback-of-two-specific-objects-using-bullet-physics - Ciro Santilli OurBigBook.com
2个回答

4
如果您正在使用Bullet,那么有几个演示可以帮助您入门。
但基本上,以下是说明(其中大部分来自其示例):
在头文件或物理系统所在的任何位置:
btDefaultCollisionConfiguration*        mPhysicsConfig;
btCollisionDispatcher*                  mPhysicsDispatcher;
btBroadphaseInterface*                  mPhysicsCache;
btSequentialImpulseConstraintSolver*    mPhysicsSolver;
btDiscreteDynamicsWorld*                mPhysicsWorld;
btAlignedObjectArray<btCollisionShape*> mPhysicsShapes;

第一步(初始化):

///collision configuration contains default setup for memory, collision setup.
mPhysicsConfig = new btDefaultCollisionConfiguration();

///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
mPhysicsDispatcher = new    btCollisionDispatcher(mPhysicsConfig);

///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
mPhysicsCache = new btDbvtBroadphase();

///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
mPhysicsSolver = new btSequentialImpulseConstraintSolver;
mPhysicsWorld = new btDiscreteDynamicsWorld(mPhysicsDispatcher,mPhysicsCache,mPhysicsSolver,mPhysicsConfig);
mPhysicsWorld->setGravity(btVector3(0,-9.81f,0));

每一帧(通常在Update函数中使用):
mPhysicsWorld->stepSimulation( timestep , 10 );

添加一个球体(指针只是为了在创建后更容易访问而返回):
btRigidBody* MyPhysicsSystem::CreateSphere(float sx, float px, float py, float pz, float mass)
{
    btCollisionShape* colShape = new btSphereShape(btScalar(sx));
    mPhysicsShapes.push_back(colShape);

    btTransform startTransform;
    startTransform.setIdentity();

    btScalar    tMass(mass);

    //rigidbody is dynamic if and only if mass is non zero, otherwise static
    bool isDynamic = (tMass != 0.f);

    btVector3 localInertia(0,0,0);
    if (isDynamic)
        colShape->calculateLocalInertia(tMass,localInertia);

    startTransform.setOrigin(btVector3(px,py,pz));

    //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
    btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
    btRigidBody::btRigidBodyConstructionInfo rbInfo(tMass,myMotionState,colShape,localInertia);
    btRigidBody* body = new btRigidBody(rbInfo);
    mPhysicsWorld->addRigidBody(body);
    return body;
}

大致就是这样了!

再次强调:

  1. 初始化模拟需要的东西。
  2. 创建一个对象并将其添加到bullet的“世界”中。
  3. 通过一些时间步骤每帧更新该世界。

Bullet会为您处理碰撞。如果您需要在发生碰撞时执行某些功能,我相信您可以将自定义回调分配为碰撞行为。

希望这可以帮到你!


1
我不想让子弹移动我的物体,我只想自己移动它。 - jokoon

1

在处理球体之间的碰撞检测时,您需要知道两件事:每个球体的半径和它们的位置。

然后,您必须遍历每个球体并将其与其他球体进行比较。对于每一对,您需要首先找出它们之间的距离。

http://www.purplemath.com/modules/distform.htm

这是基本的二维距离公式,要将其转换为三维,您只需要在平方根之前将(z2-z1)平方添加到其他两个坐标中。

一旦您得到了该距离,只需将两个球体的半径相加并将其与它们之间的距离进行比较。如果距离小于或等于半径之和,则球体已经碰撞。

我不熟悉Ogre3D,但如果您可以转换一个对象,那么您也应该能够获取它的位置。


5
顺便说一下,你不需要对结果进行平方根运算,这样会消耗很多时间。只比较两数的平方就可以了。 - jokoon
@gokoon 我之前没有考虑过这个,一直在过于注重“正确”的数学方法。虽然节省的时间不多,但你说得对,平方比开方更快(略微)。谢谢你的建议。 - Cdaragorn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接