加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Bullet(Cocos2dx)之创建地形

发布时间:2020-12-14 20:09:15 所属栏目:百科 来源:网络整理
导读:Bullet(Cocos2dx)之创建地形 分类: cocos2d-x 物理引擎 2015-01-09 19:45 196人阅读 评论(0) 收藏 举报 cocos2dx bullet 物理引擎 游戏引擎 Bullet 提供了几个类 btBvhTriangleMeshShape , btHeightfieldTerrainShape 去创建一些网格图形,首先了解 btHeig

Bullet(Cocos2dx)之创建地形

分类: cocos2d-x 物理引擎 196人阅读 评论(0) 收藏 举报
cocos2dx bullet 物理引擎 游戏引擎

Bullet提供了几个类btBvhTriangleMeshShapebtHeightfieldTerrainShape去创建一些网格图形,首先了解btHeightfieldTerrainShape,通过高度图数据创建一个3D地形。

Astaticmeshthatisoptimisedforanddescribedbythesurfaceofaheightmap.

官网解释:http://bulletphysics.com/Bullet/BulletFull/classbtHeightfieldTerrainShape.html#a90d823ba5f44871a0bcfce0174177223

建议先阅读官网介绍

首先可以下几个效果图


根据高度图数据.raw生成的高度地形图

参数设置HeightfieldInfoinfo(128,128,_heightMapData.getBytes(),PHY_UCHAR,1.6f/uData,-1.f,1.f,btVector3(25.f/uData,25.f/uData));

(uData_heightMapData的最大值)


自定义数据生成高度地形图(PHY_FLOAT)

参数设置HeightfieldInfoinfo(128,mapData,PHY_FLOAT,btVector3(1.f,1.f));

mapData自定义数据,随机0~1的数据



自定义数据生成高度地形图(PHY_FLOAT)

参数设置HeightfieldInfoinfo(128,PHY_SHORT,1.f));

mapData自定义数据0,1的数据


Bullet自带的Demo中的例子


btHeightfieldTerrainShape有两个构造函数,这里分析较复杂的一个

btHeightfieldTerrainShape(

intheightStickWidth,x轴总宽度

intheightStickLength,z轴总长度

比如width=128,length=64则x轴方向为128,z轴方向为64

constvoid*heightfieldData,高度数据

btScalarheightScale,每个字节*heightScale=实际高度

btScalarminHeight,最小高度

btScalarmaxHeight,最大高度

地形原点=(minHeight+maxHeight)*0.5

intupAxis,方向轴取值0=x,1=y,2=z,决定地形的朝向,类似法向量

PHY_ScalarTypeheightDataType,数据格式3种,PHY_SHORT,PHY_FLOAT

boolflipQuadEdges 方形裁剪

);


举个例子

50*50数据

for(inti=0;i<50;++i)

{

for(intj=0;j<50;++j)

{

heightMap[i*50+j]=j%2;

}

}

对于heightMap[i*50+j]

1.如果为0,minHeight=0.f,maxHeight=6.f;

最低点正好为-3.f

2.如果为0,maxHeight=12.f;

最低点正好为-6.f

3.如果为0,maxHeight=3.f;

最低点正好为-1.5f

1.如果为2,maxHeight=6.f;

最低点正好为-4.f

2.如果为2,maxHeight=12.f;

最低点正好为-7.f

3.如果为2,maxHeight=3.f;

最低点正好为-2.5f

地形偏移offsetY=-(minHeight+maxHeight);

不推荐minHeight+maxHeight<0,不稳定

heightScale*value(heightfieldData[i])为实际高度

高度计算:

对于PHY_UCHAR

最低点y=offsetY+min(heightfieldData);minY=0

最高点y=offsetY+max(heightfieldData)*heightScale;

对于PHY_SHORT,PHY_FLOAT

最高点y=offsetY+max(heightfieldData)*heightScale;

最低点y=offsetY+min(heightfieldData)*heightScale;

注意:

网格间隔不要过大,过大会出现物体穿过。

自定义数据类型简化参数传递

[cpp] view plain copy
  1. structHeightfieldInfo
  2. {
  3. intheightStickWidth;
  4. intheightStickLength;
  5. void*heightfieldData;
  6. PHY_ScalarTypehdt;
  7. btScalarheightScale;
  8. btScalarminHeight;
  9. btScalarmaxHeight;
  10. intupAxis;
  11. booluseFloatData;
  12. boolflipQuadEdges;
  13. btVector3localScaling;
  14. HeightfieldInfo(intwidth,intlength,void*data,PHY_ScalarTypetype=PHY_SHORT,
  15. btScalarheiScale=1.f,btScalarminHei=0.f,btScalarmaxHei=1.f,
  16. constbtVector3&scale=btVector3(1,1,1),intup=1,
  17. booluseFloat=false,boolfilpQuad=false):
  18. heightStickWidth(width),heightStickLength(length),heightfieldData(data),
  19. heightScale(heiScale),minHeight(minHei),maxHeight(maxHei),
  20. localScaling(scale),upAxis(up),
  21. hdt(type),useFloatData(useFloat),flipQuadEdges(filpQuad)
  22. {}
  23. };

