原文作者:aircraft

原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html

一.初始化世界以及模型

/// 冲突配置包含内存的默认设置,冲突设置。高级用户可以创建自己的配置。
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration(); /// 使用默认的冲突调度程序。对于并行处理,您可以使用不同的分派器(参见Extras/BulletMultiThreaded)
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration); /// btDbvtBroadphase是一种很好的通用的两步法碰撞检测。你也可以尝试btAxis3Sweep。
btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase(); /// 默认约束求解器。对于并行处理,您可以使用不同的解决程序(参见Extras/BulletMultiThreaded)
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver; btDiscreteDynamicsWorld* dynamicsWorld =
new btDiscreteDynamicsWorld(dispatcher,overlappingPairCache,solver,collisionConfiguration); dynamicsWorld->setGravity(btVector3(,-,));

上面看起来很多麻烦的东西,但是其实我们都不需要看,也不需要理解,拿到dynamicsWorld这个指针就行了,它用于表示刚体碰撞的世界。后面有很多设置都是关于他的,setGravity(btVector3(0,-10,0));这个就是设置一下他的重力为10N/kg.

二.导入3D模型

  在导入3d模型前,我们要学会怎么去画三角网格,或者说凸壳,我在写这个导入3D模型碰撞检测的程序的时候,真的是在网上找不到什么有用的资料,头都快裂开了!!!

  Bullet里面有内置很多常规的3维模型画法,比如长方体,圆,正方体之类的,并不能给我带来什么启发和用处,因为导入一个3D模型,比如OBJ文件,就是要把一个个的三角网格画出来,最后成为一个3D模型。

2.1三角片面碰撞模型
2.1对于复杂的碰撞模型,需要用三角片面来模拟。
静态碰撞模型,对于大地,房屋等物体。可以用静态的三角片面来模拟。
btBvhTriangleMeshShape 静态的三角片面模型
构建方法
btBvhTriangleMeshShape (btStridingMeshInterface *meshInterface,
bool useQuantizedAabbCompression, bool buildBvh=true)

示例代码
btTriangleMesh* trimesh = new btTriangleMesh();
bool useQuantization = true;
btCollisionShape* concaveShape = new
btBvhTriangleMeshShape(trimesh,useQuantization); //凹的三角片面碰撞模型
startTransform.setOrigin(convexDecompositionObjectOffset);
localCreateRigidBody(0.f,startTransform,concaveShape);
//质量不能设置为非0,btBvhTriangleMeshShape似乎只能用在静态的场景中。

相关类
btTriangleMesh 一个方便的存储三角片面数据的类,接口简单
通过
void addTriangle (const btVector3 &vertex0, const
btVector3 &vertex1, const btVector3
&vertex2, bool removeDuplicateVertices=false)
来为片面增加三角形,这个函数不会检查相同顶点的冗余

2.2动态的碰撞模型
btGImpactMeshShape 该类可以构建一个动态的三角片面碰撞模型
构建方法
btGImpactMeshShape (btStridingMeshInterface *meshInterface)
通过传入三角片面数据来构建
使用该类时,一是在构建该类后要调用updateBound()。二是要在dispatcher中注册该类的碰撞算法,

示例代码如下:
btGImpactMeshShape * trimesh = new
btGImpactMeshShape(indexVertexArrays); //构建形状
trimesh->setLocalScaling(btVector3(4.f,4.f,4.f));

trimesh->updateBound();
m_trimeshShape = trimesh;

//register algorithm
btCollisionDispatcher * dispatcher =
static_cast<btCollisionDispatcher
*>(m_dynamicsWorld
->getDispatcher());
btGImpactCollisionAlgorithm::registerAlgorithm(dispatcher);
//注册算法,如果不注册算法的话,会出现问题,如相同的模型不能发生碰撞

相关类
btTriangleIndexVertexArray 储存三角片面数据
btTriangleIndexVertexArray (int numTriangles, int
*triangleIndexBase, int triangleIndexStride, int numVertices,
btScalar *vertexBase, int vertexStride)
通过制定三角形顶点数组和三角形索引数组的地址,以及每组数据大小来构建。所以类中不会实际含有片面数据。使得三角片面数据可以与渲染部分的代码共用。

// create trimesh
btTriangleIndexVertexArray* indexVertexArrays = new
btTriangleIndexVertexArray(NUM_TRIANGLES, //片面数据
&gIndices[0][0],
3*sizeof(int),
NUM_VERTICES,(REAL*)
&gVertices[0],sizeof(REAL)*3);

