Bullet教程: Hello World 实例

1649 篇文章 11 订阅
1277 篇文章 12 订阅

更多信息请关注 物理引擎中文社区http://www.physicsengine.org

欢迎加qq群 52821727 讨论更多关于Bullet的东西

这篇文章里我们将尽可能简单的向你展示怎么使用Bullet, 怎样初始化Bullet, 设置一个动力学世界, 还有一个球落向地表 这个对鉴别你的build是否成功非常有用并且也能够让你快速的学习到Bullet的API. 首先,我们假设你的Bullet已经正确安装并且正确设置了Bullet的include路径(例如. /usr/local/include/bullet) 确保能连接到正确的lib. 否则请参阅Installation安装. 如果你用的是gcc来编译,请确保你的静态库反序,就是说. dynamics, collision, math.


初始化程序

以一个标准的hello world程序开始:

  1. #include <iostream>   
  2.         int main ()  
  3.         {  
  4.                 std::cout << "Hello World!" << std::endl;  
  5.                 return 0;  
  6.         }  
#include <iostream>
        int main ()
        {
                std::cout << "Hello World!" << std::endl;
                return 0;
        }

创建世界

现在我们要添加一个子弹(Bullet)模拟. 首先写入以下语句:

#include <btBulletDynamicsCommon.h>

我们想把btDiscreteDynamicsWorld 实例化但是在做此之前我们还需要解决一些其他事情. 对于一个“hello world”例子来说它太复杂我们并不需要. 但是,为了能更符合我们自己的工程, 他们可以用来微调(fine-tuning)模拟环境.

我们需要指出使用什么样的 Broadphase algorithm(宽相算法). 选择什么样的泛型算法很总要,如果有许多刚体在绘制场景里, since it has to somehow check every pair which when implemented naively(天真) is an O(n^2) problem.

宽相(broadphase)使用 传统的近似物体形状并且被称之为代理.我们需要提前告诉子弹最大的代理数, 所以才能很好的分配内存避免浪费. 下面就是世界里任何时候的最大刚体数.

int maxProxies = 1024;

一些 broadphases 使用特殊的结构要求世界的尺度提前被告知, 就像我们现在遇到的情况一样. 该broadphase可能开始严重故障,如果离开这个物体体积. 因为 the AxisSweep broadphase quantizes 空间基于我们使用的整个空间的大小, 您想这差不多等于你的世界.

使它小于你的世界将导致重大问题, 使它大于你的世界将导致低劣的性能.这是你程序调整的一个简单部分, 所以为了确保数字的正确多花点时间也不防.

在这个例子中,世界从起点开始延伸10公里远。

  1. btVector3 worldAabbMin(-10000,-10000,-10000);  
  2. btVector3 worldAabbMax(10000,10000,10000);  
btVector3 worldAabbMin(-10000,-10000,-10000);
btVector3 worldAabbMax(10000,10000,10000);

这个broadphase是我们将要使用的, 这个执行的是扫描和裁剪, 这里可以看到更多解释Broadphase .

  1. btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);  
btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);

该broadphase是一个极好的空间以消除不应碰撞的成队物体. 这是为了提高运行效率.

您可以使用碰撞调度注册一个回调,过滤器重置broadphase代理,使碰撞系统不处理系统的其它无用部分

. 更多信息请看 Collision Things.

碰撞配置可以让你微调算法用于全部(而不是不是broadphase )碰撞检测。这个方面现在还属于研究阶段

  1. btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();  
  2. btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);  
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);

我们还需要一个"solver". 这是什么原因导致物体进行互动得当,考虑到重力,游戏逻辑等的影响,碰撞,会被制约。

它工作的很好,只要你不把它推向极端,对于在任何高性能仿真都有瓶颈有一些相似的可以线程模型:

  1. btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;  
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

终于我们可以初始化了世界了:

  1. btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);  
btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);

很明显我们把重力方向设置成了Y轴的负方向,即Y轴是像上的

  1. dynamicsWorld->setGravity(btVector3(0,-10,0));  
dynamicsWorld->setGravity(btVector3(0,-10,0));

