原文作者: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(0,-10,0));

上面看起来很多麻烦的东西,但是其实我们都不需要看,也不需要理解,拿到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 = 0;for (int i = 0; i < m_pic.F.size(); i++){points[k++].setValue(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);points[k++].setValue(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU);points[k++].setValue(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU);}btScalar mass(10.f);// 刚体是动态的如果且仅当质量为非零时,否则是静止的
btConvexHullShape * collisionShape = new btConvexHullShape((btScalar*)points, m_pic.F.size()*3);btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 1000, 0)));bool isDynamic = (mass != 0.f);btVector3 localInertia(0, 0, 0);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 groundbtCollisionShape *groundShape = new btBoxShape(btVector3(1000, 0.5, 1000)); //half sizebtVector3 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 objectbtScalar rest = btScalar(1);ground->setRestitution(rest);//设置碰撞反弹系数  默认为0mp_btDynamicsWorld->addRigidBody(ground);*///init groundbtConvexHullShape *groundShape = new btConvexHullShape((btScalar*)points, m_pic.F.size() * 3);btVector3 groundpos = btVector3(0, 0, 0);btDefaultMotionState* groundMotion = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 0)));ground = new btRigidBody(0.0, groundMotion, groundShape);//mass = 0 means it is a static objectbtScalar rest = btScalar(1);ground->setRestitution(rest);//设置碰撞反弹系数  默认为0mp_btDynamicsWorld->addRigidBody(ground);}

三.进行碰撞检测

  3.1碰撞反馈

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

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

  

int numManifolds = mp_btDynamicsWorld->getDispatcher()->getNumManifolds();for (int i = 0; i < numManifolds; i++){btPersistentManifold * contactManifold = mp_btDynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);int numContacts = contactManifold->getNumContacts();if (numContacts > 0){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[16];trans.getOpenGLMatrix(m);glColor3f(0, 0, 1);glPushMatrix();glMultMatrixf((GLfloat*)m);//glTranslated(0, -400, 0);//glutSolidCube(400);for (int i = 0; i < m_pic.F.size(); i++){glBegin(GL_TRIANGLES);                            // 绘制三角形if (m_pic.VT.size() != 0)glTexCoord2f(m_pic.VT[m_pic.F[i].T[0]].TU, m_pic.VT[m_pic.F[i].T[0]].TV);  //纹理    if (m_pic.VN.size() != 0)glNormal3f(m_pic.VN[m_pic.F[i].N[0]].NX, m_pic.VN[m_pic.F[i].N[0]].NY, m_pic.VN[m_pic.F[i].N[0]].NZ);//法向量glVertex3f(m_pic.V[m_pic.F[i].V[0]].X / YU, m_pic.V[m_pic.F[i].V[0]].Y / YU, m_pic.V[m_pic.F[i].V[0]].Z / YU);        // 上顶点if (m_pic.VT.size() != 0)glTexCoord2f(m_pic.VT[m_pic.F[i].T[1]].TU, m_pic.VT[m_pic.F[i].T[1]].TV);  //纹理if (m_pic.VN.size() != 0)glNormal3f(m_pic.VN[m_pic.F[i].N[1]].NX, m_pic.VN[m_pic.F[i].N[1]].NY, m_pic.VN[m_pic.F[i].N[1]].NZ);//法向量glVertex3f(m_pic.V[m_pic.F[i].V[1]].X / YU, m_pic.V[m_pic.F[i].V[1]].Y / YU, m_pic.V[m_pic.F[i].V[1]].Z / YU);        // 左下if (m_pic.VT.size() != 0)glTexCoord2f(m_pic.VT[m_pic.F[i].T[2]].TU, m_pic.VT[m_pic.F[i].T[2]].TV);  //纹理if (m_pic.VN.size() != 0)glNormal3f(m_pic.VN[m_pic.F[i].N[2]].NX, m_pic.VN[m_pic.F[i].N[2]].NY, m_pic.VN[m_pic.F[i].N[2]].NZ);//法向量glVertex3f(m_pic.V[m_pic.F[i].V[2]].X / YU, m_pic.V[m_pic.F[i].V[2]].Y / YU, m_pic.V[m_pic.F[i].V[2]].Z / YU);        // 右下glEnd();                                        // 三角形绘制结束
    }glPopMatrix();int numManifolds = mp_btDynamicsWorld->getDispatcher()->getNumManifolds();for (int i = 0; i < numManifolds; i++){btPersistentManifold * contactManifold = mp_btDynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);int numContacts = contactManifold->getNumContacts();if (numContacts > 0){cout << "碰撞到地面" << endl;}}//groundbtTransform 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(1, 0.0005, 1);//glScalef(1, 1, 1);glutSolidCube(2000); //sizeglPopMatrix();

