Bullet物理引擎不完全指南(Bullet-Physics-Engine-not-complete-Guide)

更新时间:2023-06-26 22:10:11 阅读: 评论:0

Bullet物理引擎不完全指南(Bullet Physics Engine not complete Guide)Bullet物理引擎不完全指南(Bullet Physics Engine not complete Guide)
write by 九天雁翎(JTianLing) -- blog.csdn/vagrxie
讨论新闻组及文件
前言 Bullet据称为游戏世界占有率为第三的物理引擎,也是前几大引擎目前唯一能够找到的支持iPhone,开源,免费(Zlib协议,非常自由,且商业免费)的物理引擎,但是文档资料并不是很好,Demo虽然多,但是主要出于特性测试/展示的目的,会让初学者无从看起,一头雾水。我刚学习Bullet的时候困于没有好的文档及资料,非常没有头绪,折腾了很久,所以就发挥没有就创造的精神,写作及整理此文,(以整理资料为主,自己写 为辅)希望大家在学习Bullet的时候不要再像我开始一样没有头绪。因为我实在没有精力去完成一个包含Bullet方方面面的完全指南,所以本文只能是不完全版本,这个就请大家谅解了,但是期望能够真正的完成一个简单的由浅入深的教程,并提供尽量详尽的额外信息链接,只能说让初学者比看官方的WIKI和Demo效果更好,大家有好的信息和资料而本文没有包含的,也请告诉我,我可以在新版中添加进来。因为我学习Bullet的时间也比较短,有不对的地方请高人指点。 前段时间简单的学习了一下Bullet,牵涉到图形部分的时候主要都是研究Bullet与Ogre的结合,所以使用了OgreBullet这个Ogre的Addon,其实真正的学习当然还是直接利用Bullet本身附带的简单的debug Ope
nGL绘制就好了。本文就完全以Bullet本身的Debug功能来学习,虽然简陋,但是可以排除干扰,专注于bullet。也许除了本文,会有个额外的文章,稍微研究下Ogre与Bullet的整合和分析一下OgreBullet的源码。
Bullet介绍 Bullet的主页。最新版本在这里下载。简单的中文介绍见百度百科。一些也许可以促使你选择Bullet的小故事在以前的文章中有提及,参考这里的开头--为什么选择Bullet。很遗憾的是前几天看到的一篇很详细的bullet中文介绍找不到了,将来也许补上。士怎么组词
安装 Bullet作为一款开源物理引擎,你可以选择作者编译好的SDK,或者直接从源码编译自己的版本(Windows版本自带VS工程)。得益于CMake,在其他平台从源码自己编译也非常简单,参考这里。iPhone版本的话参考这里。想要更详细点的图文教程可以参考Creating_a_project_from_scratch。
Hello World Application 在学习之前,没有接触过物理引擎的可以参考一下这个术语表。 这里有个较为详细的教程。也包含在Bullet本身的一个名叫 AppHelloWorld 的Demo中。(注释也很详细,但是和WIKI上的版本略有不同)可以大概的对Bullet有个感觉。 其实Bullet与Ogre走的一条路线,为了
灵活,增加了很多使用的复杂性。(真怀念Box2D和Irrlicht的简单啊)其实即使希望通过strategy模式来增加灵活度,让用户可以自由的选择各类算法和解决方案,但是我还是感觉首先提供默认解决方案,
弘扬传统文化手抄报用户需要不同方案的时候通过Set方式改变(甚至也可以new的时候修改)但是大牛们研究这些东西那么透,总是会觉得这个世界上不存在默认方案。。。。。因为没有方案是最优的,是适合大多数情况的,所以导致Bullet的HelloWorld程序源代码都已经超过100行。。。。。。。。。。-_-!发了点牢骚。。。。。 通过HelloWorld程序,我们大概可以知道一些东西,比如建立一个Bullet物理世界的步骤,比如Bullet的类以bt(变态-_-!)开头,比如Bullet与Box2D这样的2D物理引擎一样,专注于数据的计算,本身没有图形输出,比如创建一个物理实体的时候也有shape的概念,然后通过一个结构作为参数(BodyConstructionInfo)来创建真实的物体,大概的熟悉一下就好,具体的细节还不懂,没有关系,一步一步来。 另外,建议趁这个机会,确定自己机器使用Bullet的环境,特别是Win32下,我的使用方法是,利用BULLET_HOME环境变量指明Bullet安装的位置,BULLTE_LIBS指明最后编译完的静态库的位置,工程中利用这两个环境变量来确定位置。(这种用法很适合屏蔽各机器的环境不同)最后的Hello World工程见/hg/中的Bullet-HelloWorld。 请确保该Hello World程序能够运行(无论是你自己的还是用我的)然后才继续下面的内容。
让你坐在司机的位置上 该怎么学习的问题,向来都是各执一词,有人认为该从最基础的学起,就像建房子一样打好地基,有人会更加推崇自上而下的学习(Top-Down Approach),我属于后一派,能先写有用的可以摸到的程序,然后一层一层的向下学习,这样会更加有趣味性,并且学习曲线也会更加平缓,假如你是前一派,那么推荐你先看完Bullet的Ur Manual,然后是Bullet所有的Tutorial Articles,
然后再自己一个一个看Demo。 在Hello World的例子中你已经可以看到文本数据的输出,能够看到球/Box的落下了,但是很明显太不直观了,得益于Bullet良好的debug输出支持,我们要先能直观的通过图形看到球的落下!先坐在司机的位置上才能学会开车^^你也不至于被乏味的汽车/交通理论闷死。 Bullet像Ogre一样,提供了一个DemoApplication类,方便我们学习,我们先看看Bullet的DemoApplication是怎么样的。先看看Bullet自己提供的AppBasicDemo这个Demo。忽略那些作者用#if 0关闭的内容和hashmap的测试内容,看看DemoApplication的用法。首先是BasicDemo类,从class BasicDemo : public PlatformDemoApplication可以看到
四季诗句春夏秋冬
,DemoApplication是给你继承使用的,这里的PlatformDemoApplication实际是GlutDemoApplication。(Win32那个作者好像只是预留的)怎么去实现这个类先放一边,看看整个类的使用: GLDebugDrawer gDebugDrawer; BasicDemo ccdDemo; ccdDemo.initPhysics(); DynamicsWorld()->tDebugDrawer(&gDebugDrawer); glutmain(argc, argv,640,480,"Bullet Physics Demo. ",&ccdDemo);实际就这5句,很简单,构造debug,BasicDemo,调用initPhysics函数,设定debug,调用glutmain这个函数,参数也一目了然。这里就不看了。看实现一个有用的DemoApplication的过程。 大概看看DemoApplication这个基类和GlutDemoApplication知道必须要实现的两个纯虚函数是virtual void initPhysics() = 0;virtual void clientMoveAndDisplay() = 0;看BasicDemo的实现后,知道还需要实现displayCallback这个现实回调,
基本上就没有其他东西了,理解起来也还算容易。initPhysics的部分,一看就知道,与HelloWorld中过程几乎一致,也就是实际构建物理世界的过程。只是多了 tTexturing(true);tShadows(true);tCameraDistance(btScalar(SCALING*50.));这三个与显示有关的东西(其实这些代码放到myinit中去也可以,毕竟与物理无关)最后还多了个clientRetScene的调用,我们知道这个过程就好,具体函数的实现先不管。clientMoveAndDisplay和displayCallback部分其实非常简单,几乎可以直接放到glutExampleApplication中去。(事实上不从灵活性考虑,我觉得放到glutExampleApplication中更好)原来的程序有些代码重复,其实只要下列代码就够了:(一般的程序也不需要修改)voidBasicDemo::clientMoveAndDisplay() { //simple dynamics world doesn't handle fixed-time-stepping floatms = getDeltaTimeMicroconds();  ///step the simulation if(m_dynamicsWorld) { m_dynamicsWorld->stepSimulation(ms / 1000000.f); }  displayCallback(); }voidBasicDemo::displayCallback(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  renderme(); //optional but uful: debug drawing to detect problems if(m_dynamicsWorld) m_dynamicsWorld->debugDrawWorld(); glFlush(); swapBuffers(); }运行该程序能够看到中间一个很多Box堆起来的大方块,点击鼠标右键还能发射一个方块出去。了解这个Demo以后,我们就可以直接来用Bullet构建我们自己的物理世界了,暂时不用考虑图形的问题,甚至不用知道Bullet使用GLUT作为debug图形的输出,GLUI做界面,都不用知道,只需要知道上面demoApplication的使用和在initPhysics函数中完成构建物理世界的代码。另外,你愿意的话,也可以
先看看exitPhysics的内容,用于分配资源的释放,作为C++程序,一开始就关注资源的释放问题是个好习惯。虽然对于我们这样简单的demo程序来说是无所谓的。看过上面Demo后,也许你已经有些了解,也许你还是一头
喜欢的英语雾水,不管怎么样,Bullet的Demo毕竟还是别人的东西,现在,从零开始,构建一个HelloWorld程序描述的世界。先自己尝试一下!假如你成功了,那么直接跳过一下的内容,失败了,再回头了看看,提醒你步骤:1.继承DemoApplication,拷贝上面clientMoveAndDisplay和displayCallback部分的代码,实现这两个函数。2.在initPhysics函数中完成构建物理世界的代码。(构建过程参考HelloWorld)3.Main中的使用代码: GLDebugDrawer gDebugDrawer; BasicDemo ccdDemo; ccdDemo.initPhysics(); DynamicsWorld()->tDebugDrawer(&gDebugDrawer); glutmain(argc, argv,640,480,"Bullet Physics Demo. ",&ccdDemo);4.注意工程需要多包含$(BULLET_HOME)/Demos/OpenGL的头文件目录和库:$(BULLET_HOME)/Glut/glut32.libopengl32.libglu32.lib麻烦点的是glut是个动态库,你需要将dll文件拷贝到你工程的运行目录。现在应该成功了吧?我实现的工程见/hg/中的Bullet-WithGL。于是乎,现在你已经可以看到Hello World中那个不曾显示的电脑凭空现象的球了。大概是下面这个样子滴:(因为现在Google Docs写完文章后很久就不能够直接post到CSDN的博客中去了,所以每次写完文章后都得到新建文章中去复制粘贴,图
如何关心女朋友片还需要重新上传然后插入,非常麻烦,所以最近的文章都尽量的减少了图片的使用,见谅。其实说来,只有看热闹的人才需要截图,真的看教程的人估计自己的程序都已经运行起来了,也没有必要看我的截图了)
到目前为止,你已经有了可以自己happy一下的程序了,你可以立即深入的学习,去研究ExampleApplication的源代码,去了解Bullet是怎么与图形交互的,但是在这个之前,特别是对于以前没有使用过其他物理引擎的人,先多在这个图形版的HelloWorld的程序的基础上玩玩,比如现在球很明显没有弹性,调整一下反弹的系数看看,比如多生成几个球,比如加上速度,演示两个球的碰撞,比如因为现在没有设置debugmode,所以实际没有debug信息输出,尝试输出aabb等debug信息,有助于进一步学习。有了图形,就有了丰富的世界,先对Bullet的各个概念先熟悉一下(特别是btRigidBodyConstructionInfo中的各个变量,还有各个shape)然后再前进吧。事实上,得益于ExampleApplication,现在甚至可以用鼠标左键拖拽物理,右键发射箱子的功能也还在,还能按左右键调整camera。(其实还有一堆功能,自己尝试一下吧)因为比较简单,在本教程中不会再有关于这些基础信息的内容,只能自己去找资料或者尝试了。其实就我使用物理引擎的经验,学习并使用一款物理引擎并不会太难,最麻烦的地方在于后期游戏中各个参数的调整,尽量使游戏的
效果变得真实,自然,或者达到你想要的效果,这种调整很多时候需要靠你自己的感觉,而这个感觉的建立,那就是多多尝试一个物理引擎中的在各个参数下呈现的不同效果了,这种感觉的建立,经验
的获得,不是任何教程,文档或者演示程序能够给你的。比如,下面是Bullet支持的5种基本物体形状:
其实上面的内容是最关键的,此时学开车的你已经在司机的位置了,学游泳的你已经在水里了,剩下的Bullet相关的内容虽然还有很多,但是其实已经完全可以自己独立折腾了,因为每个折腾的成果你都已经能够实时的看到,能够很哈皮的去折腾了。
与显示的整合,MotionState 一个只有数据运算的物理引擎,一般而言只能为显示引擎提供数据,这就牵涉到与图形引擎整合的问题,像Box2D这样的物理引擎就是直接需要直接向各个物理实体去查询位置,然后更新显示,这种方式虽然简单,但是我感觉非常不好,因为难免在update中去更新这种东西,导致游戏逻辑部分需要处理物理引擎+图形引擎两部分的内容。(可以参考Box2D与Cocos2D for iPhone的整合)而且,对于完全没有移动的物体也会进行一次查询和移动操作。(即使优化,对不移动物体也是进行了两次查询) Bullet为了解决此问题,提供了新的解决方案,MotionState。其实就是当活动物体状态改变时提供一种回调,而且就Bullet的文档中说明,此种回调还带有适当的插值以优化显示。通过这种方法,在MotionState部分就已经可以完成显示的更新,不用再需要在update中添加这种更新的代码。而且,注意,仅仅对活动物体状态改变时才会进行回调,这样完全避免了不活动物体的性能损失。 首先看看ExampleApplication中是怎么利用default的MotionState来显示上面的图形的,然后再看看复杂点的例子,与Ogre的整合。先看看回调接口:///The btMotionState interface class all
晶莹剔透怎么写ows the dynamics world to synchronize and interpolate the updated world transforms with graphics///For optimizations, potentially only moving objects get synchronized (using tWorldPosition/tWorldOrientation)class btMotionState { public:  virtual~btMotionState() {  }  virtualvoidgetWorldTransform(btTransform& worldTrans ) const=0; //Bullet only calls the update of worldtransform for active objects virtualvoidtWorldTransform(constbtTransform& worldTrans)=0;  };很简单,一个get接口,用于bullet获取物体的初始状态,一个t接口,用于活动物体位置改变时调用以设置新的状态。下面看看btDefaultMotionState这个bullet中带的默认的MotionState类。///The btDefaultMotionState provides a common implementation to synchronize world transforms with offts.structbtDefaultMotionState : publicbtMotionState { btTransform m_graphicsWorldT
铁锹简笔画
rans; btTransform m_centerOfMassOfft; btTransform m_startWorldTrans; void* m_urPointer; btDefaultMotionState(constbtTransform& startTrans = btTransform::getIdentity(),constbtTransform& centerOfMassOfft = btTransform::getIdentity()) : m_graphicsWorldTrans(startTrans), m_centerOfMassOfft(centerOfMassOfft), m_startWorldTrans(startTrans), m_urPointer(0) { } ///synchronizes world transform from ur to physics virtualvoid getWorldTransform(btTransform& centerOfMassWorldTrans ) const { centerOfMassWorldTrans = m_centerOfMassOfft.inver() * m_graphicsWorldTrans ; } ///synchronizes world transform from physics to ur ///Bullet only calls the
五行属火寓意最好的字update of worldtransform for active objects virtualvoid tWorldTransform(constbtTransform& centerOfMassWorldTrans) { m_graphicsWorldTrans = centerOfMassWorldTrans * m_centerOfMassOfft ; } };这个默认的MotionState实现了这两个接口,但是还引入了质心(center Of Mass应该是指质心吧)的概念,与外部交互时,以质心位置表示实际物体所在位置。在一般rigitBody的构造函数中可以看到下列代码: if(m_optionalMotionState) { m_optionalMotionState->getWorldTransform(m_worldTransform); } el { m_worldTransform = constructionInfo.m_startWorldTransform; }这就是get函数的使用,也就是决定物体初始坐标的函数回调。t函数的回调如下:voidbtDiscreteDynamicsWorld::synchronizeSingleMotionState(btRigidBody* body) { btAsrt(body); if(body->getMotionState() && !body->isStaticOrKinematicObject()) { //we need to call the update at least once, even for sleeping objects //otherwi the 'graphics' transform never updates properly ///@todo: add 'dirty' flag //if (body->getActivationState() != ISLAND_SLEEPING) { btTransform interpolatedTransform; btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(), body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),m_localTime*body->getHitFraction(),interpolatedTransform); body->getMotionState()->tWorldTransform(interpolatedTransform); } } }也就是同步状态的时候调用。此过程发生在调用bullet的btDynamicsWorld::stepSimulation函数调用时。然后可以参考DemoApplication的DemoApplic
ation::renderscene(int pass)函数: btScalar m[16]; btMatrix3x3 rot;rot.tIdentity(); constintnumObjects=m_dynamicsWorld->getNumCollisionObjects(); btVector3 wireColor(1,0,0); for(inti=0;i<numObjects;i++) { btCollisionObject* colObj=m_dynamicsWorld->getCollisionObjectArray()[i]; btRigidBody* body=btRigidBody::upcast(colObj); if(body&&body->getMotionState()) { btDefaultMotionState* myMotionState = (btDefaultMotionState*)body->getMotionState(); myMotionState->OpenGLMatrix(m); rot=myMotionState->Basis(); } }}实际也就是再通过获取motionState然后获取到图形的位置了,这种defaultMotion的使用就类似Box2D中的使用了。既然是回调,那么就可以让函数不仅仅做赋值

本文发布于:2023-06-26 22:10:11,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/1056300.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:物理   引擎   需要   没有   使用
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图