Added SoftBody demo, contribution by Nathanael Presson. Will integrate into Bullet broadphase.

Added very basic drawTriangle for btIDebugDraw, useful for basic softbody visualization.
Added btGjkEpa2, contribution by Nathanael Presson. Improved version of EPA penetration depth computation, more suitable for multi-core/SPU (less memory usage). Note: btGjkEpa2 is not enabled by default currently.
This commit is contained in:
erwin.coumans 2008-03-30 23:08:06 +00:00
parent 8d38ef49ef
commit d4698cb3d5
16 changed files with 4737 additions and 2 deletions

View File

@ -1,2 +1,2 @@
SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo Benchmarks HelloWorld MultiThreadedDemo CcdPhysicsDemo ConstraintDemo GenericJointDemo RagdollDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo ColladaDemo UserCollisionAlgorithm CharacterDemo ) SUBDIRS( OpenGL AllBulletDemos ConvexDecompositionDemo Benchmarks HelloWorld MultiThreadedDemo CcdPhysicsDemo ConstraintDemo GenericJointDemo RagdollDemo BasicDemo BspDemo MovingConcaveDemo VehicleDemo ColladaDemo UserCollisionAlgorithm CharacterDemo SoftBodyDemo )

View File

@ -82,6 +82,7 @@ SubInclude TOP Demos ConcaveDemo ;
SubInclude TOP Demos ConstraintDemo ; SubInclude TOP Demos ConstraintDemo ;
SubInclude TOP Demos RagdollDemo ; SubInclude TOP Demos RagdollDemo ;
SubInclude TOP Demos GenericJointDemo ; SubInclude TOP Demos GenericJointDemo ;
SubInclude TOP Demos SoftBodyDemo ;
SubInclude TOP Demos ContinuousConvexCollision ; SubInclude TOP Demos ContinuousConvexCollision ;
SubInclude TOP Demos GjkConvexCastDemo ; SubInclude TOP Demos GjkConvexCastDemo ;
SubInclude TOP Demos Raytracer ; SubInclude TOP Demos Raytracer ;

View File

