Add a helper method that creates a btCompoundShape from a btGimpactMeshShape, for more robust collision detection.
The idea is to create tetrahedra from each surface triangle, by moving its centroid inwards along the collision normal using depth. If the centroid hits an internal triangle, it will stop there. The commit also includes part of the gimpact raycast performance improvement, except for the actual btCollisionWorld part (that file was out-of-date and needs manual patching)
This commit is contained in:
93
src/BulletCollision/Gimpact/btCompoundFromGimpact.h
Normal file
93
src/BulletCollision/Gimpact/btCompoundFromGimpact.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef BT_COMPOUND_FROM_GIMPACT
|
||||
#define BT_COMPOUND_FROM_GIMPACT
|
||||
|
||||
#include "BulletCollision/CollisionShapes/btCompoundShape.h"
|
||||
#include "btGImpactShape.h"
|
||||
#include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h"
|
||||
|
||||
struct MyCallback : public btTriangleRaycastCallback
|
||||
{
|
||||
int m_ignorePart;
|
||||
int m_ignoreTriangleIndex;
|
||||
|
||||
|
||||
MyCallback(const btVector3& from, const btVector3& to, int ignorePart, int ignoreTriangleIndex)
|
||||
:btTriangleRaycastCallback(from,to),
|
||||
m_ignorePart(ignorePart),
|
||||
m_ignoreTriangleIndex(ignoreTriangleIndex)
|
||||
{
|
||||
|
||||
}
|
||||
virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex)
|
||||
{
|
||||
if (partId!=m_ignorePart || triangleIndex!=m_ignoreTriangleIndex)
|
||||
{
|
||||
if (hitFraction < m_hitFraction)
|
||||
return hitFraction;
|
||||
}
|
||||
|
||||
return m_hitFraction;
|
||||
}
|
||||
};
|
||||
struct MyInternalTriangleIndexCallback :public btInternalTriangleIndexCallback
|
||||
{
|
||||
const btGImpactMeshShape* m_gimpactShape;
|
||||
btCompoundShape* m_colShape;
|
||||
btScalar m_depth;
|
||||
|
||||
MyInternalTriangleIndexCallback (btCompoundShape* colShape, const btGImpactMeshShape* meshShape, btScalar depth)
|
||||
:m_colShape(colShape),
|
||||
m_gimpactShape(meshShape),
|
||||
m_depth(depth)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex)
|
||||
{
|
||||
btVector3 scale = m_gimpactShape->getLocalScaling();
|
||||
btVector3 v0=triangle[0]*scale;
|
||||
btVector3 v1=triangle[1]*scale;
|
||||
btVector3 v2=triangle[2]*scale;
|
||||
|
||||
btVector3 centroid = (v0+v1+v2)/3;
|
||||
btVector3 normal = (v1-v0).cross(v2-v0);
|
||||
normal.normalize();
|
||||
btVector3 rayFrom = centroid;
|
||||
btVector3 rayTo = centroid-normal*m_depth;
|
||||
|
||||
MyCallback cb(rayFrom,rayTo,partId,triangleIndex);
|
||||
|
||||
m_gimpactShape->processAllTrianglesRay(&cb,rayFrom, rayTo);
|
||||
if (cb.m_hitFraction<1)
|
||||
{
|
||||
rayTo.setInterpolate3(cb.m_from,cb.m_to,cb.m_hitFraction);
|
||||
//rayTo = cb.m_from;
|
||||
//rayTo = rayTo.lerp(cb.m_to,cb.m_hitFraction);
|
||||
//gDebugDraw.drawLine(tr(centroid),tr(centroid+normal),btVector3(1,0,0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
btBU_Simplex1to4* tet = new btBU_Simplex1to4(v0,v1,v2,rayTo);
|
||||
btTransform ident;
|
||||
ident.setIdentity();
|
||||
m_colShape->addChildShape(ident,tet);
|
||||
}
|
||||
};
|
||||
|
||||
btCompoundShape* btCreateCompoundFromGimpactShape(const btGImpactMeshShape* gimpactMesh, btScalar depth)
|
||||
{
|
||||
btCompoundShape* colShape = new btCompoundShape();
|
||||
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
|
||||
MyInternalTriangleIndexCallback cb(colShape,gimpactMesh, depth);
|
||||
btVector3 aabbMin,aabbMax;
|
||||
gimpactMesh->getAabb(tr,aabbMin,aabbMax);
|
||||
gimpactMesh->getMeshInterface()->InternalProcessAllTriangles(&cb,aabbMin,aabbMax);
|
||||
|
||||
return colShape;
|
||||
}
|
||||
|
||||
#endif //BT_COMPOUND_FROM_GIMPACT
|
||||
@@ -25,6 +25,7 @@ subject to the following restrictions:
|
||||
|
||||
#define CALC_EXACT_INERTIA 1
|
||||
|
||||
|
||||
void btGImpactCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const
|
||||
{
|
||||
lockChildShapes();
|
||||
@@ -144,6 +145,31 @@ void btGImpactMeshShape::rayTest(const btVector3& rayFrom, const btVector3& rayT
|
||||
{
|
||||
}
|
||||
|
||||
void btGImpactMeshShapePart::processAllTrianglesRay(btTriangleCallback* callback,const btVector3& rayFrom, const btVector3& rayTo) const
|
||||
{
|
||||
lockChildShapes();
|
||||
|
||||
btAlignedObjectArray<int> collided;
|
||||
btVector3 rayDir(rayTo - rayFrom);
|
||||
rayDir.normalize();
|
||||
m_box_set.rayQuery(rayDir, rayFrom, collided);
|
||||
|
||||
if(collided.size()==0)
|
||||
{
|
||||
unlockChildShapes();
|
||||
return;
|
||||
}
|
||||
|
||||
int part = (int)getPart();
|
||||
btPrimitiveTriangle triangle;
|
||||
int i = collided.size();
|
||||
while(i--)
|
||||
{
|
||||
getPrimitiveTriangle(collided[i],triangle);
|
||||
callback->processTriangle(triangle.m_vertices,part,collided[i]);
|
||||
}
|
||||
unlockChildShapes();
|
||||
}
|
||||
|
||||
void btGImpactMeshShapePart::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const
|
||||
{
|
||||
@@ -182,6 +208,15 @@ void btGImpactMeshShape::processAllTriangles(btTriangleCallback* callback,const
|
||||
}
|
||||
}
|
||||
|
||||
void btGImpactMeshShape::processAllTrianglesRay(btTriangleCallback* callback,const btVector3& rayFrom, const btVector3& rayTo) const
|
||||
{
|
||||
int i = m_mesh_parts.size();
|
||||
while(i--)
|
||||
{
|
||||
m_mesh_parts[i]->processAllTrianglesRay(callback, rayFrom, rayTo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
||||
const char* btGImpactMeshShape::serialize(void* dataBuffer, btSerializer* serializer) const
|
||||
|
||||
@@ -51,6 +51,7 @@ enum eGIMPACT_SHAPE_TYPE
|
||||
};
|
||||
|
||||
|
||||
|
||||
//! Helper class for tetrahedrons
|
||||
class btTetrahedronShapeEx:public btBU_Simplex1to4
|
||||
{
|
||||
@@ -288,6 +289,15 @@ public:
|
||||
(void) callback; (void) aabbMin; (void) aabbMax;
|
||||
}
|
||||
|
||||
//! Function for retrieve triangles.
|
||||
/*!
|
||||
It gives the triangles in local space
|
||||
*/
|
||||
virtual void processAllTrianglesRay(btTriangleCallback* /*callback*/,const btVector3& /*rayFrom*/, const btVector3& /*rayTo*/) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//!@}
|
||||
|
||||
};
|
||||
@@ -639,7 +649,7 @@ public:
|
||||
{
|
||||
if(indicestype == PHY_SHORT)
|
||||
{
|
||||
unsigned short * s_indices = (unsigned short *)(indexbase + face_index*indexstride);
|
||||
unsigned short* s_indices = (unsigned short *)(indexbase + face_index * indexstride);
|
||||
i0 = s_indices[0];
|
||||
i1 = s_indices[1];
|
||||
i2 = s_indices[2];
|
||||
@@ -885,6 +895,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
|
||||
virtual void processAllTrianglesRay(btTriangleCallback* callback,const btVector3& rayFrom,const btVector3& rayTo) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -1141,6 +1152,8 @@ public:
|
||||
*/
|
||||
virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const;
|
||||
|
||||
virtual void processAllTrianglesRay (btTriangleCallback* callback,const btVector3& rayFrom,const btVector3& rayTo) const;
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
||||
|
||||
Reference in New Issue
Block a user