子弹的政策是“谁分配,也删除” 记住,必须符合这样的结果

在main()后记的删除.

我们提供了一个通用的结果. 代码如下:

  1. #include <btBulletDynamicsCommon.h>   
  2. #include <iostream>   
  3.   
  4. int main () {  
  5.     std::cout << "Hello World!" << std::endl;  
  6.    
  7.     // Build the broadphase   
  8.     int maxProxies = 1024;  
  9.     btVector3 worldAabbMin(-10000,-10000,-10000);  
  10.     btVector3 worldAabbMax(10000,10000,10000);  
  11.     btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);  
  12.    
  13.     // 设置好碰撞属性 和调度   
  14.     btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();  
  15.     btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);  
  16.    
  17.     // 实际上的物理模拟器   
  18.     btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;  
  19.    
  20.     // 世界.   
  21.     btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);  
  22.    
  23.     // 这里做一些你想做的事   
  24.    
  25.     // 作为一个好的编程习惯 做好删除工作   
  26.     delete dynamicsWorld;  
  27.     delete solver;  
  28.     delete dispatcher;  
  29.     delete collisionConfiguration;  
  30.     delete broadphase;  
  31.    
  32.     return 0;  
  33. }  
#include <btBulletDynamicsCommon.h>
#include <iostream>

int main () {
    std::cout << "Hello World!" << std::endl;
 
    // Build the broadphase
    int maxProxies = 1024;
    btVector3 worldAabbMin(-10000,-10000,-10000);
    btVector3 worldAabbMax(10000,10000,10000);
    btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);
 
    // 设置好碰撞属性 和调度
    btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
 
    // 实际上的物理模拟器
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
 
    // 世界.
    btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
 
    // 这里做一些你想做的事
 
    // 作为一个好的编程习惯 做好删除工作
    delete dynamicsWorld;
    delete solver;
    delete dispatcher;
    delete collisionConfiguration;
    delete broadphase;
 
    return 0;
}



碰撞包围体

我们将创造一个接地平面[静态刚体] ,和一个球体,将属于在地上[动态刚体] 。每个刚体需要参考碰撞包围体. 碰撞包围体只解决碰撞检测问题, 因此没有质量,惯性,恢复原状等概念. 如果您有许多代理,使用相同的碰撞形状[例如每飞船模拟是一个5单元半径范围]。这是个好做法,只有一个子弹形状的碰撞,并分享它在所有这些代理. 但是我们这里的两个刚体形状都不一样,所以他们需要各自的shape.

地面通常是向上的并且里原始点1米的样子. 地面会和远点交叉,但子弹不允许这样做,

因此,我们将抵消它的1米和用来弥补,当我们把刚体设置好以后。

  1. btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);  
btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);

我们将让它从天上掉下来,它是一个球体,半径为1米.

  1. btCollisionShape* fallShape = new btSphereShape(1);  
btCollisionShape* fallShape = new btSphereShape(1);

这里需要做碰撞形状的清理工作.


刚体

在,我们可以添加形状的碰撞到我们的现场,并将它们定位.

让我们先初始化地面. 它的方向是特定的, 子弹的四元数形式 x,y,z,w . 位置在地面下一米, 将要补充一米我们不得不做的. 运动状态在这里可以得到详细的说明:MotionStates

  1. btDefaultMotionState* groundMotionState =  
  2.                 new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));  
btDefaultMotionState* groundMotionState =
                new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));

在第一个和最后一个参数,在下面的构造函数中是质量和地表的惯性. 由于地面是静止的所以我们把它设置成0. 固定不动的物体,质量为0 -他是固定的.

  1. btRigidBody::btRigidBodyConstructionInfo  
  2. groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));  
  3. btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);  
btRigidBody::btRigidBodyConstructionInfo
groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);


最后我们把地面加到世界中:

  1. dynamicsWorld->addRigidBody(groundRigidBody);  
dynamicsWorld->addRigidBody(groundRigidBody);

新增下跌领域非常相似。我们将其置于50米以上的地面.

  1. btDefaultMotionState* fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,50,0)));  