@ -24,7 +24,7 @@ GLDebugDrawer::GLDebugDrawer()
} }
void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& color) void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
{ {
if (m_debugMode > 0) // if (m_debugMode > 0)
{ {
glBegin(GL_LINES); glBegin(GL_LINES);
glColor3f(color.getX(), color.getY(), color.getZ()); glColor3f(color.getX(), color.getY(), color.getZ());

View File

@ -0,0 +1,62 @@
# This is basically the overall name of the project in Visual Studio this is the name of the Solution File
# For every executable you have with a main method you should have an add_executable line below.
# For every add executable line you should list every .cpp and .h file you have associated with that executable.
# This is the variable for Windows. I use this to define the root of my directory structure.
SET(GLUT_ROOT ${BULLET_PHYSICS_SOURCE_DIR}/Glut)
# You shouldn't have to modify anything below this line
########################################################
# This is the shortcut to finding GLU, GLUT and OpenGL if they are properly installed on your system
# This should be the case.
INCLUDE (${CMAKE_ROOT}/Modules/FindGLU.cmake)
INCLUDE (${CMAKE_ROOT}/Modules/FindGLUT.cmake)
INCLUDE (${CMAKE_ROOT}/Modules/FindOpenGL.cmake)
IF (WIN32)
# This is the Windows code for which Opengl, and Glut are not properly installed
# since I can't install them I must cheat and copy libraries around
INCLUDE_DIRECTORIES(${GLUT_ROOT})
# LINK_DIRECTORIES(${GLUT_ROOT}\\lib)
IF (${GLUT_glut_LIBRARY} MATCHES "GLUT_glut_LIBRARY-NOTFOUND")
SET(GLUT_glut_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/Glut/glut32.lib)
# LINK_LIBRARIES(${GLUT_ROOT}\\lib\\glut32 ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
# TARGET_LINK_LIBRARIES(table ${GLUT_ROOT}\\lib\\glut32)
#
# ADD_CUSTOM_COMMAND(TARGET table POST_BUILD COMMAND copy ${GLUT_ROOT}\\lib\\glut32.dll ${GLUT_ROOT}\\bin\\vs2005\\Debug
# COMMAND copy ${GLUT_ROOT}\\lib\\glut32.dll ${GLUT_ROOT}\\bin\\vs2003\\Debug
# COMMAND copy ${GLUT_ROOT}\\lib\\glut32.dll ${GLUT_ROOT}\\bin\\vs6\\Debug)
ELSE (${GLUT_glut_LIBRARY} MATCHES "GLUT_glut_LIBRARY-NOTFOUND")
# LINK_LIBRARIES(${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
# TARGET_LINK_LIBRARIES(table ${GLUT_glut_LIBRARY})
ENDIF(${GLUT_glut_LIBRARY} MATCHES "GLUT_glut_LIBRARY-NOTFOUND")
# TARGET_LINK_LIBRARIES(table ${OPENGL_gl_LIBRARY})
# TARGET_LINK_LIBRARIES(table ${OPENGL_glu_LIBRARY})
ELSE (WIN32)
# This is the lines for linux. This should always work if everything is installed and working fine.
# SET(CMAKE_BUILD_TYPE Debug)
# SET(CMAKE_CXX_FLAGS_DEBUG "-g")
INCLUDE_DIRECTORIES(/usr/include /usr/local/include ${GLUT_INCLUDE_DIR})
# TARGET_LINK_LIBRARIES(table ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
# TARGET_LINK_LIBRARIES(checker ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glU_LIBRARY})
ENDIF (WIN32)
INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/src ${BULLET_PHYSICS_SOURCE_DIR}/Demos/OpenGL }
)
LINK_LIBRARIES(
LibOpenGLSupport LibConvexHull LibBulletDynamics LibBulletCollision LibLinearMath ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}
)
ADD_EXECUTABLE(SoftBodyDemo
main.cpp
SoftDemo.cpp
)

3
Demos/SoftDemo/Jamfile Normal file
View File

@ -0,0 +1,3 @@
SubDir TOP Demos SoftBodyDemo ;
BulletDemo SoftBodyDemo : [ Wildcard *.h *.cpp ] ;

1286
Demos/SoftDemo/SoftDemo.cpp Normal file

File diff suppressed because it is too large Load Diff

116
Demos/SoftDemo/SoftDemo.h Normal file
View File

@ -0,0 +1,116 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btSoftBody implementation by Nathanael Presson
#ifndef SOFT_DEMO_H
#define SOFT_DEMO_H
#include "DemoApplication.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "BulletDynamics/SoftBody/btSoftBody.h"
#include "BulletDynamics/SoftBody/btSparseSDF.h"
class btBroadphaseInterface;
class btCollisionShape;
class btOverlappingPairCache;
class btCollisionDispatcher;
class btConstraintSolver;
struct btCollisionAlgorithmCreateFunc;
class btDefaultCollisionConfiguration;
///CcdPhysicsDemo shows basic stacking using Bullet physics, and allows toggle of Ccd (using key '1')
class SoftDemo : public DemoApplication
{
public:
struct SoftBodyImpl : btSoftBody::ISoftBody
{
void Attach(btSoftBody*);
void Detach(btSoftBody*);
void StartCollide(const btVector3&,const btVector3&);
bool CheckContactPrecise(const btVector3&,
btSoftBody::ISoftBody::sCti&);
bool CheckContact( const btVector3&,
btSoftBody::ISoftBody::sCti&);
void EndCollide();
void EvaluateMedium( const btVector3&,
btSoftBody::ISoftBody::sMedium&);
SoftDemo* pdemo;
btScalar air_density;
btScalar water_density;
btScalar water_offset;
btVector3 water_normal;
} m_softbodyimpl;
btAlignedObjectArray<btSoftBody*> m_softbodies;
btSparseSdf<3> m_sparsesdf;
bool m_autocam;
//keep the collision shapes, for deletion/cleanup
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
btBroadphaseInterface* m_broadphase;
btCollisionDispatcher* m_dispatcher;
#ifdef USE_PARALLEL_DISPATCHER
#ifdef WIN32
class Win32ThreadSupport* m_threadSupportCollision;
class Win32ThreadSupport* m_threadSupportSolver;
#endif
#endif
btConstraintSolver* m_solver;
btCollisionAlgorithmCreateFunc* m_boxBoxCF;
btDefaultCollisionConfiguration* m_collisionConfiguration;
public:
void initPhysics();
void exitPhysics();
virtual ~SoftDemo()
{
exitPhysics();
}
virtual void clientMoveAndDisplay();
virtual void displayCallback();
void createStack( btCollisionShape* boxShape, float halfCubeSize, int size, float zPos );
static DemoApplication* Create()
{
SoftDemo* demo = new SoftDemo;
demo->myinit();
demo->initPhysics();
return demo;
}
//
void clientResetScene();
void renderme();
void keyboardCallback(unsigned char key, int x, int y);
};
#endif //CCD_PHYSICS_DEMO_H

37
Demos/SoftDemo/main.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SoftDemo.h"
#include "GlutStuff.h"
#include "GLDebugDrawer.h"
#include "btBulletDynamicsCommon.h"
GLDebugDrawer gDebugDrawer;
int main(int argc,char** argv)
{
SoftDemo* softDemo = new SoftDemo();
softDemo->initPhysics();
softDemo->getDynamicsWorld()->setDebugDrawer(&gDebugDrawer);
glutmain(argc, argv,640,480,"Bullet Physics Demo. http://bullet.sf.net",softDemo);
delete softDemo;
return 0;
}

View File

@ -111,6 +111,8 @@ ADD_LIBRARY(LibBulletCollision
NarrowPhaseCollision/btContinuousConvexCollision.h NarrowPhaseCollision/btContinuousConvexCollision.h
NarrowPhaseCollision/btGjkEpa.cpp NarrowPhaseCollision/btGjkEpa.cpp
NarrowPhaseCollision/btGjkEpa.h NarrowPhaseCollision/btGjkEpa.h
NarrowPhaseCollision/btGjkEpa2.cpp
NarrowPhaseCollision/btGjkEpa2.h
NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp
NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h
NarrowPhaseCollision/btConvexCast.cpp NarrowPhaseCollision/btConvexCast.cpp

View File

@ -0,0 +1,891 @@
#include "BulletCollision/CollisionShapes/btConvexInternalShape.h"
#include "BulletCollision/CollisionShapes/btSphereShape.h"
#include "btGjkEpa2.h"
#if defined(DEBUG) || defined (_DEBUG)
#include <stdio.h> //for debug printf
#ifdef __SPU__
#include <spu_printf.h>
#define printf spu_printf
#endif //__SPU__
#endif
namespace gjkepa2_impl
{
// Config
/* GJK */
#define GJK_MAX_ITERATIONS 128
#define GJK_ACCURARY ((btScalar)0.0001)
#define GJK_MIN_DISTANCE ((btScalar)0.0001)
#define GJK_DUPLICATED_EPS ((btScalar)0.0001)
#define GJK_SIMPLEX2_EPS ((btScalar)0.0)
#define GJK_SIMPLEX3_EPS ((btScalar)0.0)
#define GJK_SIMPLEX4_EPS ((btScalar)0.0)
/* EPA */
#define EPA_MAX_VERTICES 64
#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
#define EPA_MAX_ITERATIONS 255
#define EPA_ACCURACY ((btScalar)0.0001)
#define EPA_FALLBACK (10*EPA_ACCURACY)
#define EPA_PLANE_EPS ((btScalar)0.00001)
#define EPA_INSIDE_EPS ((btScalar)0.01)
// Shorthands
typedef unsigned int U;
typedef unsigned char U1;
// MinkowskiDiff
struct MinkowskiDiff
{
const btConvexShape* m_shapes[2];
btMatrix3x3 m_toshape1;
btTransform m_toshape0;
btVector3 (btConvexShape::*Ls)(const btVector3&) const;
void EnableMargin(bool enable)
{
if(enable)
Ls=&btConvexShape::localGetSupportingVertex;
else
Ls=&btConvexShape::localGetSupportingVertexWithoutMargin;
}
inline btVector3 Support0(const btVector3& d) const
{
return(((m_shapes[0])->*(Ls))(d));
}
inline btVector3 Support1(const btVector3& d) const
{
return(m_toshape0*((m_shapes[1])->*(Ls))(m_toshape1*d));
}
inline btVector3 Support(const btVector3& d) const
{
return(Support0(d)-Support1(-d));
}
btVector3 Support(const btVector3& d,U index) const
{
if(index)
return(Support1(d));
else
return(Support0(d));
}
};
typedef MinkowskiDiff tShape;
// GJK
struct GJK
{
/* Types */
struct sSV
{
btVector3 d,w;
};
struct sSimplex
{
sSV* c[4];
btScalar p[4];
U rank;
};
struct eStatus { enum _ {
Valid,
Inside,
Failed };};
/* Fields */
tShape m_shape;
btVector3 m_ray;
btScalar m_distance;
sSimplex m_simplices[2];
sSV m_store[4];
sSV* m_free[4];
U m_nfree;
U m_current;
sSimplex* m_simplex;
eStatus::_ m_status;
/* Methods */
GJK()
{
Initialize();
}
void Initialize()
{
m_ray = btVector3(0,0,0);
m_nfree = 0;
m_status = eStatus::Failed;
m_current = 0;
m_distance = 0;
}
eStatus::_ Evaluate(const tShape& shapearg,const btVector3& guess)
{
U iterations=0;
btScalar sqdist=0;
btScalar alpha=0;
btVector3 lastw[4];
U clastw=0;
/* Initialize solver */
m_free[0] = &m_store[0];
m_free[1] = &m_store[1];
m_free[2] = &m_store[2];
m_free[3] = &m_store[3];
m_nfree = 4;
m_current = 0;
m_status = eStatus::Valid;
m_shape = shapearg;
m_distance = 0;
/* Initialize simplex */
m_simplices[0].rank = 0;
m_ray = guess;
const btScalar sqrl= m_ray.length2();
appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0));
m_simplices[0].p[0] = 1;
m_ray = m_simplices[0].c[0]->w;
sqdist = sqrl;
lastw[0] =
lastw[1] =
lastw[2] =
lastw[3] = m_ray;
/* Loop */
do {
const U next=1-m_current;
sSimplex& cs=m_simplices[m_current];
sSimplex& ns=m_simplices[next];
/* Check zero */
const btScalar rl=m_ray.length();
if(rl<GJK_MIN_DISTANCE)
{/* Touching or inside */
m_status=eStatus::Inside;
break;
}
/* Append new vertice in -'v' direction */
appendvertice(cs,-m_ray);
const btVector3& w=cs.c[cs.rank-1]->w;
bool found=false;
for(U i=0;i<4;++i)
{
if((w-lastw[i]).length2()<GJK_DUPLICATED_EPS)
{ found=true;break; }
}
if(found)
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
}
else
{/* Update lastw */
lastw[clastw=(clastw+1)&3]=w;
}
/* Check for termination */
const btScalar omega=dot(m_ray,w)/rl;
alpha=btMax(omega,alpha);
if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
}
/* Reduce simplex */
btScalar weights[4];
U mask=0;
switch(cs.rank)
{
case 2: sqdist=projectorigin( cs.c[0]->w,
cs.c[1]->w,
weights,mask);break;
case 3: sqdist=projectorigin( cs.c[0]->w,
cs.c[1]->w,
cs.c[2]->w,
weights,mask);break;
case 4: sqdist=projectorigin( cs.c[0]->w,
cs.c[1]->w,
cs.c[2]->w,
cs.c[3]->w,
weights,mask);break;
}
if(sqdist>=0)
{/* Valid */
ns.rank = 0;
m_ray = btVector3(0,0,0);
m_current = next;
for(U i=0,ni=cs.rank;i<ni;++i)
{
if(mask&(1<<i))
{
ns.c[ns.rank] = cs.c[i];
ns.p[ns.rank++] = weights[i];
m_ray += cs.c[i]->w*weights[i];
}
else
{
m_free[m_nfree++] = cs.c[i];
}
}
if(mask==15) m_status=eStatus::Inside;
}
else
{/* Return old simplex */
removevertice(m_simplices[m_current]);
break;
}
m_status=((++iterations)<GJK_MAX_ITERATIONS)?m_status:eStatus::Failed;
} while(m_status==eStatus::Valid);
m_simplex=&m_simplices[m_current];
switch(m_status)
{
case eStatus::Valid: m_distance=m_ray.length();break;
case eStatus::Inside: m_distance=0;break;
}
return(m_status);
}
bool EncloseOrigin()
{
switch(m_simplex->rank)
{
case 1:
{
for(U i=0;i<3;++i)
{
btVector3 axis=btVector3(0,0,0);
axis[i]=1;
appendvertice(*m_simplex, axis);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
appendvertice(*m_simplex,-axis);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
}
}
break;
case 2:
{
const btVector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w;
for(U i=0;i<3;++i)
{
btVector3 axis=btVector3(0,0,0);
axis[i]=1;
if(btFabs(dot(axis,d))>0)
{
const btVector3 p=cross(d,axis);
appendvertice(*m_simplex, p);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
appendvertice(*m_simplex,-p);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
}
}
}
break;
case 3:
{
const btVector3 n=cross(m_simplex->c[1]->w-m_simplex->c[0]->w,
m_simplex->c[2]->w-m_simplex->c[0]->w);
const btScalar l=n.length();
if(l>0)
{
appendvertice(*m_simplex,n);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
appendvertice(*m_simplex,-n);
if(EncloseOrigin()) return(true);
removevertice(*m_simplex);
}
}
break;
case 4:
{
if(btFabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w,
m_simplex->c[1]->w-m_simplex->c[3]->w,
m_simplex->c[2]->w-m_simplex->c[3]->w))>0)
return(true);
}
break;
}
return(false);
}
/* Internals */
void getsupport(const btVector3& d,sSV& sv) const
{
sv.d = d/d.length();
sv.w = m_shape.Support(sv.d);
}
void removevertice(sSimplex& simplex)
{
m_free[m_nfree++]=simplex.c[--simplex.rank];
}
void appendvertice(sSimplex& simplex,const btVector3& v)
{
simplex.p[simplex.rank]=0;
simplex.c[simplex.rank]=m_free[--m_nfree];
getsupport(v,*simplex.c[simplex.rank++]);
}
static btScalar det(const btVector3& a,const btVector3& b,const btVector3& c)
{
return( a.y()*b.z()*c.x()+a.z()*b.x()*c.y()-
a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+
a.x()*b.y()*c.z()-a.z()*b.y()*c.x());
}
static btScalar projectorigin( const btVector3& a,
const btVector3& b,
btScalar* w,U& m)
{
const btVector3 d=b-a;
const btScalar l=d.length2();
if(l>GJK_SIMPLEX2_EPS)
{
const btScalar t(l>0?-dot(a,d)/l:0);
if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); }
else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); }
else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); }
}
return(-1);
}
static btScalar projectorigin( const btVector3& a,
const btVector3& b,
const btVector3& c,
btScalar* w,U& m)
{
static const U imd3[]={1,2,0};
const btVector3* vt[]={&a,&b,&c};
const btVector3 dl[]={a-b,b-c,c-a};
const btVector3 n=cross(dl[0],dl[1]);
const btScalar l=n.length2();
if(l>GJK_SIMPLEX3_EPS)
{
btScalar mindist=-1;
btScalar subw[2];
U subm;
for(U i=0;i<3;++i)
{
if(dot(*vt[i],cross(dl[i],n))>0)
{
const U j=imd3[i];
const btScalar subd(projectorigin(*vt[i],*vt[j],subw,subm));
if((mindist<0)||(subd<mindist))
{
mindist = subd;
m = ((subm&1)?1<<i:0)+((subm&2)?1<<j:0);
w[i] = subw[0];
w[j] = subw[1];
w[imd3[j]] = 0;
}
}
}
if(mindist<0)
{
const btScalar d=dot(a,n);
const btScalar s=btSqrt(l);
const btVector3 p=n*(d/l);
mindist = p.length2();
m = 7;
w[0] = (cross(dl[1],b-p)).length()/s;
w[1] = (cross(dl[2],c-p)).length()/s;
w[2] = 1-(w[0]+w[1]);
}
return(mindist);
}
return(-1);
}
static btScalar projectorigin( const btVector3& a,
const btVector3& b,
const btVector3& c,
const btVector3& d,
btScalar* w,U& m)
{
static const U imd3[]={1,2,0};
const btVector3* vt[]={&a,&b,&c,&d};
const btVector3 dl[]={a-d,b-d,c-d};
const btScalar vl=det(dl[0],dl[1],dl[2]);
const bool ng=(vl*dot(a,cross(b-c,a-b)))<=0;
if(ng&&(btFabs(vl)>GJK_SIMPLEX4_EPS))
{
btScalar mindist=-1;
btScalar subw[3];
U subm;
for(U i=0;i<3;++i)
{
const U j=imd3[i];
const btScalar s=vl*dot(d,cross(dl[i],dl[j]));
if(s>0)
{
const btScalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm);
if((mindist<0)||(subd<mindist))
{
mindist = subd;
m = (subm&1?1<<i:0)+
(subm&2?1<<j:0)+
(subm&4?8:0);
w[i] = subw[0];
w[j] = subw[1];
w[imd3[j]] = 0;
w[3] = subw[2];
}
}
}
if(mindist<0)
{
mindist = 0;
m = 15;
w[0] = det(c,b,d)/vl;
w[1] = det(a,c,d)/vl;
w[2] = det(b,a,d)/vl;
w[3] = 1-(w[0]+w[1]+w[2]);
}
return(mindist);
}
return(-1);
}
};
// EPA
struct EPA
{
/* Types */
typedef GJK::sSV sSV;
struct sFace
{
btVector3 n;
btScalar d;
btScalar p;
sSV* c[3];
sFace* f[3];
sFace* l[2];
U1 e[3];
U1 pass;
};
struct sList
{
sFace* root;
U count;
sList() : root(0),count(0) {}
};
struct sHorizon
{
sFace* cf;
sFace* ff;
U nf;
sHorizon() : cf(0),ff(0),nf(0) {}
};
struct eStatus { enum _ {
Valid,
Touching,
Degenerated,
NonConvex,
InvalidHull,
OutOfFaces,
OutOfVertices,
AccuraryReached,
FallBack,
Failed, };};
/* Fields */
eStatus::_ m_status;
GJK::sSimplex m_result;
btVector3 m_normal;
btScalar m_depth;
sSV m_sv_store[EPA_MAX_VERTICES];
sFace m_fc_store[EPA_MAX_FACES];
U m_nextsv;
sList m_hull;
sList m_stock;
/* Methods */
EPA()
{
Initialize();
}
void Initialize()
{
m_status = eStatus::Failed;
m_normal = btVector3(0,0,0);
m_depth = 0;
m_nextsv = 0;
for(U i=0;i<EPA_MAX_FACES;++i)
{
append(m_stock,&m_fc_store[EPA_MAX_FACES-i-1]);
}
}
eStatus::_ Evaluate(GJK& gjk,const btVector3& guess)
{
GJK::sSimplex& simplex=*gjk.m_simplex;
if((simplex.rank>1)&&gjk.EncloseOrigin())
{
/* Clean up */
while(m_hull.root)
{
sFace* f(m_hull.root);
remove(m_hull,f);
append(m_stock,f);
}
m_status = eStatus::Valid;
m_nextsv = 0;
/* Orient simplex */
if(gjk.det( simplex.c[0]->w-simplex.c[3]->w,
simplex.c[1]->w-simplex.c[3]->w,
simplex.c[2]->w-simplex.c[3]->w)<0)
{
btSwap(simplex.c[0],simplex.c[1]);
btSwap(simplex.p[0],simplex.p[1]);
}
/* Build initial hull */
sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true),
newface(simplex.c[1],simplex.c[0],simplex.c[3],true),
newface(simplex.c[2],simplex.c[1],simplex.c[3],true),
newface(simplex.c[0],simplex.c[2],simplex.c[3],true)};
if(m_hull.count==4)
{
sFace* best=findbest();
sFace outer=*best;
U pass=0;
U iterations=0;
bind(tetra[0],0,tetra[1],0);
bind(tetra[0],1,tetra[2],0);
bind(tetra[0],2,tetra[3],0);
bind(tetra[1],1,tetra[3],2);
bind(tetra[1],2,tetra[2],1);
bind(tetra[2],2,tetra[3],1);
m_status=eStatus::Valid;
for(;iterations<EPA_MAX_ITERATIONS;++iterations)
{
if(m_nextsv<EPA_MAX_VERTICES)
{
sHorizon horizon;
sSV* w=&m_sv_store[m_nextsv++];
bool valid=true;
best->pass = (U1)(++pass);
gjk.getsupport(best->n,*w);
const btScalar wdist=dot(best->n,w->w)-best->d;
if(wdist>EPA_ACCURACY)
{
for(U j=0;(j<3)&&valid;++j)
{
valid&=expand( pass,w,
best->f[j],best->e[j],
horizon);
}
if(valid&&(horizon.nf>=3))
{
bind(horizon.cf,1,horizon.ff,2);
remove(m_hull,best);
append(m_stock,best);
best=findbest();
if(best->p>=outer.p) outer=*best;
} else { m_status=eStatus::InvalidHull;break; }
} else { m_status=eStatus::AccuraryReached;break; }
} else { m_status=eStatus::OutOfVertices;break; }
}
const btVector3 projection=outer.n*outer.d;
m_normal = outer.n;
m_depth = outer.d;
m_result.rank = 3;
m_result.c[0] = outer.c[0];
m_result.c[1] = outer.c[1];
m_result.c[2] = outer.c[2];
m_result.p[0] = cross( outer.c[1]->w-projection,
outer.c[2]->w-projection).length();
m_result.p[1] = cross( outer.c[2]->w-projection,
outer.c[0]->w-projection).length();
m_result.p[2] = cross( outer.c[0]->w-projection,
outer.c[1]->w-projection).length();
const btScalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2];
m_result.p[0] /= sum;
m_result.p[1] /= sum;
m_result.p[2] /= sum;
return(m_status);
}
}
/* Fallback */
m_status = eStatus::FallBack;
m_normal = -guess;
const btScalar nl=m_normal.length();
if(nl>0)
m_normal = m_normal/nl;
else
m_normal = btVector3(1,0,0);
m_depth = 0;
m_result.rank=1;
m_result.c[0]=simplex.c[0];
m_result.p[0]=1;
return(m_status);
}
sFace* newface(sSV* a,sSV* b,sSV* c,bool forced)
{
if(m_stock.root)
{
sFace* face=m_stock.root;
remove(m_stock,face);
append(m_hull,face);
face->pass = 0;
face->c[0] = a;
face->c[1] = b;
face->c[2] = c;
face->n = cross(b->w-a->w,c->w-a->w);
const btScalar l=face->n.length();
const bool v=l>EPA_ACCURACY;
face->p = btMin(btMin(
dot(a->w,cross(face->n,a->w-b->w)),
dot(b->w,cross(face->n,b->w-c->w))),
dot(c->w,cross(face->n,c->w-a->w))) /
(v?l:1);
face->p = face->p>=-EPA_INSIDE_EPS?0:face->p;
if(v)
{
face->d = dot(a->w,face->n)/l;
face->n /= l;
if(forced||(face->d>=-EPA_PLANE_EPS))
{
return(face);
} else m_status=eStatus::NonConvex;
} else m_status=eStatus::Degenerated;
remove(m_hull,face);
append(m_stock,face);
return(0);
}
m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces;
return(0);
}
sFace* findbest()
{
sFace* minf=m_hull.root;
btScalar mind=minf->d*minf->d;
btScalar maxp=minf->p;
for(sFace* f=minf->l[1];f;f=f->l[1])
{
const btScalar sqd=f->d*f->d;
if((f->p>=maxp)&&(sqd<mind))
{
minf=f;
mind=sqd;
maxp=f->p;
}
}
return(minf);
}
bool expand(U pass,sSV* w,sFace* f,U e,sHorizon& horizon)
{
static const U i1m3[]={1,2,0};
static const U i2m3[]={2,0,1};
if(f->pass!=pass)
{
const U e1=i1m3[e];
if((dot(f->n,w->w)-f->d)<-EPA_PLANE_EPS)
{
sFace* nf=newface(f->c[e1],f->c[e],w,false);
if(nf)
{
bind(nf,0,f,e);
if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf;
horizon.cf=nf;
++horizon.nf;
return(true);
}
}
else
{
const U e2=i2m3[e];
f->pass = (U1)pass;
if( expand(pass,w,f->f[e1],f->e[e1],horizon)&&
expand(pass,w,f->f[e2],f->e[e2],horizon))
{
remove(m_hull,f);
append(m_stock,f);
return(true);
}
}
}
return(false);
}
static inline void bind(sFace* fa,U ea,sFace* fb,U eb)
{
fa->e[ea]=(U1)eb;fa->f[ea]=fb;
fb->e[eb]=(U1)ea;fb->f[eb]=fa;
}
static inline void append(sList& list,sFace* face)
{
face->l[0] = 0;
face->l[1] = list.root;
if(list.root) list.root->l[0]=face;
list.root = face;
++list.count;
}
static inline void remove(sList& list,sFace* face)
{
if(face->l[1]) face->l[1]->l[0]=face->l[0];
if(face->l[0]) face->l[0]->l[1]=face->l[1];
if(face==list.root) list.root=face->l[1];
--list.count;
}
};
//
static void Initialize( const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
btGjkEpaSolver2::sResults& results,
tShape& shape,
bool withmargins)
{
/* Results */
results.witnesses[0] =
results.witnesses[1] = btVector3(0,0,0);
results.status = btGjkEpaSolver2::sResults::Separated;
/* Shape */
shape.m_shapes[0] = shape0;
shape.m_shapes[1] = shape1;
shape.m_toshape1 = wtrs1.getBasis().transposeTimes(wtrs0.getBasis());
shape.m_toshape0 = wtrs0.inverseTimes(wtrs1);
shape.EnableMargin(withmargins);
}
}
//
// Api
//
using namespace gjkepa2_impl;
//
int btGjkEpaSolver2::StackSizeRequirement()
{
return(sizeof(GJK)+sizeof(EPA));
}
//
btScalar btGjkEpaSolver2::Distance( const btConvexShape* shape0,
const btTransform& wtrs0,
const btConvexShape* shape1,
const btTransform& wtrs1,
sResults& results)
{
tShape shape;
Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,btVector3(1,1,1));
if(gjk_status==GJK::eStatus::Valid)
{
btVector3 w0=btVector3(0,0,0);
btVector3 w1=btVector3(0,0,0);
for(U i=0;i<gjk.m_simplex->rank;++i)
{
const btScalar p=gjk.m_simplex->p[i];
w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
}
results.witnesses[0] = wtrs0*w0;
results.witnesses[1] = wtrs0*w1;
return((w0-w1).length());
}
else
{
results.status = gjk_status==GJK::eStatus::Inside?
sResults::Penetrating :
sResults::GJK_Failed ;
return(-1);
}
}
//
btScalar btGjkEpaSolver2::SignedDistance(const btVector3& position,
btScalar margin,
const btConvexShape* shape0,
const btTransform& wtrs0,
sResults& results)
{
tShape shape;
btSphereShape shape1(margin);
btTransform wtrs1(btQuaternion(0,0,0,1),position);
Initialize(shape0,wtrs0,&shape1,wtrs1,results,shape,false);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,btVector3(1,1,1));
if(gjk_status==GJK::eStatus::Valid)
{
btVector3 w0=btVector3(0,0,0);
btVector3 w1=btVector3(0,0,0);
for(U i=0;i<gjk.m_simplex->rank;++i)
{
const btScalar p=gjk.m_simplex->p[i];
w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p;
w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p;
}
results.witnesses[0] = wtrs0*w0;
results.witnesses[1] = wtrs0*w1;
const btVector3 delta= results.witnesses[1]-
results.witnesses[0];
const btScalar margin= shape0->getMargin()+
shape1.getMargin();
const btScalar length= delta.length();
results.normal = delta/length;
results.witnesses[0] += results.normal*margin;
return(length-margin);
}
else
{
if(gjk_status==GJK::eStatus::Inside)
{
if(Penetration(shape0,wtrs0,&shape1,wtrs1,gjk.m_ray,results))
{
const btVector3 delta= results.witnesses[0]-
results.witnesses[1];
const btScalar length= delta.length();
results.normal = delta/length;
return(-length);
}
}
}
return(SIMD_INFINITY);
}
//
bool btGjkEpaSolver2::Penetration( const btConvexShape* shape0,
const btTransform& wtrs0,
const btConvexShape* shape1,
const btTransform& wtrs1,
const btVector3& guess,
sResults& results)
{
tShape shape;
Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,true);
GJK gjk;
GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess);
switch(gjk_status)
{
case GJK::eStatus::Inside:
{
EPA epa;
EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess);
if(epa_status!=EPA::eStatus::Failed)
{
btVector3 w0=btVector3(0,0,0);
for(U i=0;i<epa.m_result.rank;++i)
{
w0+=shape.Support(epa.m_result.c[i]->d,0)*epa.m_result.p[i];
}
results.status = sResults::Penetrating;
results.witnesses[0] = wtrs0*w0;
results.witnesses[1] = wtrs0*(w0-epa.m_normal*epa.m_depth);
return(true);
} else results.status=sResults::EPA_Failed;
}
break;
case GJK::eStatus::Failed:
results.status=sResults::GJK_Failed;
break;
}
return(false);
}
/* Symbols cleanup */
#undef GJK_MAX_ITERATIONS
#undef GJK_ACCURARY
#undef GJK_MIN_DISTANCE
#undef GJK_DUPLICATED_EPS
#undef GJK_SIMPLEX2_EPS
#undef GJK_SIMPLEX3_EPS
#undef GJK_SIMPLEX4_EPS
#undef EPA_MAX_VERTICES
#undef EPA_MAX_FACES
#undef EPA_MAX_ITERATIONS
#undef EPA_ACCURACY
#undef EPA_FALLBACK
#undef EPA_PLANE_EPS
#undef EPA_INSIDE_EPS

