接高度地形圖和三角形網格,同樣是複雜圖形的建立。
先來看看效果
左邊通過提供的頂點生成的多面體,右邊建立一個由球體與長方體組成的組合形狀
首先來了解凸多面體
根據提供的頂點建立一個凸多面體形狀,無論給定的頂點順序是怎樣的,都是建立一個由這些頂點組成的凸多面體。
先來看看btConvexHullShape的解釋及構造函數
///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory.
///It is easier to not pass any points in the constructor, and just add one point at a time, using addPoint.
///btConvexHullShape make an internal copy of the points.
btConvexHullShape(const btScalar* points=0,int numPoints=0, int stride=sizeof(btVector3));
第一個參數就是頂點資料,第二個是頂點個數,第三個是每個頂點占得位元組。
同時提出不需要一次将所有的頂點全部給出,以後可以添加:
void addPoint(const btVector3& point, bool recalculateLocalAabb = true);
增加的頂點資訊,是否重新計算AABB包圍盒
對于提供頂點資料,使用者不需要一直儲存,看源碼可知btConvexHullShape會用btAlignedObjectArray<btVector3>m_unscaledPoints;
來儲存這些頂點資料。
來個示例
看上圖,為什麼會出現一個是三棱錐,而一個卻不是呢?,其實兩個形狀是一樣的,請看我慢慢道來。
前面的解釋btConvexHullShape會根據提供的資料建立多面體,我們要牢記在心。
通過檢視繼承關系圖,我們知道btConvexHullShape繼承自btPolyhedralConvexShape,
而btPolyhedralConvexShape,提供了
///optional method mainly used to generate multiple contact points by clipping polyhedral features (faces/edges)
///experimental/work-in-progress
virtual bool initializePolyhedralFeatures(int shiftVerticesByMargin=0);
可以這樣了解,将提供的點格式化成多面體,也就是說提供頂點後就可以調用initializePolyhedralFeatures
格式化成多面體。
上圖下方是按我們提供的頂點的順序生成的結果,上方為格式化後的結果
下面來看看筆者是如何加入到PhysicsWorld3D
btRigidBody* PhysicsWorld3D::addConvexHull(const float* floatData, int numPoints, const btVector3& position, bool bPoly, const PhysicsMaterial3D& material)
{
btConvexHullShape* colShape = new btConvexHullShape(floatData, numPoints, sizeof(btVector3));
if (bPoly)
{
colShape->initializePolyhedralFeatures();
}
auto body = getBody(colShape, position, material);
_world->addRigidBody(body);
return body;
}
btRigidBody* PhysicsWorld3D::addConvexHull(std::vector<btVector3>& points, const btVector3& position, bool bPoly, const PhysicsMaterial3D& material)
{
auto body = addConvexHull(points[0].m_floats, points.size(), position, bPoly, material);
return body;
}
提供兩個重載函數,一個是直接将包含頂點資料的浮點資料指針作為參數, 另一個是将頂點數組作為參數。
提供第二個重載的目的就是為了從直接将raw檔案的資料傳入來生成多面體,還記得raw檔案吧?Bullet(Cocos2dx)之建立地形
看個例子
std::vector<float> points;
PhysicsHelper3D::loadRaw("monkey.raw", points); // blender 猴頭
_convexBody = _world->addConvexHull(&points[0], points.size() / 3, btVector3(-2, 0, 5), false, PhysicsMaterial3D(5.f, 0.5f, 0.5f, 0.f));
_convexBody = _world->addConvexHull(&points[0], points.size() / 3, btVector3(2, 0, 5), true, PhysicsMaterial3D(5.f, 0.5f, 0.5f, 0.f));
右不格式化,左為格式化
再來了解一下組合形狀
簡言之,将多個形狀組合成一個圖形,最上面的圖檔右方就是一個組合形狀
可由多個不同的Primitive Shape組成
構造函數很簡單
btCompoundShape(bool enableDynamicAabbTree = true);
預設開啟動态樹,優化
關鍵是增加碰撞形狀
void addChildShape(const btTransform& localTransform,btCollisionShape* shape);
localTransform形狀相對偏移,shape碰撞形狀。
相對偏移:加入最終btCompoundShape在(0,0,0),相對偏移就是相對于(0,0,0)
得出要想獲得組合形狀就要自己建立btCollisionShape,然後添加到btCompoundShape
筆者做了簡單的封裝
struct PhysicsShapeInfo3D
{
btCollisionShape* colShape;
btTransform transform;
PhysicsShapeInfo3D() {};
PhysicsShapeInfo3D(btCollisionShape* shape, btTransform& trans)
: colShape(shape), transform(trans)
{}
};
提供簡單的結構體來傳遞Collision Shapes屬性
btRigidBody* PhysicsWorld3D::addCompound(std::vector<PhysicsShapeInfo3D>& shapeList, const btVector3& position, const PhysicsMaterial3D& material)
{
btCompoundShape* shape = new btCompoundShape;
for (auto& shapeInfo : shapeList)
{
shape->addChildShape(shapeInfo.transform, shapeInfo.colShape);
}
auto body = getBody(shape, position, material);
_world->addRigidBody(body);
return body;
}
std::vector<PhysicsShapeInfo3D>& shapeList 形狀屬性清單,來擷取組合形狀的剛體
來個例子
// 1
shape = new btBoxShape(btVector3(1.f, 1.f, 1.f));
shapeInfo.colShape = shape;
trans.setOrigin(btVector3(0, 1, 0));
shapeInfo.transform = trans;
_shapes.push_back(shapeInfo);
// 2
shape = new btSphereShape(1.f);
shapeInfo.colShape = shape;
trans.setOrigin(btVector3(0, 3, 0));
shapeInfo.transform = trans;
_shapes.push_back(shapeInfo);
_world->addCompound(_shapes, btVector3(0, 0, 5.f));
上例建立一個上為球體,下為長方體的組合形狀
當然也可以通過球體和圓柱建立保齡球,也就可以寫出一個保齡球的小遊戲。
源代碼