2.3其他类
btConvexHullShape 一个凸体模型的类,构建一个凸体。而构建这个凸体的方法十分简单——往这个类加顶点就可以了
btConvexHullShape (const btScalar *points=0, int numPoints=0, int
stride=sizeof(btVector3))
void addPoint (const btVector3 &point)
示例
btConvexHullShape* convexShape = new btConvexHullShape();
//用桌子的点集构建了一个凸的碰撞模型,虽然桌子是凹的
for
(i=0;i<hull->numVertices();i++)
{
convexShape->addPoint(hull->getVertexPointer()[i]);
//这个模型只需要加如点就可以了
}

最后我也是使用了btConvexHullShape,这个类来导入3D模型。上面动态那个也可以进行碰撞检测,我也试过了。静态那个就不行了,因为不会动。

3.读取3D模型的数据

这里的话就不详细说了,可以看我前面几篇opengl导入3D模型的博客。

然后我们用btConvexHullShape类将我们读取的模型数据导入,构造出来我们的物体。

代码如下:

void InitObject()
{ ReadPIC();//读取3D模型内部数据存储在m_pic结构体
btTriangleMesh* tMesh = new btTriangleMesh(); int k = ;
for (int i = ; i < m_pic.F.size(); i++)
{
points[k++].setValue(m_pic.V[m_pic.F[i].V[]].X / YU, m_pic.V[m_pic.F[i].V[]].Y / YU, m_pic.V[m_pic.F[i].V[]].Z / YU);
points[k++].setValue(m_pic.V[m_pic.F[i].V[]].X / YU, m_pic.V[m_pic.F[i].V[]].Y / YU, m_pic.V[m_pic.F[i].V[]].Z / YU);
points[k++].setValue(m_pic.V[m_pic.F[i].V[]].X / YU, m_pic.V[m_pic.F[i].V[]].Y / YU, m_pic.V[m_pic.F[i].V[]].Z / YU); }
btScalar mass(.f); // 刚体是动态的如果且仅当质量为非零时,否则是静止的 btConvexHullShape * collisionShape = new btConvexHullShape((btScalar*)points, m_pic.F.size()*);
btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(, , , ), btVector3(, , )));
bool isDynamic = (mass != .f); btVector3 localInertia(, , );
if (isDynamic)
collisionShape->calculateLocalInertia(mass, localInertia);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, groundMotionState, collisionShape, localInertia);
body = new btRigidBody(rbInfo);
//body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
//body->setActivationState(4); mp_btDynamicsWorld->addRigidBody(body); /*
//init ground
btCollisionShape *groundShape = new btBoxShape(btVector3(1000, 0.5, 1000)); //half size btVector3 groundpos = btVector3(0, 0, 0);
btQuaternion groundrot(0, 0, 0, 1);
btDefaultMotionState* groundMotion = new btDefaultMotionState(btTransform(groundrot, groundpos));
ground = new btRigidBody(0.0, groundMotion, groundShape);//mass = 0 means it is a static object
btScalar rest = btScalar(1);
ground->setRestitution(rest);//设置碰撞反弹系数 默认为0
mp_btDynamicsWorld->addRigidBody(ground);
*/
//init ground
btConvexHullShape *groundShape = new btConvexHullShape((btScalar*)points, m_pic.F.size() * ); btVector3 groundpos = btVector3(, , ); btDefaultMotionState* groundMotion = new btDefaultMotionState(btTransform(btQuaternion(, , , ), btVector3(, , )));
ground = new btRigidBody(0.0, groundMotion, groundShape);//mass = 0 means it is a static object
btScalar rest = btScalar();
ground->setRestitution(rest);//设置碰撞反弹系数 默认为0
mp_btDynamicsWorld->addRigidBody(ground); }

三.进行碰撞检测

  3.1碰撞反馈

  既然要进行碰撞检测,那么碰撞时,程序就要告诉我们,物体进行碰撞了,然后我们要怎么去处理这个碰撞。。。

  那怎么获取碰撞时的信息呢?

  

int numManifolds = mp_btDynamicsWorld->getDispatcher()->getNumManifolds();
for (int i = ; i < numManifolds; i++)
{
btPersistentManifold * contactManifold = mp_btDynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
int numContacts = contactManifold->getNumContacts();
if (numContacts > )
{
cout << "碰撞" << endl;
}
}

我们可以获取两个对象的接触点,如果存在接触点,并且还大于0,那么此时肯定是碰撞了,我们就可以对这个碰撞进行处理。