View File

@ -0,0 +1,39 @@
#ifndef _68DA1F85_90B7_4bb0_A705_83B4040A75C6_
#define _68DA1F85_90B7_4bb0_A705_83B4040A75C6_
#include "BulletCollision/CollisionShapes/btConvexShape.h"
///btGjkEpaSolver contributed under zlib by Nathanael Presson
struct btGjkEpaSolver2
{
struct sResults
{
enum eStatus
{
Separated, /* Shapes doesnt penetrate */
Penetrating, /* Shapes are penetrating */
GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */
EPA_Failed, /* EPA phase fail, bigger problem, need to save parameters, and debug */
} status;
btVector3 witnesses[2];
btVector3 normal;
};
static int StackSizeRequirement();
static btScalar Distance( const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
sResults& results);
static btScalar SignedDistance( const btVector3& position,
btScalar margin,
const btConvexShape* shape,
const btTransform& wtrs,
sResults& results);
static bool Penetration(const btConvexShape* shape0,const btTransform& wtrs0,
const btConvexShape* shape1,const btTransform& wtrs1,
const btVector3& guess,
sResults& results);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,356 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btSoftBody implementation by Nathanael Presson
#ifndef _312AEEF3_52DA_4ff6_B804_FCF937182E46_
#define _312AEEF3_52DA_4ff6_B804_FCF937182E46_
#include "LinearMath/btAlignedObjectArray.h"
#include "LinearMath/btPoint3.h"
#include "LinearMath/btTransform.h"
#include "LinearMath/btIDebugDraw.h"
#include "BulletDynamics/Dynamics/btRigidBody.h"
//
// btSoftBody
//
struct btSoftBody
{
//
// Enumerations
//
/* eLType */
struct eLType { enum _ {
Structural, /* Master constraints */
Bending, /* Secondary constraints */
};};
/* eAeroModel */
struct eAeroModel { enum _ {
V_Point, /* Vertex normals are oriented toward velocity */
V_TwoSided, /* Vertex normals are fliped to match velocity */
V_OneSided, /* Vertex normals are taken as it is */
F_TwoSided, /* Face normals are fliped to match velocity */
F_OneSided, /* Face normals are taken as it is */
};};
//
// Interfaces
//
/* ISoftBody */
struct ISoftBody
{
struct sCti
{
btRigidBody* m_body; /* Rigid body */
btVector3 m_normal; /* Outward normal */
btScalar m_offset; /* Offset from origin */
};
struct sMedium
{
btVector3 m_velocity; /* Velocity */
btScalar m_pressure; /* Pressure */
btScalar m_density; /* Density */
};
virtual void Attach(btSoftBody*)
{}
virtual void Detach(btSoftBody*)
{ delete this; }
virtual void StartCollide( const btVector3& /*minbounds*/,
const btVector3& /*maxbounds*/)
{}
virtual bool CheckContact (const btVector3& /*position*/,
sCti& /*contact*/)
{ return(false); }
virtual void EndCollide()
{}
virtual void EvaluateMedium( const btVector3& /*position*/,
sMedium& medium)
{ medium.m_velocity=btVector3(0,0,0);
medium.m_pressure=0;
medium.m_density=0; }
};
//
// Internal types
//
typedef btAlignedObjectArray<btScalar> tScalarArray;
typedef btAlignedObjectArray<btVector3> tVector3Array;
/* Base type */
struct Element
{
void* m_tag; // User data
};
/* Node */
struct Node : Element
{
btVector3 m_x; // Position
btVector3 m_q; // Previous step position
btVector3 m_v; // Velocity
btVector3 m_f; // Force accumulator
btVector3 m_n; // Normal
btScalar m_im; // 1/mass
btScalar m_area; // Area
int m_battach:1; // Attached
};
/* Link */
struct Link : Element
{
Node* m_n[2]; // Node pointers
btScalar m_rl; // Rest length
btScalar m_kST; // Stiffness coefficient
btScalar m_c0; // (ima+imb)*kLST
btScalar m_c1; // rl^2
eLType::_ m_type; // Link type
};
/* Face */
struct Face : Element
{
Node* m_n[3]; // Node pointers
btVector3 m_normal; // Normal
btScalar m_ra; // Rest area
};
/* Contact */
struct Contact
{
ISoftBody::sCti m_cti; // Contact infos
Node* m_node; // Owner node
btMatrix3x3 m_c0; // Impulse matrix
btVector3 m_c1; // Relative anchor
btScalar m_c2; // ima*dt
btScalar m_c3; // Friction
};
/* Anchor */
struct Anchor
{
Node* m_node; // Node pointer
btVector3 m_local; // Anchor position in body space
btRigidBody* m_body; // Body
btMatrix3x3 m_c0; // Impulse matrix
btVector3 m_c1; // Relative anchor
btScalar m_c2; // ima*dt
};
/* Pose */
struct Pose
{
bool m_bvolume; // Is valid
bool m_bframe; // Is frame
btScalar m_volume; // Rest volume
tVector3Array m_pos; // Reference positions
tScalarArray m_wgh; // Weights
btVector3 m_com; // COM
btMatrix3x3 m_trs; // Transform
};
/* Config */
struct Config
{
eAeroModel::_ aeromodel; // Aerodynamic model (default: V_Point)
btScalar kLST; // Linear stiffness coefficient [0,1]
btScalar kDP; // Damping coefficient [0,1]
btScalar kDG; // Drag coefficient [0,+inf]
btScalar kLF; // Lift coefficient [0,+inf]
btScalar kPR; // Pressure coefficient [-inf,+inf]
btScalar kVC; // Volume conversation coefficient [0,+inf]
btScalar kDF; // Dynamic friction coefficient [0,1]
btScalar kMT; // Pose matching coefficient [0,1]
btScalar kSOR; // SOR(w) [1,2] default 1, never use with solver!=Accurate
btScalar kCHR; // Contacts hardness [0,1]
btScalar kAHR; // Anchors hardness [0,1]
btScalar timescale; // Time scale
btScalar timestep; // Time step
int maxsteps; // Maximum time steps
int iterations; // Solver iterations
bool becollide; // Enable external collisions
bool bscollide; // Enable self collisions
};
//
// Typedef's
//
typedef btAlignedObjectArray<Node> tNodeArray;
typedef btAlignedObjectArray<Link> tLinkArray;
typedef btAlignedObjectArray<Face> tFaceArray;
typedef btAlignedObjectArray<Anchor> tAnchorArray;
typedef btAlignedObjectArray<Contact> tContactArray;
//
// Fields
//
Config m_cfg; // Configuration
Pose m_pose; // Pose
ISoftBody* m_isb; // ISoftBody
void* m_tag; // User data
tNodeArray m_nodes; // Nodes
tLinkArray m_links; // Links
tFaceArray m_faces; // Faces
tAnchorArray m_anchors; // Anchors
tContactArray m_contacts; // Contacts
btScalar m_timeacc; // Time accumulator
btVector3 m_bounds[2]; // Spatial bounds
bool m_bUpdateRtCst; // Update runtime constants
//
// Api
//
/* Create a soft body */
static btSoftBody* Create( ISoftBody* isoftbody,
int node_count,
const btVector3* x=0,
const btScalar* m=0);
/* Delete a body */
void Delete();
/* Check for existing link */
bool CheckLink( int node0,
int node1) const;
bool CheckLink( const btSoftBody::Node* node0,
const btSoftBody::Node* node1) const;
/* Check for existring face */
bool CheckFace( int node0,
int node1,
int node2) const;
/* Append link */
void AppendLink( int node0,
int node1,
btScalar kST,
btSoftBody::eLType::_ type,
bool bcheckexist=false);
void AppendLink( btSoftBody::Node* node0,
btSoftBody::Node* node1,
btScalar kST,
btSoftBody::eLType::_ type,
bool bcheckexist=false);
/* Append face */
void AppendFace( int node0,
int node1,
int node2);
/* Append anchor */
void AppendAnchor( int node,
btRigidBody* body);
/* Add force (or gravity) to the entire body */
void AddForce( const btVector3& force);
/* Add force (or gravity) to a node of the body */
void AddForce( const btVector3& force,
int node);
/* Add velocity to the entire body */
void AddVelocity( const btVector3& velocity);
/* Add velocity to a node of the body */
void AddVelocity( const btVector3& velocity,
int node);
/* Set mass */
void SetMass( int node,
btScalar mass);
/* Get mass */
btScalar GetMass( int node) const;
/* Get total mass */
btScalar GetTotalMass() const;
/* Set total mass (weighted by previous masses) */
void SetTotalMass( btScalar mass,
bool fromfaces=false);
/* Set total density */
void SetTotalDensity(btScalar density);
/* Transform */
void Transform( const btTransform& trs);
/* Scale */
void Scale( const btVector3& scl);
/* Set current state as pose */
void SetPose( bool bvolume,
bool bframe);
/* Return the volume */
btScalar GetVolume() const;
/* Generate bending constraints based on distance in the adjency graph */
int GenerateBendingConstraints( int distance,
btScalar stiffness);
/* Randomize constraints to reduce solver bias */
void RandomizeConstraints();
/* Ray casting */
btScalar Raycast( const btVector3& org,
const btVector3& dir) const;
/* Step */
void Step( btScalar dt);
};
//
// Helpers
//
/* fDrawFlags */
struct fDrawFlags { enum _ {
Nodes = 0x0001,
SLinks = 0x0002,
BLinks = 0x0004,
Faces = 0x0008,
Tetras = 0x0010,
Normals = 0x0020,
Contacts = 0x0040,
Anchors = 0x0080,
/* presets */
Links = SLinks+BLinks,
Std = SLinks+Faces+Anchors,
StdTetra = Std-Faces+Tetras,
};};
/* Draw body */
void Draw( btSoftBody* psb,
btIDebugDraw* idraw,
int drawflags=fDrawFlags::Std);
/* Draw body infos */
void DrawInfos( btSoftBody* psb,
btIDebugDraw* idraw,
bool masses,
bool areas,
bool stress);
/* Draw rigid frame */
void DrawFrame( btSoftBody* psb,
btIDebugDraw* idraw);
/* Create a rope */
btSoftBody* CreateRope( btSoftBody::ISoftBody* isoftbody,
const btVector3& from,
const btVector3& to,
int res,
int fixeds);
/* Create a patch */
btSoftBody* CreatePatch( btSoftBody::ISoftBody* isoftbody,
const btVector3& corner00,
const btVector3& corner10,
const btVector3& corner01,
const btVector3& corner11,
int resx,
int resy,
int fixeds,
bool gendiags);
/* Create an ellipsoid */
btSoftBody* CreateEllipsoid(btSoftBody::ISoftBody* isoftbody,
const btVector3& center,
const btVector3& radius,
int res);
/* Create from convex-hull */
btSoftBody* CreateFromConvexHull( btSoftBody::ISoftBody* isoftbody,
const btVector3* vertices,
int nvertices);
/* Create from trimesh */
btSoftBody* CreateFromTriMesh( btSoftBody::ISoftBody* isoftbody,
const btScalar* vertices,
const int* triangles,
int ntriangles);
#endif

View File

@ -0,0 +1,429 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btSoftBodyHelpers.cpp by Nathanael Presson
#include "btSoftBody.h"
#include "Extras/ConvexHull/btConvexHull.h"
#include <stdio.h>
#include <string.h>
namespace btsoftbody_internals
{
//
static void drawVertex( btIDebugDraw* idraw,
const btVector3& x,btScalar s,const btVector3& c)
{
idraw->drawLine(x-btVector3(s,0,0),x+btVector3(s,0,0),c);
idraw->drawLine(x-btVector3(0,s,0),x+btVector3(0,s,0),c);
idraw->drawLine(x-btVector3(0,0,s),x+btVector3(0,0,s),c);
}
//
static btVector3 stresscolor(btScalar stress)
{
static const btVector3 spectrum[]= {
btVector3(1,0,1),
btVector3(0,0,1),
btVector3(0,1,1),
btVector3(0,1,0),
btVector3(1,1,0),
btVector3(1,0,0),
btVector3(1,0,0),
};
static const int ncolors=sizeof(spectrum)/sizeof(spectrum[0])-1;
static const btScalar one=1;
stress=btMax<btScalar>(0,btMin<btScalar>(1,stress))*ncolors;
const int sel=(int)stress;
const btScalar frc=stress-sel;
return(spectrum[sel]+(spectrum[sel+1]-spectrum[sel])*frc);
}
}
using namespace btsoftbody_internals;
//
void Draw( btSoftBody* psb,
btIDebugDraw* idraw,
int drawflags)
{
const btScalar scl=(btScalar)0.1;
const btScalar nscl=scl*5;
const btScalar alpha=(btScalar)0.5;
const btVector3 scolor=btVector3(0,0,0);
const btVector3 bcolor=btVector3(1,1,0);
const btVector3 ncolor=btVector3(1,1,1);
const btVector3 ccolor=btVector3(1,0,0);
/* Nodes */
if(0!=(drawflags&fDrawFlags::Nodes))
{
for(int i=0;i<psb->m_nodes.size();++i)
{
const btSoftBody::Node& n=psb->m_nodes[i];
idraw->drawLine(n.m_x-btVector3(scl,0,0),n.m_x+btVector3(scl,0,0),btVector3(1,0,0));
idraw->drawLine(n.m_x-btVector3(0,scl,0),n.m_x+btVector3(0,scl,0),btVector3(0,1,0));
idraw->drawLine(n.m_x-btVector3(0,0,scl),n.m_x+btVector3(0,0,scl),btVector3(0,0,1));
}
}
/* Links */
if(0!=(drawflags&fDrawFlags::Links))
{
for(int i=0;i<psb->m_links.size();++i)
{
const btSoftBody::Link& l=psb->m_links[i];
switch(l.m_type)
{
case btSoftBody::eLType::Structural:
if(0!=(drawflags&fDrawFlags::SLinks)) idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,scolor);break;
case btSoftBody::eLType::Bending:
if(0!=(drawflags&fDrawFlags::BLinks)) idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,bcolor);break;
}
}
}
/* Normals */
if(0!=(drawflags&fDrawFlags::Normals))
{
for(int i=0;i<psb->m_nodes.size();++i)
{
const btSoftBody::Node& n=psb->m_nodes[i];
const btVector3 d=n.m_n*nscl;
idraw->drawLine(n.m_x,n.m_x+d,ncolor);
idraw->drawLine(n.m_x,n.m_x-d,ncolor*0.5);
}
}
/* Contacts */
if(0!=(drawflags&fDrawFlags::Contacts))
{
static const btVector3 axis[]={btVector3(1,0,0),
btVector3(0,1,0),
btVector3(0,0,1)};
for(int i=0;i<psb->m_contacts.size();++i)
{
const btSoftBody::Contact& c=psb->m_contacts[i];
const btVector3 o= c.m_node->m_x-c.m_cti.m_normal*
(dot(c.m_node->m_x,c.m_cti.m_normal)+c.m_cti.m_offset);
const btVector3 x=cross(c.m_cti.m_normal,axis[c.m_cti.m_normal.minAxis()]).normalized();
const btVector3 y=cross(x,c.m_cti.m_normal).normalized();
idraw->drawLine(o-x*nscl,o+x*nscl,ccolor);
idraw->drawLine(o-y*nscl,o+y*nscl,ccolor);
idraw->drawLine(o,o+c.m_cti.m_normal*nscl*3,btVector3(1,1,0));
}
}
/* Anchors */
if(0!=(drawflags&fDrawFlags::Anchors))
{
for(int i=0;i<psb->m_anchors.size();++i)
{
const btSoftBody::Anchor& a=psb->m_anchors[i];
const btVector3 q=a.m_body->getWorldTransform()*a.m_local;
drawVertex(idraw,a.m_node->m_x,0.25,btVector3(1,0,0));
drawVertex(idraw,q,0.25,btVector3(0,1,0));
idraw->drawLine(a.m_node->m_x,q,btVector3(1,1,1));
}
for(int i=0;i<psb->m_nodes.size();++i)
{
const btSoftBody::Node& n=psb->m_nodes[i];
if(n.m_im<=0)
{
drawVertex(idraw,n.m_x,0.25,btVector3(1,0,0));
}
}
}
/* Faces */
if(0!=(drawflags&fDrawFlags::Faces))
{
const btScalar scl=(btScalar)0.7;
const btScalar alp=(btScalar)1;
const btVector3 col(0,(btScalar)0.7,0);
for(int i=0;i<psb->m_faces.size();++i)
{
const btSoftBody::Face& f=psb->m_faces[i];
const btVector3 x[]={f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x};
const btVector3 c=(x[0]+x[1]+x[2])/3;
idraw->drawTriangle((x[0]-c)*scl+c,
(x[1]-c)*scl+c,
(x[2]-c)*scl+c,
f.m_n[0]->m_n,f.m_n[1]->m_n,f.m_n[2]->m_n,
col,alp);
}
}
}
//
void DrawInfos( btSoftBody* psb,
btIDebugDraw* idraw,
bool masses,
bool areas,
bool stress)
{
for(int i=0;i<psb->m_nodes.size();++i)
{
const btSoftBody::Node& n=psb->m_nodes[i];
char text[2048]={0};
char buff[1024];
if(masses)
{
sprintf(buff," M(%.2f)",1/n.m_im);
strcat(text,buff);
}
if(areas)
{
sprintf(buff," A(%.2f)",n.m_area);
strcat(text,buff);
}
if(text[0]) idraw->draw3dText(n.m_x,text);
}
}
//
void DrawFrame( btSoftBody* psb,
btIDebugDraw* idraw)
{
if(psb->m_pose.m_bframe)
{
static const btScalar ascl=10;
static const btScalar nscl=(btScalar)0.1;
const btVector3 com=psb->m_pose.m_com;
const btMatrix3x3& trs=psb->m_pose.m_trs;
const btVector3 Xaxis=(trs*btVector3(1,0,0)).normalized();
const btVector3 Yaxis=(trs*btVector3(0,1,0)).normalized();
const btVector3 Zaxis=(trs*btVector3(0,0,1)).normalized();
idraw->drawLine(com,com+Xaxis*ascl,btVector3(1,0,0));
idraw->drawLine(com,com+Yaxis*ascl,btVector3(0,1,0));
idraw->drawLine(com,com+Zaxis*ascl,btVector3(0,0,1));
for(int i=0;i<psb->m_pose.m_pos.size();++i)
{
const btVector3 x=com+trs*psb->m_pose.m_pos[i];
idraw->drawLine(x-btVector3(1,0,0)*nscl,x+btVector3(1,0,0)*nscl,btVector3(1,0,1));
idraw->drawLine(x-btVector3(0,1,0)*nscl,x+btVector3(0,1,0)*nscl,btVector3(1,0,1));
idraw->drawLine(x-btVector3(0,0,1)*nscl,x+btVector3(0,0,1)*nscl,btVector3(1,0,1));
}
}
}
//
btSoftBody* CreateRope( btSoftBody::ISoftBody* isoftbody,
const btVector3& from,
const btVector3& to,
int res,
int fixeds)
{
/* Create nodes */
const int r=res+2;
btVector3* x=new btVector3[r];
btScalar* m=new btScalar[r];
for(int i=0;i<r;++i)
{
const btScalar t=i/(btScalar)(r-1);
x[i]=lerp(from,to,t);
m[i]=1;
}
btSoftBody* psb=btSoftBody::Create(isoftbody,r,x,m);
if(fixeds&1) psb->SetMass(0,0);
if(fixeds&2) psb->SetMass(r-1,0);
delete[] x;
delete[] m;
/* Create links */
for(int i=1;i<r;++i)
{
psb->AppendLink(i-1,i,1,btSoftBody::eLType::Structural);
}
/* Finished */
return(psb);
}
//
btSoftBody* CreatePatch( btSoftBody::ISoftBody* isoftbody,
const btVector3& corner00,
const btVector3& corner10,
const btVector3& corner01,
const btVector3& corner11,
int resx,
int resy,
int fixeds,
bool gendiags)
{
#define IDX(_x_,_y_) ((_y_)*rx+(_x_))
/* Create nodes */
if((resx<2)||(resy<2)) return(0);
const int rx=resx;
const int ry=resy;
const int tot=rx*ry;
btVector3* x=new btVector3[tot];
btScalar* m=new btScalar[tot];
for(int iy=0;iy<ry;++iy)
{
const btScalar ty=iy/(btScalar)(ry-1);
const btVector3 py0=lerp(corner00,corner01,ty);
const btVector3 py1=lerp(corner10,corner11,ty);
for(int ix=0;ix<rx;++ix)
{
const btScalar tx=ix/(btScalar)(rx-1);
x[IDX(ix,iy)]=lerp(py0,py1,tx);
m[IDX(ix,iy)]=1;
}
}
btSoftBody* psb=btSoftBody::Create(isoftbody,tot,x,m);
if(fixeds&1) psb->SetMass(IDX(0,0),0);
if(fixeds&2) psb->SetMass(IDX(rx-1,0),0);
if(fixeds&4) psb->SetMass(IDX(0,ry-1),0);
if(fixeds&8) psb->SetMass(IDX(rx-1,ry-1),0);
delete[] x;
delete[] m;
/* Create links and faces */
for(int iy=0;iy<ry;++iy)
{
for(int ix=0;ix<rx;++ix)
{
const int idx=IDX(ix,iy);
const bool mdx=(ix+1)<rx;
const bool mdy=(iy+1)<ry;
if(mdx) psb->AppendLink(idx,IDX(ix+1,iy),
1,btSoftBody::eLType::Structural);
if(mdy) psb->AppendLink(idx,IDX(ix,iy+1),
1,btSoftBody::eLType::Structural);
if(mdx&&mdy)
{
if((ix+iy)&1)
{
psb->AppendFace(IDX(ix,iy),IDX(ix+1,iy),IDX(ix+1,iy+1));
psb->AppendFace(IDX(ix,iy),IDX(ix+1,iy+1),IDX(ix,iy+1));
if(gendiags)
{
psb->AppendLink(IDX(ix,iy),IDX(ix+1,iy+1),
1,btSoftBody::eLType::Structural);
}
}
else
{
psb->AppendFace(IDX(ix,iy+1),IDX(ix,iy),IDX(ix+1,iy));
psb->AppendFace(IDX(ix,iy+1),IDX(ix+1,iy),IDX(ix+1,iy+1));
if(gendiags)
{
psb->AppendLink(IDX(ix+1,iy),IDX(ix,iy+1),
1,btSoftBody::eLType::Structural);
}
}
}
}
}
/* Finished */
#undef IDX
return(psb);
}
//
btSoftBody* CreateEllipsoid(btSoftBody::ISoftBody* isoftbody,
const btVector3& center,
const btVector3& radius,
int res)
{
struct Hammersley
{
static void Generate(btVector3* x,int n)
{
for(int i=0;i<n;i++)
{
btScalar p=0.5,t=0;
for(int j=i;j;p*=0.5,j>>=1) if(j&1) t+=p;
btScalar w=2*t-1;
btScalar a=(SIMD_PI+2*i*SIMD_PI)/n;
btScalar s=btSqrt(1-w*w);
*x++=btVector3(s*btCos(a),s*btSin(a),w);
}
}
};
btAlignedObjectArray<btVector3> vtx;
vtx.resize(3+res);
Hammersley::Generate(&vtx[0],vtx.size());
for(int i=0;i<vtx.size();++i)
{
vtx[i]=vtx[i]*radius+center;
}
return(CreateFromConvexHull(isoftbody,&vtx[0],vtx.size()));
}
//
btSoftBody* CreateFromConvexHull( btSoftBody::ISoftBody* isoftbody,
const btVector3* vertices,
int nvertices)
{
HullDesc hdsc(QF_TRIANGLES,nvertices,vertices);
HullResult hres;
HullLibrary hlib;/*??*/
hdsc.mMaxVertices=nvertices;
hlib.CreateConvexHull(hdsc,hres);
btSoftBody* psb=btSoftBody::Create( isoftbody,
(int)hres.mNumOutputVertices,
hres.mOutputVertices,0);
for(int i=0;i<(int)hres.mNumFaces;++i)
{
const int idx[]={ hres.mIndices[i*3+0],
hres.mIndices[i*3+1],
hres.mIndices[i*3+2]};
if(idx[0]<idx[1]) psb->AppendLink( idx[0],idx[1],
1,btSoftBody::eLType::Structural);
if(idx[1]<idx[2]) psb->AppendLink( idx[1],idx[2],
1,btSoftBody::eLType::Structural);
if(idx[2]<idx[0]) psb->AppendLink( idx[2],idx[0],
1,btSoftBody::eLType::Structural);
psb->AppendFace(idx[0],idx[1],idx[2]);
}
hlib.ReleaseResult(hres);
psb->RandomizeConstraints();
return(psb);
}
//
btSoftBody* CreateFromTriMesh( btSoftBody::ISoftBody* isoftbody,
const btScalar* vertices,
const int* triangles,
int ntriangles)
{
int maxidx=0;
for(int i=0,ni=ntriangles*3;i<ni;++i)
{
maxidx=btMax(triangles[i],maxidx);
}
++maxidx;
btAlignedObjectArray<bool> chks;
btAlignedObjectArray<btVector3> vtx;
chks.resize(maxidx*maxidx,false);
vtx.resize(maxidx);
for(int i=0,j=0,ni=maxidx*3;i<ni;++j,i+=3)
{
vtx[j]=btVector3(vertices[i],vertices[i+1],vertices[i+2]);
}
btSoftBody* psb=btSoftBody::Create(isoftbody,vtx.size(),&vtx[0],0);
for(int i=0,ni=ntriangles*3;i<ni;i+=3)
{
const int idx[]={triangles[i],triangles[i+1],triangles[i+2]};
#define IDX(_x_,_y_) ((_y_)*maxidx+(_x_))
for(int j=2,k=0;k<3;j=k++)
{
if(!chks[IDX(idx[j],idx[k])])
{
chks[IDX(idx[j],idx[k])]=true;
chks[IDX(idx[k],idx[k])]=true;
psb->AppendLink(idx[j],idx[k],1,btSoftBody::eLType::Structural);
}
}
#undef IDX
psb->AppendFace(idx[0],idx[1],idx[2]);
}
psb->RandomizeConstraints();
return(psb);
}