PhysicsWorld3D创建高度地形图

[cpp] view plain copy
  1. btRigidBody*PhysicsWorld3D::addHeightfieldTerrain(constHeightfieldInfo&fieldInfo,constbtVector3&position,constPhysicsMaterial3D&material)
  2. {
  3. CCAssert(material.mass==0.f,"heightfield'smassmustbe0.");
  4. btHeightfieldTerrainShape*heightfieldShape=newbtHeightfieldTerrainShape(
  5. fieldInfo.heightStickWidth,fieldInfo.heightStickLength,fieldInfo.heightfieldData,fieldInfo.heightScale,
  6. fieldInfo.minHeight,fieldInfo.maxHeight,fieldInfo.upAxis,fieldInfo.hdt,fieldInfo.flipQuadEdges);
  7. heightfieldShape->setUseDiamondSubdivision(true);//钻石细分矩形方格会出现对角线
  8. heightfieldShape->setLocalScaling(fieldInfo.localScaling);
  9. autobody=getBody(heightfieldShape,position,material);
  10. _world->addRigidBody(body);
  11. returnbody;
  12. }

下面来介绍btBvhTriangleMeshShape,通过载入三角网格,实现网格形状的物理模拟

http://bulletphysics.com/Bullet/BulletFull/classbtBvhTriangleMeshShape.html

看看效果


地形能够与模型完美的融合在一起,而且即使半径为0.1的球体也不会穿过地形

使用的shape就是btBvhTriangleMeshShape,构造方法有两个

btBvhTriangleMeshShape(

btStridingMeshInterface*meshInterface,//网格接口,存放网格数据

booluseQuantizedAabbCompression,//压缩?只有buildBvh为true才有效

constbtVector3&bvhAabbMin,

constbtVector3&bvhAabbMax,//mesh不可超过bvhaabb包围盒,只有buildBvh为true才有效

boolbuildBvh=true);//优化BVH


btBvhTriangleMeshShape(

btStridingMeshInterface*meshInterface,

booluseQuantizedAabbCompression,

boolbuildBvh=true);

通过导入一个模型的原始三角形数据,就可以建立上图的地形

如何载入模型数据,官网类关系图


提供btTriangleIndexVertexArray,载入网格数据

btTriangleIndexVertexArray(

intnumTriangles,//三角个数

int*triangleIndexBase,//三角形索引数组首地址

inttriangleIndexStride,//每个三角形索引大小=索引类型大小*3

intnumVertices,//顶点个数

btScalar*vertexBase,//顶点数组首地址

intvertexStride); //每个顶点字节=顶点元素*3

既然索引类型为int,就用int

关于原始三角形数据如何得到,

1.可以利用cocos2dx的载入模型函数获取(有待实验)

2.利用Blender或者可以导出模型原始三角数据的软件,直接导出数据

关于Blender一款开源的3D建模软件,官网:http://www.blender.org/,自带游戏引擎,物理引擎就是Bullet

导出三角形数据,Blender有个插件专门导出三角形数据文件后缀名为raw,它是文本格式的,

导出时首先要让模型旋转一定角度,坐标系不是opengl的坐标系,cocos2dx采用的就是opengl的坐标系

raw文件格式非常简单:n,每行9个浮点数据(描述一个三角形),每三个浮点为一个顶点

3.自定义格式

。。。。

来实现数据的载入吧

首先读取raw文件,实现一个简单的PhysicsHelper3D

[cpp] view plain copy
  1. #ifndef__PHYSICS_HELPER_3D_H__
  2. #define__PHYSICS_HELPER_3D_H__
  3. #include<cocos2d.h>
  4. USING_NS_CC;
  5. classPhysicsHelper3D
  6. {
  7. public:
  8. staticstd::vector<float>loadRaw(constchar*fileName);
  9. staticboolloadRaw(constchar*fileName,std::vector<float>&verts);
  10. };
  11. #endif//!__PHYSICS_HELPER_3D_H__
  12. #include"PhysicsHelper3D.h"
  13. std::vector<float>PhysicsHelper3D::loadRaw(constchar*fileName)
  14. {
  15. std::vector<float>data;
  16. if(loadRaw(fileName,data))
  17. {
  18. returndata;
  19. }
  20. returnstd::vector<float>(0);
  21. }
  22. boolPhysicsHelper3D::loadRaw(constchar*fileName,std::vector<float>&verts)
  23. {
  24. charline[1024];
  25. floatoneData;
  26. autorawData=FileUtils::getInstance()->getStringFromFile(fileName);//利用cocos2dx载入文件
  27. std::stringstreamss,ssLine;
  28. ss<<rawData;
  29. while(ss.getline(line,1024))//读取一行
  30. {
  31. ssLine<<line;
  32. for(inti=0;i<9;i++)//获取9个浮点数
  33. {
  34. ssLine>>oneData;
  35. verts.push_back(oneData);
  36. }
  37. }
  38. returntrue;
  39. }