btDefaultMotionState* fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,50,0)));

由于它是动态刚体,我们将给予质量1公斤。我不记得如何计算一个球体的惯性,但是,这并不重要,因为子弹提供它的实现

  1. btScalar mass = 1;  
  2. btVector3 fallInertia(0,0,0);  
  3.  fallShape->calculateLocalInertia(mass,fallInertia);  
btScalar mass = 1;
btVector3 fallInertia(0,0,0);
 fallShape->calculateLocalInertia(mass,fallInertia);

现在,我们可以建造刚体只是像以前一样,并把它加到世界中:

  1. btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);  
  2. btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);  
  3. dynamicsWorld->addRigidBody(fallRigidBody);  
btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);
btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);
dynamicsWorld->addRigidBody(fallRigidBody);

一个快速的解释btRigidBody::btRigidBodyConstructionInfo是为了; 物体的构建是通过某些参数的. 这是通过一个特殊的结构实现的。 该部分的btRigidBodyConstructionInfo被复制到物体当你建造的时候,并只用于在初始化的时候. 如果你想创建几千个属性一样的物体, 你只需要建立一个btRigidBodyConstructionInfo, 并通过它创建所有的.


开始模拟

这就是有趣的开始。我们会加强模拟200倍,间隔60赫兹. 这使它有足够的时间降落的地面上. 每一步, 我们都会打印出它离地面的高度.

这stepSimulation 在做你所期待, 不过他的接口确实很复杂. 读Stepping The World 以获得更多消息.

进后,我们审查的状态下降领域.位置和方向都封装在btTranform对象,我们摘录下降领域的运动状态. 我们只关心位置,我们退出变换getOrigin ( ) 。然后,我们打印y组成部分的立场载体.

  1. for (int i=0 ; i<300 ; i++) {  
  2.          
  3.                 dynamicsWorld->stepSimulation(1/60.f,10);  
  4.                  
  5.                 btTransform trans;  
  6.                 fallRigidBody->getMotionState()->getWorldTransform(trans);  
  7.          
  8.                 std::cout << "sphere height: " << trans.getOrigin().getY() << std::endl;  
  9.         }  
for (int i=0 ; i<300 ; i++) {
       
                dynamicsWorld->stepSimulation(1/60.f,10);
               
                btTransform trans;
                fallRigidBody->getMotionState()->getWorldTransform(trans);
       
                std::cout << "sphere height: " << trans.getOrigin().getY() << std::endl;
        }


这应该产生一个输出看起来像这样的东西:

sphere height: 49.9917

        sphere height: 49.9833

        sphere height: 49.9722

        sphere height: 49.9583

        sphere height: 49.9417

        sphere height: 49.9222

        sphere height: 49.9

        ...

        sphere height: 1

        sphere height: 1

        sphere height: 1

        sphere height: 1

        sphere height: 1

看起来不错迄今。如果你图这对输出迭代次数,你就会得到这个:


这个球体开始于地表的一米处. 这是因为取的是几何中心并且它的半径为1米. 这个球刚开始会有一个大的反弹然后渐渐的减缓弹起高度.

这是可以预料的实时物理引擎,但它可以尽量减少,增加频率的模拟步骤

. 试试再说!

现在你可以把这个动态世界代入你的程序 实时绘制出这个球体. 也可以看看其他的 Collision Shapes . 试试一堆盒子 或者圆柱体然后用一个球去扔向他们.