这个代码可以放在update 或者render或者display绘制里都可以。

3.2碰撞检测模型绘制

  这时候我们准备工作都已经做好了,就可以在自己的绘制display函数里将3D模型绘制出来。

if (motion)delete motion;
//motion = new btDefaultMotionState(btTransform(btQuaternion(1, 1, 0, 1), btVector3(0, 100, 0)));
//body->setMotionState(motion);
btTransform trans = body->getWorldTransform(); //trans.setOrigin(btVector3(0.0f, 400, 0.0f));
//trans.setRotation(btQuaternion(1, 1, 0, 1));
//body->getMotionState()->setWorldTransform(trans);
//body->getMotionState()->
btScalar m[];
trans.getOpenGLMatrix(m);
glColor3f(, , );
glPushMatrix();
glMultMatrixf((GLfloat*)m);
//glTranslated(0, -400, 0); //glutSolidCube(400);
for (int i = ; i < m_pic.F.size(); i++)
{
glBegin(GL_TRIANGLES); // 绘制三角形
if (m_pic.VT.size() != )glTexCoord2f(m_pic.VT[m_pic.F[i].T[]].TU, m_pic.VT[m_pic.F[i].T[]].TV); //纹理
if (m_pic.VN.size() != )glNormal3f(m_pic.VN[m_pic.F[i].N[]].NX, m_pic.VN[m_pic.F[i].N[]].NY, m_pic.VN[m_pic.F[i].N[]].NZ);//法向量
glVertex3f(m_pic.V[m_pic.F[i].V[]].X / YU, m_pic.V[m_pic.F[i].V[]].Y / YU, m_pic.V[m_pic.F[i].V[]].Z / YU); // 上顶点 if (m_pic.VT.size() != )glTexCoord2f(m_pic.VT[m_pic.F[i].T[]].TU, m_pic.VT[m_pic.F[i].T[]].TV); //纹理
if (m_pic.VN.size() != )glNormal3f(m_pic.VN[m_pic.F[i].N[]].NX, m_pic.VN[m_pic.F[i].N[]].NY, m_pic.VN[m_pic.F[i].N[]].NZ);//法向量
glVertex3f(m_pic.V[m_pic.F[i].V[]].X / YU, m_pic.V[m_pic.F[i].V[]].Y / YU, m_pic.V[m_pic.F[i].V[]].Z / YU); // 左下 if (m_pic.VT.size() != )glTexCoord2f(m_pic.VT[m_pic.F[i].T[]].TU, m_pic.VT[m_pic.F[i].T[]].TV); //纹理
if (m_pic.VN.size() != )glNormal3f(m_pic.VN[m_pic.F[i].N[]].NX, m_pic.VN[m_pic.F[i].N[]].NY, m_pic.VN[m_pic.F[i].N[]].NZ);//法向量
glVertex3f(m_pic.V[m_pic.F[i].V[]].X / YU, m_pic.V[m_pic.F[i].V[]].Y / YU, m_pic.V[m_pic.F[i].V[]].Z / YU); // 右下
glEnd(); // 三角形绘制结束
}
glPopMatrix();
int numManifolds = mp_btDynamicsWorld->getDispatcher()->getNumManifolds();
for (int i = ; i < numManifolds; i++)
{
btPersistentManifold * contactManifold = mp_btDynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
int numContacts = contactManifold->getNumContacts();
if (numContacts > )
{
cout << "碰撞到地面" << endl;
}
}
//ground
btTransform transg = ground->getWorldTransform();
//trans.setOrigin(btVector3(0.0f, 400, 0.0f));
//trans.setRotation(btQuaternion(1, 1, 0, 1));
//body->getMotionState()->setWorldTransform(trans);
//body->getMotionState()->
/*
btScalar mg[16];
transg.getOpenGLMatrix(mg); glColor3f(0, 1, 0);
glPushMatrix();
glMultMatrixf((GLfloat*)mg);
*/
glPushMatrix();
glScalef(, 0.0005, );
//glScalef(1, 1, 1);
glutSolidCube(); //size glPopMatrix();

四.结果

  我们可以看看这个项目的运行过程和结果图:

兔子模型在进行自由落体,下面是一个地板。

地板颜色给我换了一下,兔子又下落了点距离。

当兔子接触到地面时,我们将碰撞检测的结果打印出来, 这里也就是简单的打印 碰撞到了地面。

可以看到我们的兔子模型,碰撞到地面之后,遵循现实物理规则,被反弹起来一点,然后砸歪了。

