improved game soft bodies, works for objects that are using 'set smooth'

use shape matching by default for game soft bodies
store soft body index for game vertices
This commit is contained in:
Erwin Coumans 2008-09-25 03:02:30 +00:00
parent 38a80ff9a5
commit 718e2bf74f
8 changed files with 219 additions and 108 deletions

@ -967,7 +967,7 @@ Object *add_only_object(int type, char *name)
ob->linearStiffness = 1.0f;
ob->angularStiffness = 1.0f;
ob->volumePreservation = 1.0f;
ob->gamesoftFlag = 0;
ob->gamesoftFlag = OB_SOFT_SHAPE_MATCHING;
/* NT fluid sim defaults */
ob->fluidsimFlag = 0;

@ -7853,6 +7853,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
ob->linearStiffness = 1.0f;
ob->angularStiffness = 1.0f;
ob->volumePreservation = 1.0f;
ob->softflag = OB_SOFT_SHAPE_MATCHING;
}
}

@ -1321,6 +1321,13 @@ void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj,
objprop.m_dyna = (blenderobject->gameflag & OB_DYNAMIC) != 0;
objprop.m_softbody = (blenderobject->gameflag & OB_SOFT_BODY) != 0;
objprop.m_angular_rigidbody = (blenderobject->gameflag & OB_RIGID_BODY) != 0;
///for game soft bodies
objprop.m_linearStiffness = blenderobject->linearStiffness;
objprop.m_angularStiffness = blenderobject->angularStiffness;
objprop.m_volumePreservation = blenderobject->volumePreservation;
objprop.m_gamesoftFlag = blenderobject->gamesoftFlag;
objprop.m_ghost = (blenderobject->gameflag & OB_GHOST) != 0;
objprop.m_disableSleeping = (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0;//abuse the OB_COLLISION_RESPONSE flag
//mmm, for now, taks this for the size of the dynamicobject

@ -87,6 +87,12 @@ struct KX_ObjectProperties
bool m_disableSleeping;
bool m_hasCompoundChildren;
bool m_isCompoundChild;
float m_linearStiffness;
float m_angularStiffness;
float m_volumePreservation;
int m_gamesoftFlag;
double m_margin;
KX_BoundBoxClass m_boundclass;
union {

@ -667,6 +667,85 @@ void KX_ConvertODEEngineObject(KX_GameObject* gameobj,
#endif //WIN32
class KX_SoftBodyDeformer : public RAS_Deformer
{
btSoftBody* m_softBody;
class RAS_MeshObject* m_pMeshObject;
class BL_DeformableGameObject* m_gameobj;
public:
KX_SoftBodyDeformer(btSoftBody* softBody,RAS_MeshObject* pMeshObject,BL_DeformableGameObject* gameobj)
: m_softBody(softBody),
m_pMeshObject(pMeshObject),
m_gameobj(gameobj)
{
//printf("KX_SoftBodyDeformer\n");
};
virtual ~KX_SoftBodyDeformer()
{
//printf("~KX_SoftBodyDeformer\n");
};
virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)
{
//printf("relink\n");
}
virtual bool Apply(class RAS_IPolyMaterial *polymat)
{
//printf("apply\n");
RAS_MeshSlot::iterator it;
RAS_MeshMaterial *mmat;
RAS_MeshSlot *slot;
size_t i;
// update the vertex in m_transverts
Update();
// The vertex cache can only be updated for this deformer:
// Duplicated objects with more than one ploymaterial (=multiple mesh slot per object)
// share the same mesh (=the same cache). As the rendering is done per polymaterial
// cycling through the objects, the entire mesh cache cannot be updated in one shot.
mmat = m_pMeshObject->GetMeshMaterial(polymat);
if(!mmat->m_slots[(void*)m_gameobj])
return true;
slot = *mmat->m_slots[(void*)m_gameobj];
// for each array
for(slot->begin(it); !slot->end(it); slot->next(it))
{
btSoftBody::tNodeArray& nodes(m_softBody->m_nodes);
int index = 0;
for(i=it.startvertex; i<it.endvertex; i++,index++) {
RAS_TexVert& v = it.vertex[i];
MT_Point3 pt (
nodes[v.getSoftBodyIndex()].m_x.getX(),
nodes[v.getSoftBodyIndex()].m_x.getY(),
nodes[v.getSoftBodyIndex()].m_x.getZ());
v.SetXYZ(pt);
}
}
return true;
}
virtual bool Update(void)
{
//printf("update\n");
return true;//??
}
virtual RAS_Deformer *GetReplica()
{
//printf("getReplica\n");
return 0;
}
protected:
//class RAS_MeshObject *m_pMesh;
};
// forward declarations
void KX_ConvertBulletObject( class KX_GameObject* gameobj,
@ -916,6 +995,11 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
ci.m_angularDamping = 1.f - shapeprops->m_ang_drag;
//need a bit of damping, else system doesn't behave well
ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behaviour
ci.m_linearStiffness = objprop->m_linearStiffness;
ci.m_angularStiffness= objprop->m_angularStiffness;
ci.m_volumePreservation= objprop->m_volumePreservation;
ci.m_gamesoftFlag = objprop->m_gamesoftFlag;
ci.m_collisionFilterGroup = (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : short(CcdConstructionInfo::StaticFilter);
ci.m_collisionFilterMask = (isbulletdyna) ? short(CcdConstructionInfo::AllFilter) : short(CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::StaticFilter);
ci.m_bRigid = objprop->m_dyna && objprop->m_angular_rigidbody;
@ -990,107 +1074,15 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
physicscontroller->SetObject(gameobj->GetSGNode());
class KX_SoftBodyDeformer : public RAS_Deformer
{
btSoftBody* m_softBody;
class BL_SkinMeshObject* m_pMeshObject;
class BL_DeformableGameObject* m_gameobj;
public:
KX_SoftBodyDeformer(btSoftBody* softBody,BL_SkinMeshObject* pMeshObject,BL_DeformableGameObject* gameobj)
: m_softBody(softBody),
m_pMeshObject(pMeshObject),
m_gameobj(gameobj)
{
//printf("KX_SoftBodyDeformer\n");
};
virtual ~KX_SoftBodyDeformer()
{
//printf("~KX_SoftBodyDeformer\n");
};
virtual void Relink(GEN_Map<class GEN_HashedPtr, void*>*map)
{
//printf("relink\n");
}
virtual bool Apply(class RAS_IPolyMaterial *polymat)
{
//printf("apply\n");
RAS_MeshSlot::iterator it;
RAS_MeshMaterial *mmat;
RAS_MeshSlot *slot;
size_t i;
// update the vertex in m_transverts
Update();
// The vertex cache can only be updated for this deformer:
// Duplicated objects with more than one ploymaterial (=multiple mesh slot per object)
// share the same mesh (=the same cache). As the rendering is done per polymaterial
// cycling through the objects, the entire mesh cache cannot be updated in one shot.
mmat = m_pMeshObject->GetMeshMaterial(polymat);
if(!mmat->m_slots[(void*)m_gameobj])
return true;
slot = *mmat->m_slots[(void*)m_gameobj];
// for each array
for(slot->begin(it); !slot->end(it); slot->next(it))
{
// for each vertex
// copy the untransformed data from the original mvert
int count = 0;
{
for(i=it.startvertex; i<it.endvertex; i++,count++)
{
}
}
btSoftBody::tNodeArray& nodes(m_softBody->m_nodes);
if (count == m_softBody->m_userIndexMapping.size())
{
int index = 0;
for(i=it.startvertex; i<it.endvertex; i++,index++) {
RAS_TexVert& v = it.vertex[i];
MT_Point3 pt (
nodes[m_softBody->m_userIndexMapping[index]].m_x.getX(),
nodes[m_softBody->m_userIndexMapping[index]].m_x.getY(),
nodes[m_softBody->m_userIndexMapping[index]].m_x.getZ());
v.SetXYZ(pt);
//(m_transverts[v.getOrigIndex()]);
}
}
}
return true;
}
virtual bool Update(void)
{
//printf("update\n");
return true;//??
}
virtual RAS_Deformer *GetReplica()
{
//printf("getReplica\n");
return 0;
}
protected:
//class RAS_MeshObject *m_pMesh;
};
///test for soft bodies
if (objprop->m_softbody && physicscontroller)
{
btSoftBody* softBody = physicscontroller->GetSoftBody();
if (softBody && gameobj->GetMesh(0))
if (softBody && gameobj->GetMesh(0))//only the first mesh, if any
{
//should be a mesh then, so add a soft body deformer
KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer(softBody, (BL_SkinMeshObject*)gameobj->GetMesh(0),(BL_DeformableGameObject*)gameobj);
KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer(softBody, gameobj->GetMesh(0),(BL_DeformableGameObject*)gameobj);
gameobj->SetDeformer(softbodyDeformer);
}

@ -222,14 +222,57 @@ void CcdPhysicsController::CreateRigidbody()
psb->appendFace(idx[0],idx[1],idx[2]);
}
///create a mapping between graphics mesh vertices and soft body vertices
{
for (int i=0;i<hlib.m_vertexIndexMapping.size();i++)
psb->m_userIndexMapping.push_back(hlib.m_vertexIndexMapping[i]);
//psb->m_userIndexMapping.push_back(hres.m_Indices[i]);
RAS_MeshObject* rasMesh= GetShapeInfo()->GetMesh();
if (rasMesh)
{
//printf("apply\n");
RAS_MeshSlot::iterator it;
RAS_MeshMaterial *mmat;
RAS_MeshSlot *slot;
size_t i;
//for each material
for (int m=0;m<rasMesh->NumMaterials();m++)
{
// The vertex cache can only be updated for this deformer:
// Duplicated objects with more than one ploymaterial (=multiple mesh slot per object)
// share the same mesh (=the same cache). As the rendering is done per polymaterial
// cycling through the objects, the entire mesh cache cannot be updated in one shot.
mmat = rasMesh->GetMeshMaterial(m);
slot = mmat->m_baseslot;
for(slot->begin(it); !slot->end(it); slot->next(it))
{
int index = 0;
for(i=it.startvertex; i<it.endvertex; i++,index++)
{
RAS_TexVert* vertex = &it.vertex[i];
//search closest index, and store it in vertex
vertex->setSoftBodyIndex(0);
btScalar maxDistSqr = 1e30;
btSoftBody::tNodeArray& nodes(psb->m_nodes);
btVector3 xyz = trans(btVector3(vertex->getXYZ()[0],vertex->getXYZ()[1],vertex->getXYZ()[2]));
for (int n=0;n<nodes.size();n++)
{
btScalar distSqr = (nodes[n].m_x - xyz).length2();
if (distSqr<maxDistSqr)
{
maxDistSqr = distSqr;
vertex->setSoftBodyIndex(n);
}
}
}
}
}
}
}
hlib.ReleaseResult(hres);
psb->randomizeConstraints();
}
@ -292,13 +335,42 @@ void CcdPhysicsController::CreateRigidbody()
//psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RS;//btSoftBody::fCollision::CL_SS+ btSoftBody::fCollision::CL_RS;
psb->m_cfg.collisions = btSoftBody::fCollision::SDF_RS + btSoftBody::fCollision::CL_SS;
//psb->m_cfg.collisions = btSoftBody::fCollision::CL_SS + btSoftBody::fCollision::CL_RS;
//btSoftBody::Material* pm=psb->appendMaterial();
btSoftBody::Material* pm=psb->m_materials[0];
pm->m_kLST = 0.1f;
pm->m_kLST = m_cci.m_linearStiffness;
pm->m_kAST = m_cci.m_angularStiffness;
pm->m_kVST = m_cci.m_volumePreservation;
//pm->m_kAST = 0.01f;
//pm->m_kVST = 0.001f;
psb->generateBendingConstraints(2,pm);
//psb->m_cfg.piterations = 4;
//psb->m_cfg.viterations = 4;
//psb->m_cfg.diterations = 4;
//psb->m_cfg.citerations = 4;
if (m_cci.m_gamesoftFlag & 1)///OB_SOFT_SHAPE_MATCHING)
{
psb->setPose(false,true);//
} else
{
psb->setPose(true,false);
}
psb->m_cfg.kDF = 0.5;
psb->m_cfg.kMT = 0.05;
psb->m_cfg.piterations = 5;
psb->m_cfg.piterations = 5;
//psb->m_cfg.kVC = 20;
psb->randomizeConstraints();
/*
psb->m_cfg.kDF = 0.1f;//1.f;
psb->m_cfg.kDP = 0.0001;
@ -315,10 +387,10 @@ void CcdPhysicsController::CreateRigidbody()
// psb->activate();
// psb->setActivationState(1);
// psb->setDeactivationTime(1.f);
//psb->m_cfg.piterations = 4;
//psb->m_materials[0]->m_kLST = 0.1+(i/(btScalar)(n-1))*0.9;
psb->setTotalMass(m_cci.m_mass);
psb->generateClusters(64);
//psb->generateClusters(8);//(64);
psb->setCollisionFlags(0);
// m_object->setCollisionShape(rbci.m_collisionShape);
btTransform startTrans;
@ -1147,7 +1219,19 @@ bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject* meshobj, bool polytope)
{
const float* vtx = poly->GetVertex(i)->getXYZ();
btPoint3 point(vtx[0],vtx[1],vtx[2]);
m_vertexArray.push_back(point);
//avoid duplicates (could better directly use vertex offsets, rather than a vertex compare)
bool found = false;
for (int j=0;j<m_vertexArray.size();j++)
{
if (m_vertexArray[j]==point)
{
found = true;
break;
}
}
if (!found)
m_vertexArray.push_back(point);
numvalidpolys++;
}
} else

@ -147,6 +147,10 @@ struct CcdConstructionInfo
m_linearDamping(0.1f),
m_angularDamping(0.1f),
m_margin(0.06f),
m_linearStiffness(1.f),
m_angularStiffness(1.f),
m_volumePreservation(1.f),
m_gamesoftFlag(0),
m_collisionFlags(0),
m_bRigid(false),
m_bSoft(false),
@ -169,6 +173,12 @@ struct CcdConstructionInfo
btScalar m_linearDamping;
btScalar m_angularDamping;
btScalar m_margin;
btScalar m_linearStiffness;
btScalar m_angularStiffness;
btScalar m_volumePreservation;
int m_gamesoftFlag;
int m_collisionFlags;
bool m_bRigid;
bool m_bSoft;

@ -44,15 +44,16 @@ class RAS_TexVert
float m_uv1[2]; // 2*4 = 8
float m_uv2[2]; // 2*4 = 8
unsigned int m_rgba; // 4
float m_tangent[4]; // 4*2 = 8
float m_normal[3]; // 3*2 = 6
float m_tangent[4]; // 4*4 = 16
float m_normal[3]; // 3*4 = 12
short m_flag; // 2
short m_softBodyIndex; //2
unsigned int m_unit; // 4
unsigned int m_origindex; // 4
unsigned int m_origindex; // 4
//---------
// 56
// 56+6+8+2=72
// 32 bytes total size, fits nice = 56 = not fit nice.
// We'll go for 64 bytes total size - 24 bytes left.
public:
enum {
FLAT = 1,
@ -91,6 +92,16 @@ public:
return m_normal;
}
short int getSoftBodyIndex() const
{
return m_softBodyIndex;
}
void setSoftBodyIndex(short int sbIndex)
{
m_softBodyIndex = sbIndex;
}
const float* getTangent() const {
return m_tangent;
}