[Bullet3]三种碰撞检测及实现
官方文档:http://bulletphysics.org
开源代码:https://github.com/bulletphysics/bullet3/releases
API文档:http://bulletphysics.org/Bullet/BulletFull/annotated.html
bullet3的三种碰撞检测
以下三种方式都是可以达到碰撞检测的效果:
btCollisionWorld::contactTest检测指定对象是否与场景发生碰撞;btCollisionWorld::performDiscreteCollisionDetection检测场景中所有的碰撞;btDynamicsWorld::stepSimulation模拟运动。
还有一种射线检测,但是与这里的物体碰撞稍微有些区别,这里就不展开来讲了。
0. 准备工作
先创建一个场景,增加一个地板(box)
btDefaultCollisionConfiguration* g_colConfig;
btCollisionDispatcher* g_dispatcher;
btBroadphaseInterface* g_broadInterface;
btSequentialImpulseConstraintSolver* g_solver;
btDynamicsWorld* g_world; // 场景信息,退出的时候需要delete
g_colConfig = new btDefaultCollisionConfiguration();
g_dispatcher = new btCollisionDispatcher(g_colConfig);
g_broadInterface = new btDbvtBroadphase();
g_solver = new btSequentialImpulseConstraintSolver;
g_world = new btDiscreteDynamicsWorld(g_dispatcher, g_broadInterface, g_solver, g_colConfig);
g_world->setGravity(btVector3(0,-10,0)); // 设置重力加速度
// add a test box
{
btCollisionShape* shape = new btBoxShape(btVector3(btScalar(1000.),btScalar(10.),btScalar(1000.)));
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(0, -10, 0));
btScalar mass=0.f;
btVector3 localInertia(0, 0, 0);
bool isDynamic = (mass != 0.f);
if (isDynamic)
shape->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* myMotionState = new btDefaultMotionState(trans);
btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);
btRigidBody* body = new btRigidBody(cInfo);
g_world->addRigidBody(body);
}
1. btCollisionWorld::contactTest
完整函数内容为
void btCollisionWorld::contactTest(btCollisionObject * colObj, ContactResultCallback & resultCallback)
contactTest会对确定的colObj对象与btCollisionWorld中的所有对象进行接触检测,并调用ContactResultCallBack回调。
其实这个函数不算碰撞检测,只是算接触检测,如果距离为0,是会触发回调的。
1.1. 继承回调的结构体
ContactResultCallback结构体有一个名为addSingleResult的纯虚函数,在继承的时候一定要实现addSingleResult函数。这个也是碰撞的时候执行的回调函数。是这个结构体的核心。碰撞信息会存储在btManifoldPoint & cp中,使用方法也比较简单,可以参考API文档的接口。其它地方的碰撞,也是用这个对象存储,处理方法是一样的。
// 碰撞检测回调
struct MyColCallBack : btCollisionWorld::ContactResultCallback
{
public:
btScalar addSingleResult(
btManifoldPoint & cp,
const btCollisionObjectWrapper * colObj0Wrap,
int partId0,
int index0,
const btCollisionObjectWrapper * colObj1Wrap,
int partId1,
int index1)
{
btVector3 posA = cp.getPositionWorldOnA();
btVector3 posB = cp.getPositionWorldOnB();
printf("col pos for A {%f, %f, %f}\n", posA.getX(), posA.getY(), posA.getZ());
printf("col pos for B {%f, %f, %f}\n", posB.getX(), posB.getY(), posB.getZ());
return btScalar(0.f);
};
};
1.2. 碰撞检测
// 创建一个球体,并加入到场景中
btCollisionShape* shape = new btSphereShape(btScalar(1.f));
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(0, 1, 0));
btScalar mass=1.f;
btVector3 localInertia(0, 0, 0);
bool isDynamic = (mass != 0.f);
if (isDynamic)
shape->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* myMotionState = new btDefaultMotionState(trans);
btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);
btRigidBody* g_body = new btRigidBody(cInfo);
g_world->addRigidBody(g_body);
// 创建回调并碰撞检测
MyColCallBack callBack;
g_world->contactTest(g_body, callBack);
// todo delete
运行结果:

2. btCollisionWorld::performDiscreteCollisionDetection
performDiscreteCollisionDetection会对场景中的所有物体进行一次碰撞检测。而contactTest是对确定的物体进行碰撞检测。
g_world->performDiscreteCollisionDetection();
list<btCollisionObject*> m_collisionObjects;
int numManifolds = g_world->getDispatcher()->getNumManifolds();
for(int i=0; i<numManifolds; i++)
{
btPersistentManifold* contactManifold = g_world->getDispatcher()->getManifoldByIndexInternal(i);
btCollisionObject* obA = (btCollisionObject*)(contactManifold->getBody0());
btCollisionObject* obB = (btCollisionObject*)(contactManifold->getBody1());
int numContacts = contactManifold->getNumContacts();
for(int j=0; j<numContacts; j++)
{
btManifoldPoint& pt = contactManifold->getContactPoint(j);
if(pt.getDistance()<=0.f)
{
m_collisionObjects.push_back(obA);
m_collisionObjects.push_back(obB);
btVector3 posA = pt.getPositionWorldOnA();
btVector3 posB = pt.getPositionWorldOnB();
printf("%d A -> {%f, %f, %f}\n", i, posA.getX(), posA.getY(), posA.getZ()); // 碰撞点
printf("%d B -> {%f, %f, %f}\n", i, posB.getX(), posB.getY(), posB.getZ());
}
}
}
这里需要注意一下,多个物体两两碰撞的时候,列表m_collisionObjects内是存在重复的可能的,往往需要去重一下。
m_collisionObjects.sort();
m_collisionObjects.unique();
运行结果:
这里我多加了一个半径为1,位置为{1,1,0}的求,然后基本上两个球和地板发生了两两碰撞。

3. btDynamicsWorld::stepSimulation
完整的函数内容为:
virtual int btDynamicsWorld::stepSimulation(
btScalar timeStep,
int maxSubSteps = 1,
btScalar fixedTimeStep = btScalar(1.)/btScalar(60.))
stepSimulation其实不是用来做碰撞检测的,而是用来做物理运动模拟的。既然能做运动模拟,那肯定也能够做碰撞检测了。
3.1. 模拟运动
设置场景的重力加速为btVector3(0,-10,0),增加一个半径为1,位置为{0,100,0}的球体,并设置其质量为1,冲量为{2,0,0},即球体会以x轴速度为2,Y轴以-10的加速度做抛物线运动。
// 设置重力加速度
g_world->setGravity(btVector3(0,-10,0));
// 创建一个球体,并加入到场景中
btCollisionShape* shape = new btSphereShape(btScalar(1.f));
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(0, 100, 0));
btScalar mass=1.f;
btVector3 localInertia(0, 0, 0);
bool isDynamic = (mass != 0.f);
if (isDynamic)
shape->calculateLocalInertia(mass, localInertia);
btDefaultMotionState* myMotionState = new btDefaultMotionState(trans);
btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);
btRigidBody* g_body = new btRigidBody(cInfo);
g_body->applyCentralImpulse(btVector3(2,0,0)); // 设置冲量
g_world->addRigidBody(g_body);
for (i=0;i<10;i++)
{
g_world->stepSimulation(1.f/60.f,10); // 模拟运动
trans = g_body->getWorldTransform();
printf("world pos = %f,%f,%f\n", trans.getOrigin().getX(),
trans.getOrigin().getY(),
trans.getOrigin().getZ());
}
}
执行结果