本项目源码获得可以添加后台小编微信发送:本文章标题———源码  获取:

  可微信扫码关注本人公众号,里面会不定期的分享各种编程教程,和共享源码,诸如研究分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识

bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑的更多相关文章

  1. Bullet物理引擎在OpenGL中的应用

    Bullet物理引擎在OpenGL中的应用 在开发OpenGL的应用之时, 难免要遇到使用物理来模拟OpenGL中的场景内容. 由于OpenGL仅仅是一个关于图形的开发接口, 因此需要通过第三方库来实 ...

  2. OpenGl读取导入3D模型并且添加鼠标移动旋转显示

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...

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

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

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

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

  5. WPF利用HelixToolKit后台导入3D模型

    原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/de ...

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

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

  7. Unity导入3D模型的过程与方法

    一.介绍 资源是游戏开发中的原材料,也就是组成游戏的模块. Unity只是一个游戏开发引擎,而并不是一个资源开发软件.这就意味着在游戏中需要的资源通常是由一些设计者使用其他软件开发出来的,然后设计者会 ...

  8. cesium导入3D模型(obj转gltf)

    cesium中支持载入3D模型,不过只支持gltf格式.gltf是khronos组织(起草OpenGL标准的那家)定义的一种交换格式,用于互联网或移动设备上展现3d内容,充分支持opengl,webg ...

  9. 【Unity】3.0 第3章 创建和导入3D模型

    分类:Unity.C#.VS2015 创建日期:2016-04-02 一.简介 利用Unity内置的基本模型和工具,不需要借助任何其他的三维建模软件,就可以直接创建出各种3D模型,这是这一章我们首先学 ...

随机推荐

  1. Vue使用MathJax动态识别数学公式

    本人菜鸟一名,如有错误,还请见谅. 1.前言 最近公司的一个项目需求是在前端显示Latex转化的数学公式,经过不断的百度和测试已基本实现.现在此做一个记录. 2.MathJax介绍 MathJax是一 ...

  2. 从“HDU 2005 第几天?”谈起

    在程序设计中,日期时间的处理经常会遇到.在C语言程序设计的一些教材中会出现如下例子或习题. [例1]第几天? (HDU 2005) 给定一个日期,输出这个日期是该年的第几天. Input输入数据有多组 ...

  3. mysql 复制表结构和表数据

    CREATE TABLE a1 ( id INT NOT NULL AUTO_INCREMENT COMMENT '编号', txt VARCHAR(20) NOT NULL DEFAULT '' C ...

  4. Winform中自定义xml配置文件,并配置获取文件路径

    场景 在Winform程序中,需要将一些配置项存到配置文件中,这时就需要自定义xml的配置文件格式.并在一些工具类中去获取配置文件的路径并加载其内容. 关注公众号霸道的程序猿获取编程相关电子书.教程推 ...

  5. thymeleaf+layui加载页面渲染时TemplateProcessingException: Could not parse as expression

    Caused by: org.attoparser.ParseException: Could not parse as expression: " {type: 'numbers'}, { ...

  6. 装系统 ------ 使用微PE 做系统盘

    1.什么是PE系统 pe系统是一种装系统的系统,也就是预装系统的系统,它是一种系统预装环境和工具. 可以放在U盘或光盘里随身携带,可以用来给电脑装系统 2.常见的制作pe 系统的工具 大白菜,U启动, ...

  7. mybatis源码专题(1)--------复习jdbc操作,编译mybatis源码,准备为你的简历加分吧

    本文是作者原创,版权归作者所有.若要转载,请注明出处.文章中若有错误和疏漏之处,还请各位大佬不吝指出,谢谢大家. 1.mybatis的底层是jdbc操作,我们来回顾一下,如下  运行以后的结果如下图: ...

  8. RocksDB线程局部缓存

    概述 在开发过程中,我们经常会遇到并发问题,解决并发问题通常的方法是加锁保护,比如常用的spinlock,mutex或者rwlock,当然也可以采用无锁编程,对实现要求就比较高了.对于任何一个共享变量 ...

  9. Recovery启动流程(2)---UI界面【转】

    Recovery启动流程系列文章把recvoery目录下文件分成小块讲解,最后再以一条主线贯穿所有的内容.这篇文章主要讲解Recovery-UI的相关内容. 我们知道,当我们通过按键或者应用进入rec ...

  10. linux 堆栈查看

    top -c 查看进程ID pstree PID 查看线程树 pstack PID 查看堆栈