四.结果

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

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

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

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

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

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

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

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

  1. bullet 物理引擎资料

    bullet 官方网站 https://pybullet.org gamekit-developers 开源的游戏引擎,由 bullet 创始人发起. https://github.com/gamek ...

  2. 给osg配置bullet物理引擎

    配置bullet物理引擎,花了好长时间,因为没有详细的教程,现在做个笔记. 首先,对于下载下来的一大堆文件,包括好多demo,example,src,等等看的我们眼花缭乱,其实我们可以先不要管他,因为 ...

  3. Three.js基础入门系列(九)--导入3D模型

    先来学习今天的知识--Three.js导入3D模型 复杂的3D模型(比如制作一个飞机模型)一般都是用第三方建模工具生成,然后加载到Three.js中. 01 常用建模制作工具 3Dmax 链接地址:h ...

  4. Altium Designer导入3D模型出现:cannot load 3D model from file警告

    这可把我给烦的呀,一整天都在想办法解决这个问题,前前后后安装了8遍,愣是在最后一次才解决.软件的安装都显示破解OK,但是一到封装的时候,想导入3D模型,就显示Cannot load 3D model ...

  5. 解决在OpenGL中导入.obj模型所遇一些问题的方法

    解决在OpenGL中导入.obj模型所遇一些问题的方法 相对路径格式 "/"与"\" 相对路径起始 导入模型的限制 最近在学习 LearnOpenGL CN,学 ...

  6. Bullet 物理引擎 简析[1]

    原创帖子, 转载请注明出处,作者信息.   这个是自己分析bullet的代码过程中的笔记,比较简陋, 希望抛砖引玉, 欢迎板砖 作者: 马良 (www.iphonephysics.com ) (此bl ...

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

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

  8. 详解Unity中的导入3D模型

    前言 三维模型可以表示任何现实世界中存在的物体,自然也可以表示任何游戏世界中存在的物体,比如地面,山川河流,花草树木,建筑,人物,都需要使用三维模型来表示.一般我们使用一些建模软件来建出游戏中需要的模 ...

  9. Cesium学习笔记(九):导入3D模型(obj转gltf)

    在用cesium的过程中难免需要导入别人做好的3D模型,这时候就需要将这些模型转成gltf格式了 当然,官方也给了我们一个网页版的转换器,但是毕竟是网页版的,效率极其低下,文件还不能太大,所以我们就需 ...

最新文章

  1. sql左连接_【PL/SQL 练习题】左连接条件里的And和Where
  2. centos7安装FTP
  3. shell字符串截取总结
  4. Linux——文件打包与压缩
  5. Android的跨进程通信
  6. c#erp项目源码 mysql_Jsp+Ssm+Mysql实现图书馆预约占座管理系统项目源码(可带论文文档)...
  7. linux实现免密登陆
  8. java中程序执行顺序
  9. valgrind 内存泄漏_应用 AddressSanitizer 发现程序内存错误
  10. maven没有resource文件夹_maven项目中没有resource文件夹的问题
  11. 【课程】MIT深度学习课程:架起理论与实践的桥梁
  12. django开发 遇到的问题解决
  13. VS远程Linux项目附加pthread
  14. python将txt文档中的内容按字母顺序进行排序,并存入txt中
  15. 自制 os 极简教程1:写一个操作系统有多难
  16. 高校固定资产折旧使用计算机,高校固定资产管理系统功能介绍
  17. 金融风控实战——反欺诈特征
  18. 大规模定制基本思想和特点介绍
  19. 进出口业务财务一体化外贸流程管理解决方案
  20. 网站死链接检测工具 Xenu 汉化版

热门文章

  1. 堆叠降噪自编码器SDAE
  2. 河南理工计算机专业在哪个校区,河南理工大学有几个校区及校区地址
  3. 巨头财报来袭系好安全带,苹果、微软、特斯拉谁将开启美股巨震?
  4. [计算机毕设]基于java的连连看游戏系统设计与实现(项目报告+答辩PPT+源代码+数据库)
  5. 【大数据】大数据时代,别让思维方式拖你后腿
  6. 求最大公约数(更相减损术)
  7. 如何修复 WordPress 定制开发中登录重定向循环?
  8. 【动态ppt制作软件】Focusky教程 | 如何合并Focusky工程文件?
  9. dota2起源1和2引擎区别_DOTA2正式启用起源2引擎 “强制”使用或引玩家反感
  10. 【PyTorch教程】P22 squential和小实战