[Bullet3]三种碰撞检测及实现的更多相关文章
- Navisworks 提供了.NET, COM和NwCreate 三种API
Navisworks 提供了.NET, COM和NwCreate 三种API.而通常我们说Navisworks API其实指的只是COM或.NET,因为NwCreate的功能比较特殊.待我一一道来: ...
- 盛大游戏技术总监徐峥:Unity引擎使用的三种方式
在5月13日Unite 2017 案例分享专场上,盛大游戏技术总监徐峥分享了使用Unity引擎的三种方式,以下为详细内容: 大家好,我先简单介绍一下我自己,我是盛大游戏的技术总监徐峥.我今天想分享的主 ...
- 简谈百度坐标反转至WGS84的三种思路
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 基于百度地图进行数据展示是目前项目中常见场景,但是因为百度地图 ...
- 测试一下StringBuffer和StringBuilder及字面常量拼接三种字符串的效率
之前一篇里写过字符串常用类的三种方式<java中的字符串相关知识整理>,只不过这个只是分析并不知道他们之间会有多大的区别,或者所谓的StringBuffer能提升多少拼接效率呢?为此写个简 ...
- Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用
OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...
- css中的浮动与三种清除浮动的方法
说到浮动之前,先说一下CSS中margin属性的两种特殊现象 1, 外边距的合并现象: 如果两个div上下排序,给上面一个div设置margin-bottom,给下面一个div设置margin-top ...
- ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式
由于ASP.NET Core应用是一个同时处理多个请求的服务器应用,所以在处理某个请求过程中抛出的异常并不会导致整个应用的终止.出于安全方面的考量,为了避免敏感信息的外泄,客户端在默认的情况下并不会得 ...
- 【Win 10 应用开发】文件读写的三种方案
本文老周就跟伙伴们探讨一下关于文件读写的方法.总得来说嘛,有三种方案可以用,而且每种方案都各有特色,也说不上哪种较好.反正你得记住老祖宗留给我们的大智慧——事无定法,灵活运用者为上. OK,咱们开始吧 ...
- .NET Core采用的全新配置系统[6]: 深入了解三种针对文件(JSON、XML与INI)的配置源
物理文件是我们最常用到的原始配置的载体,最佳的配置文件格式主要由三种,它们分别是JSON.XML和INI,对应的配置源类型分别是JsonConfigurationSource.XmlConfigura ...
随机推荐
- 13、手把手教你Extjs5(十三)模块字段和Grid列的定义[1]
这一节加入模块自定义字段,并根据这些字段生成model.然后再定义grid中的分组和列.从这一切开始真正进入到了模块自定义的节奏当中,代码的复杂度和技巧性也大大提高.先从模块字段的自定义开始.先看一下 ...
- html 设置页脚div一直在页面底部
先上代码 <!DOCTYPE HTML> <html lang="en" style="height: 100%; width: 100%;" ...
- css颜色渐变在不同浏览器的设置
在web开发中,难免会遇到浏览器之间的兼容问题,关于Css设置颜色渐变下面有解决的办法,直接上代码: 适用于谷歌浏览器: background: -webkit-gradient(linear, 0 ...
- shell 实例学习
安装crond:yum install crontabs (http://blog.163.com/victory_wxl/blog/static/14130530220115296180333/) ...
- camstar --飞达上料
业务场景:某工厂的SMT车间接到生产PCB(3151502),数量1000片.如果实现飞达进行上料,并在贴片机工作时,系统自动进行物料消耗.3151502的BOM为1107790,1107792,11 ...
- 【转】Linux正则表达式使用指南
正则表达式是一种符号表示法,用于识别文本模式.Linux处理正则表达式的主要程序是grep.grep搜索与正则表达式匹配的行,并将结果输送至标准输出. 1. grep匹配模式 grep按下述方式接受选 ...
- MYSQL最大连接数修改
MYSQL数据库安装完成后,默认最大连接数是100,一般流量稍微大一点的论坛或网站这个连接数是远远不够的,增加默认MYSQL连接数的方法有两个 方法一:进入MYSQL安装目录 打开MYSQL配置文件 ...
- 写一个程序,统计自己C语言共写了多少行代码。ver2.00
概要 完成一个程序,作用是统计一个文件夹下面所有文件的代码行数.输入是一个文件夹的绝对路径,输出是代码行数.所以此程序的新特点有两个: 统计某一文件夹下的所有文件: 可以任意指定本机硬盘上任何位置的某 ...
- C# new和override的区别
浅析C# new和override的区别 C#中new和override是继承中经常用到的两个关键字,但是往往有时候容易把这两个关键字的作用搞混淆. new C# new关键字表示隐藏,是指加上new ...
- APK的反编译
有秘密的地方就有见不得光的东西,我讨厌这些,所以对于某一个XX圈APP极其反感,感觉就像一个色情网站 一.ApkTool的使用 看了几个教程,自己下载的好像总是不完整,下载包解压后一个没有aapt.e ...