当前位置: 首页 > news >正文

bullet3 三种碰撞检测及实现

       

         Bullet 物理引擎是一个专业的开放源码的碰撞检测,刚体和柔体动力学库。Bullet 物理引擎目标是实时和交互使用在游戏,电影和机器人的视觉效果。自由zlib授权的商业使用库。

bullet3的三种碰撞检测

以下三种方式都是可以达到碰撞检测的效果:

  1. btCollisionWorld::contactTest 检测指定对象是否与场景发生碰撞;
  2. btCollisionWorld::performDiscreteCollisionDetection 检测场景中所有的碰撞;
  3. btDynamicsWorld::stepSimulation 模拟运动。

还有一种射线检测,但是与这里的物体碰撞稍微有些区别,这里就不展开来讲了。

0. 准备工作

先创建一个场景,增加一个地板(box)

btDefaultCollisionConfiguration* g_colConfig;
btCollisionDispatcher* g_dispatcher;
btBroadphaseInterface* g_broadInterface;
btSequentialImpulseConstraintSolver* g_solver;
btDynamicsWorld* g_world;  // 场景信息,退出的时候需要deleteg_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

运行结果:

result

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}的求,然后基本上两个球和地板发生了两两碰撞。

result

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());}
}

执行结果

result

相关文章:

  • 不要盲目自学网络安全!学习顺序特别重要!
  • WPF调节图片的对比度
  • 抖音小店怎么做好前期运营?这三个步骤做好就行了!
  • 【开题报告】基于SpringBoot的洗衣店管理系统的设计与实现
  • ios环境搭建_xcode安装及运行源码
  • 【干货】Windows中定时删除system32目录下的.dmp文件教程
  • springboot连接oracle报错ORA-12505解决方案
  • JOSEF约瑟 定时限过流继电器 JSL-21/5 柜内安装,板前接线 实物图
  • RTSP/Onvif安防平台EasyNVR接入EasyNVS显示服务不存在的原因及解决办法
  • 海康威视摄像头+服务器+录像机配置校园围墙安全侦测区域入侵侦测+越界侦测.docx
  • 部署KVM虚拟化平台
  • Python 模块和包(1)
  • 跑步中位数
  • 探索Spring最常用的30个注解
  • 天翼云高校云盘在线扩容
  • Android Volley源码解析
  • Angular 响应式表单之下拉框
  • ECS应用管理最佳实践
  • Nodejs和JavaWeb协助开发
  • PaddlePaddle-GitHub的正确打开姿势
  • quasar-framework cnodejs社区
  • REST架构的思考
  • vue--为什么data属性必须是一个函数
  • 百度小程序遇到的问题
  • 简单数学运算程序(不定期更新)
  • 如何胜任知名企业的商业数据分析师?
  • 怎样选择前端框架
  • ​决定德拉瓦州地区版图的关键历史事件
  • #HarmonyOS:软件安装window和mac预览Hello World
  • #微信小程序(布局、渲染层基础知识)
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (zt)最盛行的警世狂言(爆笑)
  • (算法二)滑动窗口
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)EOS中账户、钱包和密钥的关系
  • *1 计算机基础和操作系统基础及几大协议
  • ./configure、make、make install 命令
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .Net+SQL Server企业应用性能优化笔记4——精确查找瓶颈
  • .Net8 Blazor 尝鲜
  • .NET命名规范和开发约定
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • ::什么意思
  • [ solr入门 ] - 利用solrJ进行检索
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [ 转载 ] SharePoint 资料
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [202209]mysql8.0 双主集群搭建 亲测可用
  • [⑧ADRV902x]: Digital Pre-Distortion (DPD)学习笔记
  • [C语言][C++][时间复杂度详解分析]二分查找——杨氏矩阵查找数字详解!!!
  • [Hive] 常见函数
  • [IDF]啥?