Bullet物理引擎在OpenGL中的应用

在开发OpenGL的应用之时, 难免要遇到使用物理来模拟OpenGL中的场景内容. 由于OpenGL仅仅是一个关于图形的开发接口, 因此需要通过第三方库来实现场景的物理模拟. 目前我选择 Bullet 物理引擎, 其官方网站为 Bullet, 开发库的下载地址则在 github 上.


1. OpenGL 环境

首先我们需要搭建框架, OpenGL 的基本框架这里不详述, 我个人是在几何着色器内实现光照, 这是由于我实现的是面法线. 另外用到的其他三方库有 GLFW 和 GLM库, 前者有助于管理OpenGL窗口, 后者省却了自己写数学公式代码的过程. 另外实现了立方体模型和球体的创建, 满足学习 Bullet 的需要即可.


2. 物理环境的初始化

对于 Bullet 物理库而言, 它的搭建也很简单, 在初始化 OpenGL 的上下文的时候, 也可以初始化我们的物理环境, 参考物理库自带的 HelloWorld 即可, 相关代码为:

  1. ///collision configuration contains default setup for memory, collision setup
  2. m_collisionConfiguration = new btDefaultCollisionConfiguration();
  3. //m_collisionConfiguration->setConvexConvexMultipointIterations();
  4. ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
  5. m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
  6. m_broadphase = new btDbvtBroadphase();
  7. ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
  8. btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
  9. m_solver = sol;
  10. m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
  11. m_dynamicsWorld->setGravity(btVector3(0, -10, 0));

3. 物理环境的销毁

相应的, 还有清理代码

  1. std::vector<ModelInfo>::iterator it = m_models.begin();
  2. while(it != m_models.end())
  3. {
  4. ModelInfo info = *it;
  5. delete info.model;
  6. m_dynamicsWorld->removeRigidBody(info.obj);
  7. it++;
  8. }
  9. m_models.clear();
  10. for (int j=0;j<m_collisionShapes.size();j++)
  11. {
  12. btCollisionShape* shape = m_collisionShapes[j];
  13. m_collisionShapes[j] = 0;
  14. delete shape;
  15. }
  16. //delete dynamics world
  17. delete m_dynamicsWorld;
  18. //delete solver
  19. delete m_solver;
  20. delete m_broadphase;
  21. delete m_dispatcher;
  22. delete m_collisionConfiguration;
  23. //next line is optional: it will be cleared by the destructor when the array goes out of scope
  24. m_collisionShapes.clear();

在我的实现内, 结构体 ModelInfo 是一个自定义的结构体(struct), 我通过该结构体的容器保存了所有物体的物理模型以及其对应OpenGL模型的关系, 这样在物理库更新一个物体的位置和方向时, 我们就可以在 OpenGL 内更新物体的位置和方向.

4. 物理世界的渲染

下面是我渲染物理世界中所有模型的代码, 计算出所有模型的变换矩阵, 而后通知其相关代码进行渲染.

  1. void PhysicsBaseWorld::render()
  2. {
  3. std::vector<ModelInfo>::iterator it = m_models.begin();
  4. while(it != m_models.end())
  5. {
  6. ModelInfo info = *it;
  7. btRigidBody* obj = info.obj;
  8. btRigidBody* body = btRigidBody::upcast(obj);
  9. btTransform trans;
  10. if (body && body->getMotionState())
  11. {
  12. body->getMotionState()->getWorldTransform(trans);
  13. } else
  14. {
  15. trans = obj->getWorldTransform();
  16. }
  17. glm::vec3 position = glm::vec3(float(trans.getOrigin().getX()),float(trans.getOrigin().getY()),float(trans.getOrigin().getZ()));
  18. btQuaternion rot = trans.getRotation();
  19. glm::quat q = glm::quat(rot.getW(), rot.getX(), rot.getY(), rot.getZ());
  20. glm::mat4 rot4 = glm::toMat4(q);
  21. glm::mat4 m = glm::translate(glm::mat4(1.0), position) * rot4;
  22. Model* model = info.model;
  23. model->setModelMat(m);
  24. model->render();
  25. it++;
  26. }
  27. }

5. 绘制静态的物体

在创建物理世界的过程中, 物理库中主要使用函数 createRigidBody() 来创建刚体模型, 其主要有三个参数, 分别表示质量, 变换, 形状. 其中质量为 0 的物体为静止物体, 可以用来创建地面或者路边的石头之类的物体模型. 创建静止立方体模型的代码

  1. ///create a few basic rigid bodies
  2. btCollisionShape* shape = new btBoxShape(btVector3(halfsize[0],halfsize[1],halfsize[2]));
  3. m_collisionShapes.push_back(shape);
  4. btTransform transform;
  5. transform.setIdentity();
  6. transform.setOrigin(btVector3(pos[0], pos[1], pos[2]));
  7. {
  8. btScalar mass(0.);
  9. btRigidBody* body = createRigidBody(mass,transform,shape);
  10. Cube* cube = new Cube(halfsize[0],halfsize[1],halfsize[2]);
  11. cube->setColor(col);
  12. ModelInfo info = {body, cube};
  13. m_models.push_back(info);
  14. }

上面的代码创建的过程中, 我同时创建了一个对应的 OpenGL 立方体.

6. 绘制可活动的物体

