BGE Physics

Add support back for reinstancePhysics mesh, a frequently requested feature in the BGE forums.
from what I can tell Sumo supported this but bullet never did.
Currently only accessible via python at the moment.

- rigid body, dynamic, static types work.
- instanced physics meshes are modified too.
- compound shapes are not supported.

Physics mesh can be re-instanced from...
* shape keys & armature deformations
* subsurf (any other modifiers too)
* RAS_TexVert's (can be modified from python)

Moved the reinstancePhysicsMesh functions from RAS_MeshObject into KX_GameObject since the physics data is stored here.

video and blend file demo.
http://www.graphicall.org/ftp/ideasman42/reinstance.ogv
http://www.graphicall.org/ftp/ideasman42/reinstance_demo.blend
This commit is contained in:
2009-07-25 22:57:29 +00:00
parent 1c00eacca2
commit e9ca43521f
14 changed files with 506 additions and 50 deletions

View File

@@ -22,6 +22,8 @@ subject to the following restrictions:
#include "PHY_IMotionState.h"
#include "CcdPhysicsEnvironment.h"
#include "RAS_MeshObject.h"
#include "KX_GameObject.h"
#include "BulletSoftBody/btSoftBody.h"
#include "BulletSoftBody//btSoftBodyInternals.h"
#include "BulletSoftBody/btSoftBodyHelpers.h"
@@ -529,7 +531,7 @@ void CcdPhysicsController::CreateRigidbody()
}
static void DeleteBulletShape(btCollisionShape* shape)
static void DeleteBulletShape(btCollisionShape* shape, bool free)
{
if (shape->getShapeType() == TRIANGLE_MESH_SHAPE_PROXYTYPE)
{
@@ -539,7 +541,66 @@ static void DeleteBulletShape(btCollisionShape* shape)
if (meshInterface)
delete meshInterface;
}
delete shape;
if(free) {
delete shape;
}
}
bool CcdPhysicsController::DeleteControllerShape( )
{
if (m_collisionShape)
{
// collision shape is always unique to the controller, can delete it here
if (m_collisionShape->isCompound())
{
// bullet does not delete the child shape, must do it here
btCompoundShape* compoundShape = (btCompoundShape*)m_collisionShape;
int numChild = compoundShape->getNumChildShapes();
for (int i=numChild-1 ; i >= 0; i--)
{
btCollisionShape* childShape = compoundShape->getChildShape(i);
DeleteBulletShape(childShape, true);
}
}
DeleteBulletShape(m_collisionShape, true);
return true;
}
return false;
}
bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape)
{
/* Note, deleting the previous collision shape must be done alredy */
/* if (m_collisionShape) DeleteControllerShape(); */
m_object->setCollisionShape(newShape);
m_collisionShape= newShape;
m_cci.m_collisionShape= newShape;
/* Copied from CcdPhysicsEnvironment::addCcdPhysicsController() */
/* without this, an object can rest on the old physics mesh
* and not move to account for the physics mesh, even with 'nosleep' */
btSoftRigidDynamicsWorld* dw= GetPhysicsEnvironment()->getDynamicsWorld();
btCollisionObjectArray &obarr= dw->getCollisionObjectArray();
btCollisionObject *ob;
btBroadphaseProxy* proxy;
for(int i= 0; i < obarr.size(); i++) {
ob= obarr[i];
if (ob->getCollisionShape() == newShape); {
proxy = obarr[i]->getBroadphaseHandle();
if(proxy)
dw->getPairCache()->cleanProxyFromPairs(proxy,dw->getDispatcher());
}
}
return true;
}
CcdPhysicsController::~CcdPhysicsController()
@@ -554,22 +615,8 @@ CcdPhysicsController::~CcdPhysicsController()
delete m_bulletMotionState;
delete m_object;
if (m_collisionShape)
{
// collision shape is always unique to the controller, can delete it here
if (m_collisionShape->isCompound())
{
// bullet does not delete the child shape, must do it here
btCompoundShape* compoundShape = (btCompoundShape*)m_collisionShape;
int numChild = compoundShape->getNumChildShapes();
for (int i=numChild-1 ; i >= 0; i--)
{
btCollisionShape* childShape = compoundShape->getChildShape(i);
DeleteBulletShape(childShape);
}
}
DeleteBulletShape(m_collisionShape);
}
DeleteControllerShape();
if (m_shapeInfo)
{
m_shapeInfo->Release();
@@ -1264,7 +1311,7 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplica()
if (m_shapeInfo)
{
// This situation does not normally happen
cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(0.01);
cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin);
}
else if (m_collisionShape)
{
@@ -1621,6 +1668,311 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, DerivedMesh* dm,
return true;
}
#include <cstdio>
/* Updates the arrays used by CreateBulletShape(),
* take care that recalcLocalAabb() runs after CreateBulletShape is called.
* */
bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject* gameobj, class RAS_MeshObject* meshobj)
{
int numpolys;
int numverts;
unsigned int tot_bt_tris= 0;
unsigned int tot_bt_verts= 0;
int i, j;
int v_orig;
/* Use for looping over verts in a face as a try or 2 tris */
const int quad_verts[7]= {0,1,2, 0,2,3, -1};
const int tri_verts[4]= {0,1,2, -1};
const int *fv_pt;
if(gameobj==NULL && meshobj==NULL)
return false;
if(m_shapeType != PHY_SHAPE_MESH)
return false;
RAS_Deformer *deformer= gameobj ? gameobj->GetDeformer():NULL;
/* get the mesh from the object if not defined */
if(meshobj==NULL) {
/* modifier mesh */
if(deformer && deformer->GetFinalMesh())
meshobj= deformer->GetRasMesh();
/* game object first mesh */
if(meshobj==NULL) {
if(gameobj->GetMeshCount() > 0) {
meshobj= gameobj->GetMesh(0);
}
}
}
if(deformer && deformer->GetFinalMesh() && deformer->GetRasMesh() == meshobj)
{ /*
* Derived Mesh Update
*
* */
DerivedMesh* dm= gameobj->GetDeformer()->GetFinalMesh();
MVert *mvert = dm->getVertArray(dm);
MFace *mface = dm->getFaceArray(dm);
numpolys = dm->getNumFaces(dm);
numverts = dm->getNumVerts(dm);
int* index = (int*)dm->getFaceDataArray(dm, CD_ORIGINDEX);
MFace *mf;
MVert *mv;
int flen;
if(CustomData_has_layer(&dm->faceData, CD_MTFACE))
{
MTFace *tface = (MTFace *)dm->getFaceDataArray(dm, CD_MTFACE);
MTFace *tf;
vector<bool> vert_tag_array(numverts, false);
vector<int> vert_remap_array(numverts, 0);
for(mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++) {
if(tf->mode & TF_DYNAMIC)
{
if(mf->v4) {
tot_bt_tris+= 2;
flen= 4;
} else {
tot_bt_tris++;
flen= 3;
}
for(j=0; j<flen; j++)
{
v_orig = (*(&mf->v1 + j));
if(vert_tag_array[v_orig]==false)
{
vert_tag_array[v_orig]= true;
vert_remap_array[v_orig]= tot_bt_verts;
tot_bt_verts++;
}
}
}
}
m_vertexArray.resize(tot_bt_verts*3);
btScalar *bt= &m_vertexArray[0];
m_triFaceArray.resize(tot_bt_tris*3);
int *tri_pt= &m_triFaceArray[0];
m_polygonIndexArray.resize(tot_bt_tris);
int *poly_index_pt= &m_polygonIndexArray[0];
for(mf= mface, tf= tface, i=0; i < numpolys; mf++, tf++, i++)
{
if(tf->mode & TF_DYNAMIC)
{
if(mf->v4) {
fv_pt= quad_verts;
*poly_index_pt++ = *poly_index_pt++ = index[i];
flen= 4;
} else {
fv_pt= tri_verts;
*poly_index_pt++ = index[i];
flen= 3;
}
for(; *fv_pt > -1; fv_pt++)
{
v_orig = (*(&mf->v1 + (*fv_pt)));
if(vert_tag_array[v_orig])
{
mv= mvert + v_orig;
*bt++ = mv->co[0];
*bt++ = mv->co[1];
*bt++ = mv->co[2];
vert_tag_array[v_orig]= false;
}
*tri_pt++ = vert_remap_array[v_orig];
}
}
}
}
else {
/* no need for a vertex mapping. simple/fast */
tot_bt_verts= numverts;
for(mf= mface, i=0; i < numpolys; mf++, i++) {
tot_bt_tris += (mf->v4 ? 2:1);
}
m_vertexArray.resize(tot_bt_verts*3);
btScalar *bt= &m_vertexArray[0];
m_triFaceArray.resize(tot_bt_tris*3);
int *tri_pt= &m_triFaceArray[0];
m_polygonIndexArray.resize(tot_bt_tris);
int *poly_index_pt= &m_polygonIndexArray[0];
for(mv= mvert, i=0; i < numverts; mv++, i++) {
*bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2];
}
for(mf= mface, i=0; i < numpolys; mf++, i++) {
unsigned int *fv = &mf->v1;
if(mf->v4) {
fv_pt= quad_verts;
*poly_index_pt++ = *poly_index_pt++ = index[i];
}
else {
fv_pt= tri_verts;
*poly_index_pt++ = index[i];
}
for(; *fv_pt > -1; fv_pt++)
*tri_pt++ = (*(&mf->v1 + (*fv_pt)));
}
}
}
else { /*
* RAS Mesh Update
*
* */
/* Note!, gameobj can be NULL here */
/* transverts are only used for deformed RAS_Meshes, the RAS_TexVert data
* is too hard to get at, see below for details */
float (*transverts)[3]= NULL;
int transverts_tot= 0; /* with deformed meshes - should always be greater then the max orginal index, or we get crashes */
if(deformer) {
/* map locations from the deformed array
*
* Could call deformer->Update(); but rely on redraw updating.
* */
transverts= deformer->GetTransVerts(&transverts_tot);
}
// Tag verts we're using
numpolys= meshobj->NumPolygons();
numverts= meshobj->m_sharedvertex_map.size();
const float *xyz;
vector<bool> vert_tag_array(numverts, false);
vector<int> vert_remap_array(numverts, 0);
for(int p=0; p<numpolys; p++)
{
RAS_Polygon* poly= meshobj->GetPolygon(p);
if (poly->IsCollider())
{
for(i=0; i < poly->VertexCount(); i++)
{
v_orig= poly->GetVertex(i)->getOrigIndex();
if(vert_tag_array[v_orig]==false)
{
vert_tag_array[v_orig]= true;
vert_remap_array[v_orig]= tot_bt_verts;
tot_bt_verts++;
}
}
tot_bt_tris += (poly->VertexCount()==4 ? 2:1);
}
}
m_vertexArray.resize(tot_bt_verts*3);
btScalar *bt= &m_vertexArray[0];
m_triFaceArray.resize(tot_bt_tris*3);
int *tri_pt= &m_triFaceArray[0];
/* cant be used for anything useful in this case, since we dont rely on the original mesh
* will just be an array like pythons range(tot_bt_tris) */
m_polygonIndexArray.resize(tot_bt_tris);
for(int p=0; p<numpolys; p++)
{
RAS_Polygon* poly= meshobj->GetPolygon(p);
if (poly->IsCollider())
{
/* quad or tri loop */
fv_pt= (poly->VertexCount()==3 ? tri_verts:quad_verts);
for(; *fv_pt > -1; fv_pt++)
{
v_orig= poly->GetVertex(*fv_pt)->getOrigIndex();
if(vert_tag_array[v_orig])
{
if(transverts) {
/* deformed mesh, using RAS_TexVert locations would be too troublesome
* because they are use the gameob as a hash in the material slot */
*bt++ = transverts[v_orig][0];
*bt++ = transverts[v_orig][1];
*bt++ = transverts[v_orig][2];
}
else {
/* static mesh python may have modified */
xyz= meshobj->GetVertexLocation( v_orig );
*bt++ = xyz[0];
*bt++ = xyz[1];
*bt++ = xyz[2];
}
vert_tag_array[v_orig]= false;
}
*tri_pt++ = vert_remap_array[v_orig];
}
}
m_polygonIndexArray[p]= p; /* dumb counting */
}
}
#if 0
/* needs #include <cstdio> */
printf("# vert count %d\n", m_vertexArray.size());
for(int i=0; i<m_vertexArray.size(); i+=3) {
printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i+1], m_vertexArray[i+2]);
}
printf("# face count %d\n", m_triFaceArray.size());
for(int i=0; i<m_triFaceArray.size(); i+=3) {
printf("f %d %d %d\n", m_triFaceArray[i]+1, m_triFaceArray[i+1]+1, m_triFaceArray[i+2]+1);
}
#endif
/* force recreation of the m_unscaledShape.
* If this has multiple users we cant delete */
if(m_unscaledShape) {
// dont free now so it can re-allocate under the same location and not break pointers.
// DeleteBulletShape(m_unscaledShape);
m_forceReInstance= true;
}
m_meshObject= meshobj;
return true;
}
bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo)
{
if (shapeInfo == NULL)
@@ -1696,7 +2048,7 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin)
} else
{
if (!m_unscaledShape)
if (!m_unscaledShape || m_forceReInstance)
{
btTriangleIndexVertexArray* indexVertexArrays = 0;
@@ -1731,7 +2083,18 @@ btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin)
}
// this shape will be shared and not deleted until shapeInfo is deleted
m_unscaledShape = new btBvhTriangleMeshShape( indexVertexArrays, true );
// for UpdateMesh, reuse the last memory location so instancing wont crash.
if(m_unscaledShape) {
DeleteBulletShape(m_unscaledShape, false);
m_unscaledShape->~btBvhTriangleMeshShape();
m_unscaledShape = new(m_unscaledShape) btBvhTriangleMeshShape( indexVertexArrays, true );
} else {
m_unscaledShape = new btBvhTriangleMeshShape( indexVertexArrays, true );
}
m_forceReInstance= false;
m_unscaledShape->recalcLocalAabb();
}
collisionShape = new btScaledBvhTriangleMeshShape(m_unscaledShape, btVector3(1.0f,1.0f,1.0f));
@@ -1776,7 +2139,7 @@ CcdShapeConstructionInfo::~CcdShapeConstructionInfo()
m_shapeArray.clear();
if (m_unscaledShape)
{
DeleteBulletShape(m_unscaledShape);
DeleteBulletShape(m_unscaledShape, true);
}
m_vertexArray.clear();
if (m_shapeType == PHY_SHAPE_MESH && m_meshObject != NULL)