Bullet provides several classes of btbvhtrianglemeshshape,btheightfieldterrainshape to create some grid graphics, first to understand Btheightfieldterrainshape, create a 3D terrain from the height graph data.
A static mesh that's optimised for and described by the surface of a height map.
Official website explanation:http://bulletphysics.com/Bullet/BulletFull/classbtHeightfieldTerrainShape.html# a90d823ba5f44871a0bcfce0174177223
Recommended first read the official website introduction
The first few
Based on the height map data. High topographic map generated by Raw
Parameter Settings heightfieldinfo info (_heightmapdata.getbytes (), Phy_uchar, 1.6f/udata, -1.f, 1.f, BtVector3 (25.f/uda Ta, 1.f, 25.f/udata));
(UData is the maximum value of _heightmapdata )
Custom data generation height topographic map (phy_float)
Parameter Settings heightfieldinfo info (mapData, phy_float, 1.f, -1.f, 1.f, BtVector3(1.f, 1.F, 1). f));
MapData custom data, random 0~1 data
Custom data generation height topographic map (phy_float)
Parameter Settings heightfieldinfo info (mapData, phy_short, 1.f, -1.f, 1.f, BtVector3(1.f, 1.F, 1). f));
MapData data for custom data 0,1
examples of Bullet 's own Demo
Btheightfieldterrainshape has two constructors, which analyze the more complex one
Btheightfieldterrainshape (
int heightstickwidth, total x axis width
int heightsticklength, z-axis total length
For example, width = x, length = 64, 128,z axis direction is 64
Const void* Heightfielddata, height data
Btscalar Heightscale, *heightscale per byte = actual height
Btscalar minheight, min. height
Btscalar maxheight, max height
Terrain origin = (MinHeight + maxheight) * 0.5
int Upaxis, Direction axis value 0=x, 1=y, 2=z, determines the orientation of the terrain, similar to the normal vector
Phy_scalartype heightdatatype, data Format 3 kinds, Phy_uchar, Phy_short, phy_float
BOOL Flipquadedges Square cropping
);
As an example,
50*50 data
for (int i=0; i<50; ++i)
{
for (int j=0; j<50; ++j)
{
HEIGHTMAP[I*50+J] = j% 2;
}
}
For Heightmap[i*50+j]
1. If 0, minheight = 0.f, maxheight = 6.F;
The lowest point is just -3.f.
2. If 0, minheight = 0.f, maxheight = 12.f;
The lowest point is just -6.f.
3. If 0, minheight = 0.f, maxheight = 3.F;
The lowest point is just -1.5f.
1. If 2, MinHeight = 0.f, maxheight = 6.F;
The lowest point is just -4.f.
2. If 2, MinHeight = 0.f, maxheight = 12.f;
The lowest point is just -7.f.
3. If 2, MinHeight = 0.f, maxheight = 3.F;
The lowest point is just -2.5f.
Terrain Offset offsety =-(MinHeight + maxheight);
Not recommended MinHeight + MaxHeight < 0, unstable
Heightscale * Value (Heightfielddata[i]) is the actual height
Height calculation:
For Phy_uchar
Lowest point y = OffsetY + min (heightfielddata); Miny = 0
The highest point y = OffsetY + max (heightfielddata) * Heightscale;
For Phy_short, Phy_float
The highest point y = OffsetY + max (heightfielddata) * Heightscale;
Lowest point y = OffsetY + min (heightfielddata) * Heightscale;
Attention:
The grid spacing should not be too large, passing through the Assembly of objects.
Custom data type simplified parameter passing
struct Heightfieldinfo{int heightstickwidth;int heightsticklength;void* heightfielddata; Phy_scalartype hdt;btscalar heightscale;btscalar minheight;btscalar maxheight;int upAxis;bool useFloatData;bool Flipquadedges;btvector3 localscaling; Heightfieldinfo (int width, int length, void* data, Phy_scalartype type = Phy_short, btscalar heiscale = 1.f, Btscalar MinH ei = 0.f, btscalar Maxhei = 1.f, const btvector3& scale = BtVector3 (1, 1, 1), int up = 1, bool Usefloat = FALSE, bool Filpquad = False): Heightstickwidth (width), heightsticklength (length), Heightfielddata (data), Heightscale (Heiscale), MinHeight (Minhei), MaxHeight (Maxhei), localscaling (scale), Upaxis (UP), HDT (type), Usefloatdata (Usefloat), Flipquadedges (Filpquad) {}};
Physicsworld3d creating a highly topographic map
btrigidbody* physicsworld3d::addheightfieldterrain (const heightfieldinfo& fieldInfo, const btvector3& Position, const physicsmaterial3d& material) {Ccassert (Material.mass = = 0.f, "height field ' s mass must be 0."); btheightfieldterrainshape* heightfieldshape = new Btheightfieldterrainshape (Fieldinfo.heightstickwidth, Fieldinfo.heightsticklength, Fieldinfo.heightfielddata, Fieldinfo.heightscale,fieldinfo.minheight, Fieldinfo.maxheight, Fieldinfo.upaxis, FIELDINFO.HDT, fieldinfo.flipquadedges);heightfieldshape-> Setusediamondsubdivision (TRUE);//The Diagonal heightfieldshape->setlocalscaling (fieldinfo.localscaling) will appear in the Diamond subdivision rectangle square; Auto BODY = GetBody (heightfieldshape, position, material); _world->addrigidbody (body); return body;}
Here's a description Btbvhtrianglemeshshape , the physical simulation of grid shape is realized by loading triangular meshes .
Http://bulletphysics.com/Bullet/BulletFull/classbtBvhTriangleMeshShape.html
Look at the effect
The terrain can be perfectly fused with the model , and even spheres with a radius of 0.1 will not cross the terrain
The shape used is btbvhtrianglemeshshape, and the construction method has two
Btbvhtrianglemeshshape (
btstridingmeshinterface* meshinterface, //grid interface, storing grid data
bool usequantizedaabbcompression,//compression? Only valid if BUILDBVH is True
Const BtVector3& Bvhaabbmin,
Const BtVector3& Bvhaabbmax, //mesh cannot exceed bvhaabb bounding box, only BUILDBVH is true
bool BUILDBVH = true); //optimize BVH
Btbvhtrianglemeshshape (
btstridingmeshinterface* meshinterface,
bool usequantizedaabbcompression,
bool BUILDBVH = true);
By importing the raw triangle data of a model, you can create a terrain
How to load model data, official website class diagram
Provide Bttriangleindexvertexarray, load grid data
Bttriangleindexvertexarray (
int numtriangles,//Triangle number
int* triangleindexbase,//Triangle index Array first address
int triangleindexstride,//index size per triangle = Index Type size * 3
int numvertices,//Vertex count
btscalar* vertexbase,//vertex array first address
int vertexstride); Bytes per vertex = vertex element * 3
Since the index type is int, use int
about how the raw triangle data is obtained,
1. Can be obtained using cocos2dx 's load model function ( pending Experiment )
2. directly export data using Blender or software that can export the original triangular data of the model
About Blender an open source 3D modeling software , official website :/http www.blender.org/ , with its own game engine, the physics engine is Bullet
Export triangle data,Blender has a plugin specifically exported triangle data file suffix named raw, it is text Format ,
When exporting, first let the model rotate a certain angle , the coordinate system is not the OpenGL coordinate system,cocos2dx uses OpenGL the coordinate system
The raw file format is simple:n rows of 9 Floating-point data per line ( describe a triangle ), each three floating point is a vertex
3. Custom formats
。。。。
To implement the data loading.
First read the raw file, implement a simple physicshelper3d
#ifndef __physics_helper_3d_h__#define __physics_helper_3d_h__#include <cocos2d.h>using_ns_cc;class Physicshelper3d{public:static std::vector<float> loadraw (const char* fileName), static bool Loadraw (const char* FileName, std::vector<float>& verts);}; #endif//!__physics_helper_3d_h__#include "PhysicsHelper3D.h" std::vector<float> Physicshelper3d::loadraw ( Const char* fileName) {std::vector<float> data;if (loadraw (filename, data)) {return data;} Return std::vector<float> (0);} BOOL Physicshelper3d::loadraw (const char* fileName, std::vector<float>& Verts) {Char line[1024];float Onedata;auto rawdata = fileutils::getinstance ()->getstringfromfile (fileName);//use COCOS2DX to load files Std::stringstream SS, Ssline;ss << Rawdata;while (Ss.getline (line, 1024))//read a row {ssline << line;for (int i = 0; i < 9; i++)// Get 9 floating-point numbers {ssline >> onedata;verts.push_back (Onedata);}} return true;}
It's not hard, but it's not good to load the file, but let's use it.
_indexvertexarrays = new Bttriangleindexvertexarray (_verts.size ()/9, &_verindices[0], 3 * sizeof (int), _verts.size ()/3, (btscalar*) &_verts[0], 3 * sizeof (float)), _meshshape = new Btbvhtrianglemeshshape (_indexvertexarrays, true); _verts is the number of vector<float> triangles =_verts.size ()/9 in order to build a convenient implementation physicsmesh3d#ifndef __physics_mesh_3d_h__#define __ Physics_mesh_3d_h__#include "Bullet/btbulletdynamicscommon.h" #include "cocos2d.h" Using_ns_cc;class PhysicsMesh3D{ Public:static physicsmesh3d* constuct (const char* filename); void destroy (); bool Initwithfile (const char* filename); private:std::vector<float> _verts;//storage vertex std::vector<int> _verindices;// Vertex index bttriangleindexvertexarray* _indexvertexarrays;//triangle Data cc_synthesize_readonly (btbvhtrianglemeshshape*, _ Meshshape, Meshshape);//shape}; #endifCC_SYNTHESIZE_READONLY the macro bool Physicsmesh3d::initwithfile provided for COCOS2DX (const char* fileName) {_indexvertexarrays = Nullptr;_verts.clear (); _verindices.clear (); if (Physicshelper3d::loadraw ( FilenaMe, _verts)//Load Data {_verindices.resize (_verts.size ());//The position of vertex is index for (int i=0; i < _verts.size (); ++i) {_verindices[ I] = i;} _indexvertexarrays = new Bttriangleindexvertexarray (_verts.size ()/9,//number of triangles &_verindices[0],//Triangle data Array First address 3 * Sizeo f (int),//A triangular index size _verts.size ()/3,//Vertex count (btscalar*) &_verts[0],//vertex array first address 3 * sizeof (float));//a vertex size//Get Shape_m Eshshape = new Btbvhtrianglemeshshape (_indexvertexarrays, True); return true;} return false;}
Release the requested memory
void Physicsmesh3d::d Estroy () {_verts.clear (); _verindices.clear ();d elete _indexvertexarrays;delete this;}
Create a method for adding mesh in Physicsworld3d
btrigidbody* Addtrianglemeshshape (physicsmesh3d* mesh3d, const btvector3& position, const physicsmaterial3d& material = Physics_material3d_plane); btrigidbody* Physicsworld3d::addtrianglemeshshape (physicsmesh3d* Mesh3D, const btvector3& position, const physicsmaterial3d& material) {Ccassert (Material.mass = = 0.f, "body ' s mass must be 0."); Auto BODY = GetBody (Mesh3d->getmeshshape (), position, material); _world->addrigidbody (body); return body;}
Test
HelloWorld Adding variables
physicsmesh3d* _phymesh3d;//Mesh Shape
Add Mesh
_phymesh3d = Physicsmesh3d::constuct ("Heightmap.raw"); _world->addtrianglemeshshape (_phyMesh3D, BtVector3 (0, 0, 0 );//load plane model Auto Spplane = sprite3d::create ("model/heightmap.c3b"); This->addchild (Spplane); Spplane->setposition3d (Vec3 (0, 0, 0)); spplane->setrotation3d (VEC3 (0, 180, 0));
OnExit () Don't forget.
_phymesh3d->destroy ();
For the convenience of testing, a roaming camera has been implemented and is available for explanation.
Full Source and resources
GitHub
Bullet (COCOS2DX) Creation of terrain