创建可活动模型时需要设置相关的运动状态信息

  1. btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));
  2. //rigidbody is dynamic if and only if mass is non zero, otherwise static
  3. bool isDynamic = (mass != 0.f);
  4. btVector3 localInertia(0, 0, 0);
  5. if (isDynamic)
  6. shape->calculateLocalInertia(mass, localInertia);
  7. btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
  8. btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);
  9. btRigidBody* body = new btRigidBody(cInfo);
  10. body->setUserIndex(-1);
  11. m_dynamicsWorld->addRigidBody(body);
  12. btBoxShape* s = dynamic_cast<btBoxShape*>(shape);
  13. if(s != 0)
  14. {
  15. btVector3 size = s->getHalfExtentsWithMargin();
  16. Cube* cube = new Cube(size.getX(), size.getY(), size.getZ());
  17. cube->setColor(col);
  18. ModelInfo info = {body, cube};
  19. m_models.push_back(info);
  20. }
  21. return body;

7. 更新物理世界

最后我们需要时刻更新物理世界中的模型位置和方位

  1. m_dynamicsWorld->stepSimulation(elpasedTime, 0);

Bullet物理引擎在OpenGL中的应用的更多相关文章

  1. bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...

  2. Bullet物理引擎的安装与使用

    图形赋予游戏一种视觉的吸引力,但是能够让游戏的世界鲜活起来的还应该是内部的物理引擎.物理引擎是游戏引擎中的子模块,是一种软件组件,可仿真物理系统.它根据牛顿力学定律,计算游戏中物体的合理的物理位置,并 ...

  3. 将 Android* Bullet 物理引擎移植至英特尔&#174; 架构

    简单介绍 因为眼下的移动设备上可以使用更高的计算性能.移动游戏如今也可以提供震撼的画面和真实物理(realistic physics). 枪战游戏中的手雷爆炸效果和赛车模拟器中的汽车漂移效果等便是由物 ...

  4. 转:Bullet物理引擎不完全指南(Bullet Physics Engine not complete Guide)

    write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 前言 Bullet据称为游戏世界占有率为第三的物理引擎,也是前几大引擎目前唯一能够 ...

  5. 【Bullet引擎】Bullet物理引擎简单说明

    说明 Bullet是一款开源的物理模拟计算引擎,包括刚体.柔体.弹性体等,是世界三大物理模拟引擎之一(包括Havok和PhysX),被广泛应用于游戏开发(GTA5等)和电影(2012等)制作中. Bu ...

  6. 链接收藏:bullet物理引擎不完全指南

    这个也是博客园的文章,编辑得也很好,就不copy了,结尾还有PDF: https://www.cnblogs.com/skyofbitbit/p/4128347.html 完结

  7. cocos2d-x中的Box2D物理引擎

    在Cocos2d-x中集成了2个物理引擎,一个是Chipmunk,一个是Box2D.前者是用C语言编写的,文档和例子相对较少:Box2D是用C++写的,并且有比较完善的文档和资料.所以在需要使用物理引 ...

  8. 【AwayPhysics学习笔记】:Away3D物理引擎的简介与使用

    首先我们要了解的是AwayPhysics这个物理引擎并不是重头开始写的新物理引擎,而是使用Flascc技术把一个已经很成熟的Bullet物理引擎引入到了Flash中,同时为了让as3可以使用这个C++ ...

  9. 【Unity 3D】学习笔记三十六:物理引擎——刚体

    物理引擎就是游戏中模拟真是的物理效果.如两个物体发生碰撞,物体自由落体等.在unity中使用的是NVIDIA的physX,它渲染的游戏画面很逼真. 刚体 刚体是一个很很中要的组件. 默认情况下,新创的 ...

随机推荐

  1. 第九周PSP

     工作周期:11.10-11.17 本周PSP: C类型 C内容 S开始时间 ST结束时间 I中断时间 T净时间(分) 文档 写随笔(PSP) 19:00min 22:00min 30min 90mi ...

  2. 识别有效的IP地址和掩码并进行分类统计

    该题我的想法是把每一个ip看出一个整数,将读取得到的数据一一与给定的ip范围比较即可.另外本题应该注意的地方是scanf读取俩字符串的方法. 代码如下: #include<stdio.h> ...

  3. Xamarin踩坑经历

    1.SDK版本 Android SDK Build-tools必须安装23.0.1版,不得升级高版本,否则将导致异常:尝试在条件"$(_DeviceSdkVersion) >= 21& ...

  4. H5学习系列之Communication API

    1 .postMessage API 首先介绍一下什么是iframe? 百度百科里这样写道:IFRAME,HTML标签,作用是文档中的文档,或者浮动的框架(FRAME). 我的理解就是网页中的网页. ...

  5. Getting Started With Hazelcast 读书笔记(第四章)

    第四章 分而治之 在指导了如何进行基本使用之后,又再次进入理论模块. Hazelcast的基本策略就是切片分区,默认是271个片.内置一个 partition table记录那个节点是那个分区,并在h ...

  6. <<Design Patterns>> Gang of Four

    One:Introduction: One-1:Before  delving into the  some twenty pattern designs, it's necessary for ME ...

  7. 1075 PAT Judge (25)

    排序题 #include <stdio.h> #include <string.h> #include <iostream> #include <algori ...

  8. linq group by max 多表链接实例

    SELECT s.* FROM dbo.ERG_TipOffsInfo s, (SELECT Data,MAX(Createtime) max_Time FROM dbo.ERG_TipOffsInf ...

  9. Java编程中“为了性能”尽量要做到的一些地方

    最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了. 下面是参考网络资源总结的一些在Ja ...

  10. 【转】linux yum命令详解

    yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器.基於RPM包管理,能够从指定的服务器自动下载RP ...