View File

@ -0,0 +1,313 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
///btSparseSdf implementation by Nathanael Presson
#ifndef _14F9D17F_EAE8_4aba_B41C_292DB2AA70F3_
#define _14F9D17F_EAE8_4aba_B41C_292DB2AA70F3_
template <const int CELLSIZE>
struct btSparseSdf
{
//
// Inner types
//
struct IntFrac
{
int b;
int i;
btScalar f;
};
struct Client
{
btCollisionShape* shape;
btVector3 center;
btVector3 extent;
btScalar vsize;
int id;
};
struct Cell
{
btScalar d[CELLSIZE+1][CELLSIZE+1][CELLSIZE+1];
int c[3];
int puid;
unsigned hash;
const Client* pclient;
Cell* next;
};
//
// Fields
//
btAlignedObjectArray<Cell*> cells;
btAlignedObjectArray<Client*> clients;
int puid;
int ncells;
int nprobes;
int nqueries;
//
// Methods
//
//
void Initialize(int hashsize=2383)
{
cells.resize(hashsize,0);
Reset();
}
//
void Reset()
{
for(int i=0,ni=cells.size();i<ni;++i)
{
Cell* pc=cells[i];
cells[i]=0;
while(pc)
{
Cell* pn=pc->next;
delete pc;
pc=pn;
}
}
puid =0;
ncells =0;
nprobes =1;
nqueries =1;
}
//
void GarbageCollect(int lifetime=64)
{
const int life=puid-lifetime;
for(int i=0;i<cells.size();++i)
{
Cell*& root=cells[i];
Cell* pp=0;
Cell* pc=root;
while(pc)
{
Cell* pn=pc->next;
if(pc->puid<life)
{
if(pp) pp->next=pn; else root=pn;
delete pc;pc=pp;--ncells;
}
pp=pc;pc=pn;
}
}
//printf("GC[%d]: %d cells, PpQ: %f\r\n",puid,ncells,nprobes/(btScalar)nqueries);
nqueries=1;
nprobes=1;
++puid; /* TODO: Reset puid's when int range limit is reached */
/* else setup a priority list... */
}
//
Client* GetClient( btCollisionShape* shape)
{
Client* pc=(Client*)shape->getUserPointer();
if(!pc)
{
pc=new Client();
clients.push_back(pc);
shape->setUserPointer(pc);
pc->shape = shape;
pc->id = clients.size();
pc->vsize = 0.25;
SetShapeBounds(*pc);
}
return(pc);
}
//
btScalar Evaluate( const btVector3& x,
btCollisionShape* shape,
btVector3& normal)
{
const Client* pclient=GetClient(shape);
/* Bounds check */
const btVector3 offset=x-pclient->center;
const btVector3 sqoffset=offset*offset;
if( (sqoffset.x()>pclient->extent.x()) ||
(sqoffset.y()>pclient->extent.y()) ||
(sqoffset.z()>pclient->extent.z())) return(SIMD_INFINITY);
/* Lookup cell */
const btVector3 scx=x/pclient->vsize;
const IntFrac ix=Decompose(scx.x());
const IntFrac iy=Decompose(scx.y());
const IntFrac iz=Decompose(scx.z());
const unsigned h=Hash(ix.b,iy.b,iz.b,pclient->id);
Cell*& root=cells[h%cells.size()];
Cell* c=root;
++nqueries;
while(c)
{
++nprobes;
if( (c->hash==h) &&
(c->c[0]==ix.b) &&
(c->c[1]==iy.b) &&
(c->c[2]==iz.b) &&
(c->pclient==pclient))
{ break; }
else
{ c=c->next; }
}
if(!c)
{
++nprobes;
++ncells;
c=new Cell();
c->next=root;root=c;
c->pclient=pclient;c->hash=h;
c->c[0]=ix.b;c->c[1]=iy.b;c->c[2]=iz.b;
BuildCell(*c);
}
c->puid=puid;
/* Extract infos */
const int o[]={ ix.i,iy.i,iz.i};
const btScalar d[]={ c->d[o[0]+0][o[1]+0][o[2]+0],
c->d[o[0]+1][o[1]+0][o[2]+0],
c->d[o[0]+1][o[1]+1][o[2]+0],
c->d[o[0]+0][o[1]+1][o[2]+0],
c->d[o[0]+0][o[1]+0][o[2]+1],
c->d[o[0]+1][o[1]+0][o[2]+1],
c->d[o[0]+1][o[1]+1][o[2]+1],
c->d[o[0]+0][o[1]+1][o[2]+1]};
/* Normal */
#if 1
const btScalar gx[]={ d[1]-d[0],d[2]-d[3],
d[5]-d[4],d[6]-d[7]};
const btScalar gy[]={ d[3]-d[0],d[2]-d[1],
d[7]-d[4],d[6]-d[5]};
const btScalar gz[]={ d[4]-d[0],d[5]-d[1],
d[7]-d[3],d[6]-d[2]};
normal.setX(Lerp( Lerp(gx[0],gx[1],iy.f),
Lerp(gx[2],gx[3],iy.f),iz.f));
normal.setY(Lerp( Lerp(gy[0],gy[1],ix.f),
Lerp(gy[2],gy[3],ix.f),iz.f));
normal.setZ(Lerp( Lerp(gz[0],gz[1],ix.f),
Lerp(gz[2],gz[3],ix.f),iy.f));
normal = normal.normalized();
#else
normal = btVector3(d[1]-d[0],d[3]-d[0],d[4]-d[0]).normalized();
#endif
/* Distance */
const btScalar d0=Lerp(Lerp(d[0],d[1],ix.f),
Lerp(d[3],d[2],ix.f),iy.f);
const btScalar d1=Lerp(Lerp(d[4],d[5],ix.f),
Lerp(d[7],d[6],ix.f),iy.f);
return(Lerp(d0,d1,iz.f));
}
//
void BuildCell(Cell& c)
{
const Client* client=c.pclient;
const btVector3 org=btVector3(c.c[0],c.c[1],c.c[2])*CELLSIZE*client->vsize;
for(int k=0;k<=CELLSIZE;++k)
{
const btScalar z=client->vsize*k+org.z();
for(int j=0;j<=CELLSIZE;++j)
{
const btScalar y=client->vsize*j+org.y();
for(int i=0;i<=CELLSIZE;++i)
{
const btScalar x=client->vsize*i+org.x();
c.d[i][j][k]=DistanceToShape( btVector3(x,y,z),
client->shape,
client->vsize);
}
}
}
}
//
static inline btScalar DistanceToShape(const btVector3& x,
btCollisionShape* shape,
btScalar margin)
{
btTransform unit;
unit.setIdentity();
if(shape->isConvex())
{
btGjkEpaSolver2::sResults res;
btConvexShape* csh=static_cast<btConvexShape*>(shape);
return(btGjkEpaSolver2::SignedDistance(x,margin,csh,unit,res));
}
return(0);
}
//
static inline void SetShapeBounds(Client& c)
{
if(c.shape->isConvex())
{
btConvexShape* csh=static_cast<btConvexShape*>(c.shape);
const btVector3 x[]={ csh->localGetSupportingVertex(btVector3(+1,0,0)),
csh->localGetSupportingVertex(btVector3(-1,0,0))};
const btVector3 y[]={ csh->localGetSupportingVertex(btVector3(0,+1,0)),
csh->localGetSupportingVertex(btVector3(0,-1,0))};
const btVector3 z[]={ csh->localGetSupportingVertex(btVector3(0,0,+1)),
csh->localGetSupportingVertex(btVector3(0,0,-1))};
c.center = btVector3( x[0].x()+x[1].x(),
y[0].y()+y[1].y(),
z[0].z()+z[1].z())*0.5;
c.extent = btVector3( x[0].x()-x[1].x(),
y[0].y()-y[1].y(),
z[0].z()-z[1].z())*0.5;
c.extent += btVector3(c.vsize,c.vsize,c.vsize);
c.extent *= c.extent;
}
}
//
static inline IntFrac Decompose(btScalar x)
{
/* That one need a lot of improvements... */
/* Remove test, faster floor... */
IntFrac r;
x/=CELLSIZE;
const int o=x<0?(int)(-x+1):0;
x+=o;r.b=(int)x;
const btScalar k=(x-r.b)*CELLSIZE;
r.i=(int)k;r.f=k-r.i;r.b-=o;
return(r);
}
//
static inline btScalar Lerp(btScalar a,btScalar b,btScalar t)
{
return(a+(b-a)*t);
}
//
static inline unsigned Hash(int x,int y,int z,int i)
{
const int data[]={x,y,z,i};
return(HsiehHash<sizeof(data)/4>(data));
}
// Modified Paul Hsieh hash
template <const int DWORDLEN>
static inline unsigned HsiehHash(const void* pdata)
{
const unsigned short* data=(const unsigned short*)pdata;
unsigned hash=DWORDLEN<<2,tmp;
for(int i=0;i<DWORDLEN;++i)
{
hash += data[0];
tmp = (data[1]<<11)^hash;
hash = (hash<<16)^tmp;
data += 2;
hash += hash>>11;
}
hash^=hash<<3;hash+=hash>>5;
hash^=hash<<4;hash+=hash>>17;
hash^=hash<<25;hash+=hash>>6;
return(hash);
}
};
#endif

View File

@ -56,6 +56,17 @@ class btIDebugDraw
virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)=0; virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)=0;
virtual void drawTriangle(const btVector3& v0,const btVector3& v1,const btVector3& v2,const btVector3& n0,const btVector3& n1,const btVector3& n2,const btVector3& color, btScalar alpha)
{
drawTriangle(v0,v1,v2,color,alpha);
}
virtual void drawTriangle(const btVector3& v0,const btVector3& v1,const btVector3& v2,const btVector3& color, btScalar alpha)
{
drawLine(v0,v1,color);
drawLine(v1,v2,color);
drawLine(v2,v0,color);
}
virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)=0; virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)=0;
virtual void reportErrorWarning(const char* warningString) = 0; virtual void reportErrorWarning(const char* warningString) = 0;