并不是很难吧,载入文件办法不好,不过先将就着用吧

[cpp] view plain copy
  1. _indexVertexArrays=newbtTriangleIndexVertexArray(_verts.size()/9,&_verIndices[0],3*sizeof(int),
  2. _verts.size()/3,(btScalar*)&_verts[0],3*sizeof(float));
  3. _meshShape=newbtBvhTriangleMeshShape(_indexVertexArrays,true);
  4. _verts是vector<float>三角形的个数=_verts.size()/9
  5. 为了构建方便实现PhysicsMesh3D
  6. #ifndef__PHYSICS_MESH_3D_H__
  7. #define__PHYSICS_MESH_3D_H__
  8. #include"Bullet/btBulletDynamicsCommon.h"
  9. #include"cocos2d.h"
  10. USING_NS_CC;
  11. classPhysicsMesh3D
  12. {
  13. public:
  14. staticPhysicsMesh3D*constuct(constchar*fileName);
  15. voiddestroy();
  16. boolinitWithFile(constchar*fileName);
  17. private:
  18. std::vector<float>_verts;//存放顶点
  19. std::vector<int>_verIndices;//顶点索引
  20. btTriangleIndexVertexArray*_indexVertexArrays;//三角形数据
  21. CC_SYNTHESIZE_READONLY(btBvhTriangleMeshShape*,_meshShape,MeshShape);//shape
  22. };
  23. #endif
  24. CC_SYNTHESIZE_READONLY为cocos2dx提供的宏
  25. boolPhysicsMesh3D::initWithFile(constchar*fileName)
  26. {
  27. _indexVertexArrays=nullptr;
  28. _verts.clear();
  29. _verIndices.clear();
  30. if(PhysicsHelper3D::loadRaw(fileName,_verts))//载入数据
  31. {
  32. _verIndices.resize(_verts.size());//顶点的位置就是索引
  33. for(inti=0;i<_verts.size();++i)
  34. {
  35. _verIndices[i]=i;
  36. }
  37. _indexVertexArrays=newbtTriangleIndexVertexArray(
  38. _verts.size()/9,//三角形个数
  39. &_verIndices[0],//三角数据数组首地址
  40. 3*sizeof(int),//一个三角索引大小
  41. _verts.size()/3,//顶点个数
  42. (btScalar*)&_verts[0],//顶点数组首地址
  43. 3*sizeof(float));//一个顶点大小
  44. //获取shape
  45. _meshShape=newbtBvhTriangleMeshShape(_indexVertexArrays,true);
  46. returntrue;
  47. }
  48. returnfalse;
  49. }

释放申请的内存

[cpp] view plain copy
  1. voidPhysicsMesh3D::destroy()
  2. {
  3. _verts.clear();
  4. _verIndices.clear();
  5. delete_indexVertexArrays;
  6. deletethis;
  7. }

在PhysicsWorld3D建立一个添加Mesh的方法

[cpp] view plain copy
  1. btRigidBody*addTriangleMesh(PhysicsMesh3D*mesh3D,
  2. constPhysicsMaterial3D&material=PHYSICS_MATERIAL3D_PLANE);
  3. btRigidBody*PhysicsWorld3D::addTriangleMeshShape(PhysicsMesh3D*mesh3D,constbtVector3&position,constPhysicsMaterial3D&material)
  4. {
  5. CCAssert(material.mass==0.f,"body'smassmustbe0.");
  6. autobody=getBody(mesh3D->getMeshShape(),material);
  7. _world->addRigidBody(body);
  8. returnbody;
  9. }

测试

HelloWorld添加变量

[cpp] view plain copy
  1. PhysicsMesh3D*_phyMesh3D;//meshshape
添加网格
[cpp] view plain copy
  1. _phyMesh3D=PhysicsMesh3D::constuct("heightmap.raw");
  2. _world->addTriangleMesh(_phyMesh3D,btVector3(0,0));
  3. //载入plane模型
  4. autospPlane=Sprite3D::create("model/heightmap.c3b");
  5. this->addChild(spPlane);
  6. spPlane->setPosition3D(Vec3(0,0));
  7. spPlane->setRotation3D(Vec3(0,180,0));

onExit()不要忘了

[cpp] view plain copy
  1. _phyMesh3D->destroy();


为了方便测试,实现了一个漫游摄像机,有空讲解一下。

完整源码及资源

github

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读