天天看點

Bullet(Cocos2dx)之凸多面體形狀群組合形狀

接高度地形圖和三角形網格,同樣是複雜圖形的建立。

先來看看效果

Bullet(Cocos2dx)之凸多面體形狀群組合形狀

左邊通過提供的頂點生成的多面體,右邊建立一個由球體與長方體組成的組合形狀

首先來了解凸多面體

根據提供的頂點建立一個凸多面體形狀,無論給定的頂點順序是怎樣的,都是建立一個由這些頂點組成的凸多面體。

先來看看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;

來儲存這些頂點資料。

來個示例

Bullet(Cocos2dx)之凸多面體形狀群組合形狀

看上圖,為什麼會出現一個是三棱錐,而一個卻不是呢?,其實兩個形狀是一樣的,請看我慢慢道來。

前面的解釋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));
           
Bullet(Cocos2dx)之凸多面體形狀群組合形狀

右不格式化,左為格式化

再來了解一下組合形狀

簡言之,将多個形狀組合成一個圖形,最上面的圖檔右方就是一個組合形狀

可由多個不同的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));

上例建立一個上為球體,下為長方體的組合形狀

當然也可以通過球體和圓柱建立保齡球,也就可以寫出一個保齡球的小遊戲。

 源代碼

繼續閱讀