Bullet物理引擎在OpenGL中的应用

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


1. OpenGL 环境

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


2. 物理环境的初始化

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

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

3. 物理环境的销毁

相应的, 还有清理代码

    std::vector<ModelInfo>::iterator it = m_models.begin();
while(it != m_models.end())
{
ModelInfo info = *it;
delete info.model;
m_dynamicsWorld->removeRigidBody(info.obj);
it++;
}
m_models.clear(); for (int j=0;j<m_collisionShapes.size();j++)
{
btCollisionShape* shape = m_collisionShapes[j];
m_collisionShapes[j] = 0;
delete shape;
}
//delete dynamics world
delete m_dynamicsWorld; //delete solver
delete m_solver; delete m_broadphase; delete m_dispatcher; delete m_collisionConfiguration; //next line is optional: it will be cleared by the destructor when the array goes out of scope
m_collisionShapes.clear();

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

4. 物理世界的渲染

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

void PhysicsBaseWorld::render()
{
std::vector<ModelInfo>::iterator it = m_models.begin();
while(it != m_models.end())
{
ModelInfo info = *it;
btRigidBody* obj = info.obj;
btRigidBody* body = btRigidBody::upcast(obj); btTransform trans;
if (body && body->getMotionState())
{
body->getMotionState()->getWorldTransform(trans); } else
{
trans = obj->getWorldTransform();
}
glm::vec3 position = glm::vec3(float(trans.getOrigin().getX()),float(trans.getOrigin().getY()),float(trans.getOrigin().getZ()));
btQuaternion rot = trans.getRotation();
glm::quat q = glm::quat(rot.getW(), rot.getX(), rot.getY(), rot.getZ());
glm::mat4 rot4 = glm::toMat4(q);
glm::mat4 m = glm::translate(glm::mat4(1.0), position) * rot4; Model* model = info.model;
model->setModelMat(m);
model->render();
it++;
}
}

5. 绘制静态的物体

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

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

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

6. 绘制可活动的物体

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

    btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));

    //rigidbody is dynamic if and only if mass is non zero, otherwise static
bool isDynamic = (mass != 0.f); btVector3 localInertia(0, 0, 0);
if (isDynamic)
shape->calculateLocalInertia(mass, localInertia); btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia); btRigidBody* body = new btRigidBody(cInfo); body->setUserIndex(-1);
m_dynamicsWorld->addRigidBody(body); btBoxShape* s = dynamic_cast<btBoxShape*>(shape);
if(s != 0)
{
btVector3 size = s->getHalfExtentsWithMargin();
Cube* cube = new Cube(size.getX(), size.getY(), size.getZ());
cube->setColor(col);
ModelInfo info = {body, cube};
m_models.push_back(info);
} return body;

7. 更新物理世界

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

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. KVC 与 KVO

    一.Key-Value Coding (KVC)键值编码 KVC,即是指 NSKeyValueCoding,一个非正式的 Protocol,提供一种机制来间接访问对象的属性.KVO 就是基于 KVC ...

  2. MFC学习笔记

    获取窗口句柄 FindWindow               根据窗口名获取 GetSafehWnd                取你程序所在窗口类的句柄 GetActiveWindow     ...

  3. C#数据结构选择

    选择一个合适的数据结构会对程序的性能有着显著的提高 线性表和链表: 1.LinkedList<T>:适合于元素数组不固定,存在大量列表的头尾添加动作场合.其它可使用List<T> ...

  4. Spring RestTemplate: 比httpClient更优雅的Restful URL访问, java HttpPost with header

    { "Author": "tomcat and jerry", "url":"http://www.cnblogs.com/tom ...

  5. caffe net 可视化工具

    http://ethereon.github.io/netscope/#/editor 将对应的网络输入到里面,然后按shift+enter即可查看对应的网络结构

  6. error C2664

    error C2664: “int CWnd::MessageBoxW(LPCTSTR,LPCTSTR,UINT)”: 无法将参数 1 从“const char [19]”转换为“LPCTSTR” n ...

  7. CSS布局技巧 -- 纯CSS让子元素的宽度总和决定其父元素的宽度

    使用场景 在移动端屏幕宽度有限的前提下,使用横向滚动的方式展示更多的内容.在这样的需求下,希望父元素作为容器,其宽度可以又横向排列资源的总宽度动态撑开,超过祖父元素的宽度:在不超过祖父元素时,自动继承 ...

  8. C语言之数组,字符串,指针

    一. 数组的定义 1.  数组初始化 初始化方式 int a[3] = {10, 9, 6}; int a[3] = {10,9}; int a[] = {11, 7, 6}; int a[4] = ...

  9. [ MySql学习心得 ] --One

    一.安装MySql 1.解压版安装 下载地址: http://dev.mysql.com/downloads/mysql/ 安装及配置教程:http://jingyan.baidu.com/artic ...

  10. 给自己立下一个巨大的flag

    [BZOJ1861][BZOJ3224] [BZOJ2733][BZOJ1056] [BZOJ2120][BZOJ3673] [BZOJ1833][BZOJ1026] [BZOJ3209][BZOJ1 ...