完整代码

  1. #include <iostream>   
  2.    
  3. #include <btBulletDynamicsCommon.h>   
  4.    
  5. int main (void)  
  6. {  
  7.    
  8.         btVector3 worldAabbMin(-10000,-10000,-10000);  
  9.         btVector3 worldAabbMax(10000,10000,10000);  
  10.         int maxProxies = 1024;  
  11.         btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);  
  12.    
  13.         btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();  
  14.         btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);  
  15.    
  16.         btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;  
  17.    
  18.         btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);  
  19.    
  20.         dynamicsWorld->setGravity(btVector3(0,-10,0));  
  21.    
  22.         btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);  
  23.    
  24.         btCollisionShape* fallShape = new btSphereShape(1);  
  25.    
  26.         btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));  
  27.         btRigidBody::btRigidBodyConstructionInfo  
  28.                 groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));  
  29.         btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);  
  30.         dynamicsWorld->addRigidBody(groundRigidBody);  
  31.    
  32.         btDefaultMotionState* fallMotionState =  
  33.                 new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,50,0)));  
  34.         btScalar mass = 1;  
  35.         btVector3 fallInertia(0,0,0);  
  36.         fallShape->calculateLocalInertia(mass,fallInertia);  
  37.         btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);  
  38.         btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);  
  39.         dynamicsWorld->addRigidBody(fallRigidBody);  
  40.    
  41.         for (int i=0 ; i<300 ; i++) {  
  42.                 dynamicsWorld->stepSimulation(1/60.f,10);  
  43.    
  44.                 btTransform trans;  
  45.                 fallRigidBody->getMotionState()->getWorldTransform(trans);  
  46.    
  47.                 std::cout << "sphere height: " << trans.getOrigin().getY() << std::endl;  
  48.         }  
  49.    
  50.         dynamicsWorld->removeRigidBody(fallRigidBody);  
  51.         delete fallRigidBody->getMotionState();  
  52.         delete fallRigidBody;  
  53.    
  54.         dynamicsWorld->removeRigidBody(groundRigidBody);  
  55.         delete groundRigidBody->getMotionState();  
  56.         delete groundRigidBody;  
  57.    
  58.         delete fallShape;  
  59.    
  60.         delete groundShape;  
  61.    
  62.         delete dynamicsWorld;  
  63.         delete solver;  
  64.         delete collisionConfiguration;  
  65.         delete dispatcher;  
  66.         delete broadphase;  
  67.    
  68.         return 0;  
  69. }  
#include <iostream>
 
#include <btBulletDynamicsCommon.h>
 
int main (void)
{
 
        btVector3 worldAabbMin(-10000,-10000,-10000);
        btVector3 worldAabbMax(10000,10000,10000);
        int maxProxies = 1024;
        btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies);
 
        btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
        btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
 
        btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
 
        btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
 
        dynamicsWorld->setGravity(btVector3(0,-10,0));
 
        btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),1);
 
        btCollisionShape* fallShape = new btSphereShape(1);
 
        btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,-1,0)));
        btRigidBody::btRigidBodyConstructionInfo
                groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
        btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
        dynamicsWorld->addRigidBody(groundRigidBody);
 
        btDefaultMotionState* fallMotionState =
                new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,50,0)));
        btScalar mass = 1;
        btVector3 fallInertia(0,0,0);
        fallShape->calculateLocalInertia(mass,fallInertia);
        btRigidBody::btRigidBodyConstructionInfo fallRigidBodyCI(mass,fallMotionState,fallShape,fallInertia);
        btRigidBody* fallRigidBody = new btRigidBody(fallRigidBodyCI);
        dynamicsWorld->addRigidBody(fallRigidBody);
 
        for (int i=0 ; i<300 ; i++) {
                dynamicsWorld->stepSimulation(1/60.f,10);
 
                btTransform trans;
                fallRigidBody->getMotionState()->getWorldTransform(trans);
 
                std::cout << "sphere height: " << trans.getOrigin().getY() << std::endl;
        }
 
        dynamicsWorld->removeRigidBody(fallRigidBody);
        delete fallRigidBody->getMotionState();
        delete fallRigidBody;
 
        dynamicsWorld->removeRigidBody(groundRigidBody);
        delete groundRigidBody->getMotionState();
        delete groundRigidBody;
 
        delete fallShape;
 
        delete groundShape;
 
        delete dynamicsWorld;
        delete solver;
        delete collisionConfiguration;
        delete dispatcher;
        delete broadphase;
 
        return 0;
}


 

 

http://www.cnblogs.com/hzhg/archive/2010/12/17/1908751.html

http://hi.baidu.com/kenshin1987/blog/item/9fe00afb8134878f9f51468c.html

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值