Add the old Bullet 2.x obsolete demos, and CMake buildsystem files, and gradually move them to newer Bullet 3.x structure
Use statically linked freeglut, instead of dynamic glut for the obsolete Bullet 2.x demos Add the 'reset' method to b3GpuDynamicsWorld, and use it in the BasicGpuDemo (pretty slow in debug mode, use release mode) Don't crash in btCollisionWorld, if there is no collision dispatcher
This commit is contained in:
81
ObsoleteDemos/FractureDemo/CMakeLists.txt
Normal file
81
ObsoleteDemos/FractureDemo/CMakeLists.txt
Normal file
@@ -0,0 +1,81 @@
|
||||
# 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
|
||||
########################################################
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${BULLET_PHYSICS_SOURCE_DIR}/src
|
||||
../OpenGL
|
||||
)
|
||||
|
||||
|
||||
|
||||
IF (USE_GLUT)
|
||||
LINK_LIBRARIES(
|
||||
OpenGLSupport BulletDynamics BulletCollision LinearMath ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}
|
||||
)
|
||||
|
||||
IF (WIN32)
|
||||
ADD_EXECUTABLE(AppFractureDemo
|
||||
main.cpp
|
||||
FractureDemo.cpp
|
||||
FractureDemo.h
|
||||
btFractureBody.h
|
||||
btFractureBody.cpp
|
||||
btFractureDynamicsWorld.cpp
|
||||
btFractureDynamicsWorld.h
|
||||
${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc
|
||||
)
|
||||
ELSE()
|
||||
ADD_EXECUTABLE(AppFractureDemo
|
||||
main.cpp
|
||||
FractureDemo.cpp
|
||||
FractureDemo.h
|
||||
btFractureBody.h
|
||||
btFractureBody.cpp
|
||||
btFractureDynamicsWorld.cpp
|
||||
btFractureDynamicsWorld.h
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
||||
|
||||
|
||||
ELSE (USE_GLUT)
|
||||
|
||||
|
||||
|
||||
LINK_LIBRARIES(
|
||||
OpenGLSupport BulletDynamics BulletCollision LinearMath ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}
|
||||
)
|
||||
|
||||
|
||||
ADD_EXECUTABLE(AppFractureDemo
|
||||
WIN32
|
||||
../OpenGL/Win32AppMain.cpp
|
||||
Win32FractureDemo.cpp
|
||||
FractureDemo.cpp
|
||||
FractureDemo.h
|
||||
btFractureBody.h
|
||||
btFractureBody.cpp
|
||||
btFractureDynamicsWorld.cpp
|
||||
btFractureDynamicsWorld.h
|
||||
${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc
|
||||
)
|
||||
|
||||
|
||||
ENDIF (USE_GLUT)
|
||||
|
||||
IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES)
|
||||
SET_TARGET_PROPERTIES(AppFractureDemo PROPERTIES DEBUG_POSTFIX "_Debug")
|
||||
SET_TARGET_PROPERTIES(AppFractureDemo PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel")
|
||||
SET_TARGET_PROPERTIES(AppFractureDemo PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo")
|
||||
ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES)
|
||||
362
ObsoleteDemos/FractureDemo/FractureDemo.cpp
Normal file
362
ObsoleteDemos/FractureDemo/FractureDemo.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2011 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.
|
||||
*/
|
||||
|
||||
|
||||
///FractureDemo shows how to break objects.
|
||||
///It assumes a btCompoundShaps (where the childshapes are the pre-fractured pieces)
|
||||
///The btFractureBody is a class derived from btRigidBody, dealing with the collision impacts.
|
||||
///Press the F key to toggle between fracture and glue mode
|
||||
///This is preliminary work
|
||||
|
||||
|
||||
#define CUBE_HALF_EXTENTS 1.f
|
||||
#define EXTRA_HEIGHT 1.f
|
||||
///scaling of the objects (0.1 = 20 centimeter boxes )
|
||||
#define SCALING 1.
|
||||
#define START_POS_X -5
|
||||
#define START_POS_Y -5
|
||||
#define START_POS_Z -3
|
||||
|
||||
#include "FractureDemo.h"
|
||||
#include "GlutStuff.h"
|
||||
#include "GLDebugFont.h"
|
||||
///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
|
||||
|
||||
#include <stdio.h> //printf debugging
|
||||
|
||||
|
||||
int sFrameNumber = 0;
|
||||
|
||||
#include "btFractureBody.h"
|
||||
#include "btFractureDynamicsWorld.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void FractureDemo::initPhysics()
|
||||
{
|
||||
|
||||
setTexturing(true);
|
||||
setShadows(true);
|
||||
|
||||
setDebugMode(btIDebugDraw::DBG_DrawText|btIDebugDraw::DBG_NoHelpText);
|
||||
|
||||
setCameraDistance(btScalar(SCALING*20.));
|
||||
|
||||
///collision configuration contains default setup for memory, collision setup
|
||||
m_collisionConfiguration = new btDefaultCollisionConfiguration();
|
||||
//m_collisionConfiguration->setConvexConvexMultipointIterations();
|
||||
|
||||
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
|
||||
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
|
||||
|
||||
m_broadphase = new btDbvtBroadphase();
|
||||
|
||||
///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
|
||||
btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
|
||||
m_solver = sol;
|
||||
|
||||
//m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
|
||||
|
||||
btFractureDynamicsWorld* fractureWorld = new btFractureDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
|
||||
m_dynamicsWorld = fractureWorld;
|
||||
|
||||
m_ShootBoxInitialSpeed=100;
|
||||
|
||||
//m_splitImpulse removes the penetration resolution from the applied impulse, otherwise objects might fracture due to deep penetrations.
|
||||
m_dynamicsWorld->getSolverInfo().m_splitImpulse = true;
|
||||
|
||||
{
|
||||
///create a few basic rigid bodies
|
||||
btCollisionShape* groundShape = new btBoxShape(btVector3(50,1,50));
|
||||
/// btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),0);
|
||||
m_collisionShapes.push_back(groundShape);
|
||||
btTransform groundTransform;
|
||||
groundTransform.setIdentity();
|
||||
groundTransform.setOrigin(btVector3(0,0,0));
|
||||
localCreateRigidBody(0.f,groundTransform,groundShape);
|
||||
}
|
||||
|
||||
{
|
||||
///create a few basic rigid bodies
|
||||
btCollisionShape* shape = new btBoxShape(btVector3(1,1,1));
|
||||
m_collisionShapes.push_back(shape);
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
tr.setOrigin(btVector3(5,2,0));
|
||||
localCreateRigidBody(0.f,tr,shape);
|
||||
}
|
||||
|
||||
|
||||
|
||||
{
|
||||
//create a few dynamic rigidbodies
|
||||
// Re-using the same collision is better for memory usage and performance
|
||||
|
||||
btCollisionShape* colShape = new btBoxShape(btVector3(SCALING*1,SCALING*1,SCALING*1));
|
||||
//btCollisionShape* colShape = new btCapsuleShape(SCALING*0.4,SCALING*1);
|
||||
//btCollisionShape* colShape = new btSphereShape(btScalar(1.));
|
||||
m_collisionShapes.push_back(colShape);
|
||||
|
||||
/// Create Dynamic Objects
|
||||
btTransform startTransform;
|
||||
startTransform.setIdentity();
|
||||
|
||||
btScalar mass(1.f);
|
||||
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.f);
|
||||
|
||||
btVector3 localInertia(0,0,0);
|
||||
if (isDynamic)
|
||||
colShape->calculateLocalInertia(mass,localInertia);
|
||||
|
||||
|
||||
int gNumObjects = 10;
|
||||
|
||||
for (int i=0;i<gNumObjects;i++)
|
||||
{
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
|
||||
btVector3 pos(i*2*CUBE_HALF_EXTENTS ,20,0);
|
||||
trans.setOrigin(pos);
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(trans);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
|
||||
btFractureBody* body = new btFractureBody(rbInfo, m_dynamicsWorld);
|
||||
body->setLinearVelocity(btVector3(0,-10,0));
|
||||
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
fractureWorld->stepSimulation(1./60.,0);
|
||||
fractureWorld->glueCallback();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void FractureDemo::clientResetScene()
|
||||
{
|
||||
exitPhysics();
|
||||
initPhysics();
|
||||
}
|
||||
|
||||
|
||||
void FractureDemo::clientMoveAndDisplay()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
//simple dynamics world doesn't handle fixed-time-stepping
|
||||
float ms = getDeltaTimeMicroseconds();
|
||||
|
||||
///step the simulation
|
||||
if (m_dynamicsWorld)
|
||||
{
|
||||
m_dynamicsWorld->stepSimulation(ms / 1000000.f);
|
||||
//optional but useful: debug drawing
|
||||
m_dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
|
||||
|
||||
|
||||
renderme();
|
||||
|
||||
showMessage();
|
||||
|
||||
glFlush();
|
||||
|
||||
swapBuffers();
|
||||
|
||||
}
|
||||
|
||||
void FractureDemo::showMessage()
|
||||
{
|
||||
if((getDebugMode() & btIDebugDraw::DBG_DrawText))
|
||||
{
|
||||
setOrthographicProjection();
|
||||
glDisable(GL_LIGHTING);
|
||||
glColor3f(0, 0, 0);
|
||||
char buf[124];
|
||||
|
||||
int lineWidth=380;
|
||||
int xStart = m_glutScreenWidth - lineWidth;
|
||||
int yStart = 20;
|
||||
|
||||
btFractureDynamicsWorld* world = (btFractureDynamicsWorld*)m_dynamicsWorld;
|
||||
if (world->getFractureMode())
|
||||
{
|
||||
sprintf(buf,"Fracture mode");
|
||||
} else
|
||||
{
|
||||
sprintf(buf,"Glue mode");
|
||||
}
|
||||
GLDebugDrawString(xStart,yStart,buf);
|
||||
sprintf(buf,"f to toggle fracture/glue mode");
|
||||
yStart+=20;
|
||||
GLDebugDrawString(xStart,yStart,buf);
|
||||
sprintf(buf,"space to restart, mouse to pick/shoot");
|
||||
yStart+=20;
|
||||
GLDebugDrawString(xStart,yStart,buf);
|
||||
|
||||
resetPerspectiveProjection();
|
||||
glEnable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FractureDemo::displayCallback(void) {
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
renderme();
|
||||
|
||||
showMessage();
|
||||
|
||||
//optional but useful: debug drawing to detect problems
|
||||
if (m_dynamicsWorld)
|
||||
m_dynamicsWorld->debugDrawWorld();
|
||||
|
||||
glFlush();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
|
||||
void FractureDemo::keyboardUpCallback(unsigned char key, int x, int y)
|
||||
{
|
||||
if (key=='f')
|
||||
{
|
||||
btFractureDynamicsWorld* world = (btFractureDynamicsWorld*)m_dynamicsWorld;
|
||||
world->setFractureMode(!world->getFractureMode());
|
||||
}
|
||||
|
||||
PlatformDemoApplication::keyboardUpCallback(key,x,y);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void FractureDemo::shootBox(const btVector3& destination)
|
||||
{
|
||||
|
||||
if (m_dynamicsWorld)
|
||||
{
|
||||
btScalar mass = 1.f;
|
||||
btTransform startTransform;
|
||||
startTransform.setIdentity();
|
||||
btVector3 camPos = getCameraPosition();
|
||||
startTransform.setOrigin(camPos);
|
||||
|
||||
setShootBoxShape ();
|
||||
|
||||
btAssert((!m_shootBoxShape || m_shootBoxShape->getShapeType() != INVALID_SHAPE_PROXYTYPE));
|
||||
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.f);
|
||||
|
||||
btVector3 localInertia(0,0,0);
|
||||
if (isDynamic)
|
||||
m_shootBoxShape->calculateLocalInertia(mass,localInertia);
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
|
||||
btFractureBody* body = new btFractureBody(mass,0,m_shootBoxShape,localInertia,&mass,1,m_dynamicsWorld);
|
||||
|
||||
body->setWorldTransform(startTransform);
|
||||
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
|
||||
|
||||
body->setLinearFactor(btVector3(1,1,1));
|
||||
//body->setRestitution(1);
|
||||
|
||||
btVector3 linVel(destination[0]-camPos[0],destination[1]-camPos[1],destination[2]-camPos[2]);
|
||||
linVel.normalize();
|
||||
linVel*=m_ShootBoxInitialSpeed;
|
||||
|
||||
body->getWorldTransform().setOrigin(camPos);
|
||||
body->getWorldTransform().setRotation(btQuaternion(0,0,0,1));
|
||||
body->setLinearVelocity(linVel);
|
||||
body->setAngularVelocity(btVector3(0,0,0));
|
||||
body->setCcdMotionThreshold(1.);
|
||||
body->setCcdSweptSphereRadius(0.2f);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void FractureDemo::exitPhysics()
|
||||
{
|
||||
|
||||
//cleanup in the reverse order of creation/initialization
|
||||
|
||||
//remove the rigidbodies from the dynamics world and delete them
|
||||
int i;
|
||||
for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
|
||||
{
|
||||
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
|
||||
btRigidBody* body = btRigidBody::upcast(obj);
|
||||
if (body && body->getMotionState())
|
||||
{
|
||||
delete body->getMotionState();
|
||||
}
|
||||
m_dynamicsWorld->removeCollisionObject( obj );
|
||||
delete obj;
|
||||
}
|
||||
|
||||
//delete collision shapes
|
||||
for (int j=0;j<m_collisionShapes.size();j++)
|
||||
{
|
||||
btCollisionShape* shape = m_collisionShapes[j];
|
||||
delete shape;
|
||||
}
|
||||
|
||||
m_collisionShapes.clear();
|
||||
|
||||
delete m_dynamicsWorld;
|
||||
m_dynamicsWorld=0;
|
||||
|
||||
delete m_solver;
|
||||
m_solver=0;
|
||||
|
||||
delete m_broadphase;
|
||||
m_broadphase=0;
|
||||
|
||||
delete m_dispatcher;
|
||||
m_dispatcher=0;
|
||||
|
||||
delete m_collisionConfiguration;
|
||||
m_collisionConfiguration=0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
87
ObsoleteDemos/FractureDemo/FractureDemo.h
Normal file
87
ObsoleteDemos/FractureDemo/FractureDemo.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
#ifndef FRACTURE_DEMO_H
|
||||
#define FRACTURE_DEMO_H
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include "Win32DemoApplication.h"
|
||||
#define PlatformDemoApplication Win32DemoApplication
|
||||
#else
|
||||
#include "GlutDemoApplication.h"
|
||||
#define PlatformDemoApplication GlutDemoApplication
|
||||
#endif
|
||||
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
|
||||
class btBroadphaseInterface;
|
||||
class btCollisionShape;
|
||||
class btOverlappingPairCache;
|
||||
class btCollisionDispatcher;
|
||||
class btConstraintSolver;
|
||||
struct btCollisionAlgorithmCreateFunc;
|
||||
class btDefaultCollisionConfiguration;
|
||||
|
||||
///FractureDemo shows basic breaking and glueing of objects
|
||||
class FractureDemo : public PlatformDemoApplication
|
||||
{
|
||||
|
||||
//keep the collision shapes, for deletion/cleanup
|
||||
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
|
||||
|
||||
btBroadphaseInterface* m_broadphase;
|
||||
|
||||
btCollisionDispatcher* m_dispatcher;
|
||||
|
||||
btConstraintSolver* m_solver;
|
||||
|
||||
btDefaultCollisionConfiguration* m_collisionConfiguration;
|
||||
|
||||
void showMessage();
|
||||
|
||||
public:
|
||||
|
||||
FractureDemo()
|
||||
{
|
||||
}
|
||||
virtual ~FractureDemo()
|
||||
{
|
||||
exitPhysics();
|
||||
}
|
||||
void initPhysics();
|
||||
|
||||
void exitPhysics();
|
||||
|
||||
virtual void clientMoveAndDisplay();
|
||||
|
||||
virtual void displayCallback();
|
||||
|
||||
virtual void keyboardUpCallback(unsigned char key, int x, int y);
|
||||
|
||||
virtual void clientResetScene();
|
||||
|
||||
static DemoApplication* Create()
|
||||
{
|
||||
FractureDemo* demo = new FractureDemo;
|
||||
demo->myinit();
|
||||
demo->initPhysics();
|
||||
return demo;
|
||||
}
|
||||
|
||||
void shootBox(const btVector3& destination);
|
||||
|
||||
};
|
||||
|
||||
#endif //FRACTURE_DEMO_H
|
||||
|
||||
25
ObsoleteDemos/FractureDemo/Win32FractureDemo.cpp
Normal file
25
ObsoleteDemos/FractureDemo/Win32FractureDemo.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifdef _WINDOWS
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2011 Erwin Coumans http://bulletphysics.org
|
||||
|
||||
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 "FractureDemo.h"
|
||||
|
||||
///The 'createDemo' function is called from Bullet/Demos/OpenGL/Win32AppMain.cpp to instantiate this particular demo
|
||||
DemoApplication* createDemo()
|
||||
{
|
||||
return new FractureDemo();
|
||||
}
|
||||
|
||||
#endif
|
||||
139
ObsoleteDemos/FractureDemo/btFractureBody.cpp
Normal file
139
ObsoleteDemos/FractureDemo/btFractureBody.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
#include "btFractureBody.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
|
||||
#include "BulletCollision/CollisionShapes/btCompoundShape.h"
|
||||
#include "BulletDynamics/Dynamics/btDynamicsWorld.h"
|
||||
|
||||
|
||||
|
||||
void btFractureBody::recomputeConnectivity(btCollisionWorld* world)
|
||||
{
|
||||
m_connections.clear();
|
||||
//@todo use the AABB tree to avoid N^2 checks
|
||||
|
||||
if (getCollisionShape()->isCompound())
|
||||
{
|
||||
btCompoundShape* compound = (btCompoundShape*)getCollisionShape();
|
||||
for (int i=0;i<compound->getNumChildShapes();i++)
|
||||
{
|
||||
for (int j=i+1;j<compound->getNumChildShapes();j++)
|
||||
{
|
||||
|
||||
struct MyContactResultCallback : public btCollisionWorld::ContactResultCallback
|
||||
{
|
||||
bool m_connected;
|
||||
btScalar m_margin;
|
||||
MyContactResultCallback() :m_connected(false),m_margin(0.05)
|
||||
{
|
||||
}
|
||||
virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1)
|
||||
{
|
||||
if (cp.getDistance()<=m_margin)
|
||||
m_connected = true;
|
||||
return 1.f;
|
||||
}
|
||||
};
|
||||
|
||||
MyContactResultCallback result;
|
||||
|
||||
btCollisionObject obA;
|
||||
obA.setWorldTransform(compound->getChildTransform(i));
|
||||
obA.setCollisionShape(compound->getChildShape(i));
|
||||
btCollisionObject obB;
|
||||
obB.setWorldTransform(compound->getChildTransform(j));
|
||||
obB.setCollisionShape(compound->getChildShape(j));
|
||||
world->contactPairTest(&obA,&obB,result);
|
||||
if (result.m_connected)
|
||||
{
|
||||
btConnection tmp;
|
||||
tmp.m_childIndex0 = i;
|
||||
tmp.m_childIndex1 = j;
|
||||
tmp.m_childShape0 = compound->getChildShape(i);
|
||||
tmp.m_childShape1 = compound->getChildShape(j);
|
||||
tmp.m_strength = 1.f;//??
|
||||
m_connections.push_back(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
btCompoundShape* btFractureBody::shiftTransformDistributeMass(btCompoundShape* boxCompound,btScalar mass,btTransform& shift)
|
||||
{
|
||||
|
||||
btVector3 principalInertia;
|
||||
|
||||
btScalar* masses = new btScalar[boxCompound->getNumChildShapes()];
|
||||
for (int j=0;j<boxCompound->getNumChildShapes();j++)
|
||||
{
|
||||
//evenly distribute mass
|
||||
masses[j]=mass/boxCompound->getNumChildShapes();
|
||||
}
|
||||
|
||||
return shiftTransform(boxCompound,masses,shift,principalInertia);
|
||||
|
||||
}
|
||||
|
||||
|
||||
btCompoundShape* btFractureBody::shiftTransform(btCompoundShape* boxCompound,btScalar* masses,btTransform& shift, btVector3& principalInertia)
|
||||
{
|
||||
btTransform principal;
|
||||
|
||||
boxCompound->calculatePrincipalAxisTransform(masses,principal,principalInertia);
|
||||
|
||||
|
||||
///create a new compound with world transform/center of mass properly aligned with the principal axis
|
||||
|
||||
///non-recursive compound shapes perform better
|
||||
|
||||
#ifdef USE_RECURSIVE_COMPOUND
|
||||
|
||||
btCompoundShape* newCompound = new btCompoundShape();
|
||||
newCompound->addChildShape(principal.inverse(),boxCompound);
|
||||
newBoxCompound = newCompound;
|
||||
//m_collisionShapes.push_back(newCompound);
|
||||
|
||||
//btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||
//btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,newCompound,principalInertia);
|
||||
|
||||
#else
|
||||
#ifdef CHANGE_COMPOUND_INPLACE
|
||||
newBoxCompound = boxCompound;
|
||||
for (int i=0;i<boxCompound->getNumChildShapes();i++)
|
||||
{
|
||||
btTransform newChildTransform = principal.inverse()*boxCompound->getChildTransform(i);
|
||||
///updateChildTransform is really slow, because it re-calculates the AABB each time. todo: add option to disable this update
|
||||
boxCompound->updateChildTransform(i,newChildTransform);
|
||||
}
|
||||
bool isDynamic = (mass != 0.f);
|
||||
btVector3 localInertia(0,0,0);
|
||||
if (isDynamic)
|
||||
boxCompound->calculateLocalInertia(mass,localInertia);
|
||||
|
||||
#else
|
||||
///creation is faster using a new compound to store the shifted children
|
||||
btCompoundShape* newBoxCompound = new btCompoundShape();
|
||||
for (int i=0;i<boxCompound->getNumChildShapes();i++)
|
||||
{
|
||||
btTransform newChildTransform = principal.inverse()*boxCompound->getChildTransform(i);
|
||||
///updateChildTransform is really slow, because it re-calculates the AABB each time. todo: add option to disable this update
|
||||
newBoxCompound->addChildShape(newChildTransform,boxCompound->getChildShape(i));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#endif//USE_RECURSIVE_COMPOUND
|
||||
|
||||
shift = principal;
|
||||
return newBoxCompound;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
78
ObsoleteDemos/FractureDemo/btFractureBody.h
Normal file
78
ObsoleteDemos/FractureDemo/btFractureBody.h
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
#ifndef BT_FRACTURE_BODY
|
||||
#define BT_FRACTURE_BODY
|
||||
|
||||
class btCollisionShape;
|
||||
class btDynamicsWorld;
|
||||
class btCollisionWorld;
|
||||
class btCompoundShape;
|
||||
class btManifoldPoint;
|
||||
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "BulletDynamics/Dynamics/btRigidBody.h"
|
||||
|
||||
#define CUSTOM_FRACTURE_TYPE (btRigidBody::CO_USER_TYPE+1)
|
||||
|
||||
|
||||
struct btConnection
|
||||
{
|
||||
|
||||
btCollisionShape* m_childShape0;
|
||||
btCollisionShape* m_childShape1;
|
||||
int m_childIndex0;
|
||||
int m_childIndex1;
|
||||
btScalar m_strength;
|
||||
};
|
||||
|
||||
class btFractureBody : public btRigidBody
|
||||
{
|
||||
//connections
|
||||
public:
|
||||
|
||||
btDynamicsWorld* m_world;
|
||||
btAlignedObjectArray<btScalar> m_masses;
|
||||
btAlignedObjectArray<btConnection> m_connections;
|
||||
|
||||
|
||||
|
||||
btFractureBody( const btRigidBodyConstructionInfo& constructionInfo, btDynamicsWorld* world)
|
||||
:btRigidBody(constructionInfo),
|
||||
m_world(world)
|
||||
{
|
||||
m_masses.push_back(constructionInfo.m_mass);
|
||||
m_internalType=CUSTOM_FRACTURE_TYPE+CO_RIGID_BODY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///btRigidBody constructor for backwards compatibility.
|
||||
///To specify friction (etc) during rigid body construction, please use the other constructor (using btRigidBodyConstructionInfo)
|
||||
btFractureBody( btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia, btScalar* masses, int numMasses, btDynamicsWorld* world)
|
||||
:btRigidBody(mass,motionState,collisionShape,localInertia),
|
||||
m_world(world)
|
||||
{
|
||||
|
||||
for (int i=0;i<numMasses;i++)
|
||||
m_masses.push_back(masses[i]);
|
||||
|
||||
m_internalType=CUSTOM_FRACTURE_TYPE+CO_RIGID_BODY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void recomputeConnectivity(btCollisionWorld* world);
|
||||
|
||||
|
||||
static btCompoundShape* shiftTransform(btCompoundShape* boxCompound,btScalar* masses,btTransform& shift, btVector3& principalInertia);
|
||||
|
||||
static btCompoundShape* shiftTransformDistributeMass(btCompoundShape* boxCompound,btScalar mass,btTransform& shift);
|
||||
|
||||
static bool collisionCallback(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1);
|
||||
|
||||
};
|
||||
|
||||
|
||||
void fractureCallback(btDynamicsWorld* world, btScalar timeStep);
|
||||
void glueCallback(btDynamicsWorld* world, btScalar timeStep);
|
||||
|
||||
#endif //BT_FRACTURE_BODY
|
||||
688
ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.cpp
Normal file
688
ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.cpp
Normal file
@@ -0,0 +1,688 @@
|
||||
|
||||
#include "btFractureDynamicsWorld.h"
|
||||
#include "btFractureBody.h"
|
||||
#include "BulletCollision/CollisionShapes/btCompoundShape.h"
|
||||
|
||||
#include "BulletCollision/CollisionDispatch/btUnionFind.h"
|
||||
|
||||
btFractureDynamicsWorld::btFractureDynamicsWorld ( btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration)
|
||||
:btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration),
|
||||
m_fracturingMode(true)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void btFractureDynamicsWorld::glueCallback()
|
||||
{
|
||||
|
||||
int numManifolds = getDispatcher()->getNumManifolds();
|
||||
|
||||
///first build the islands based on axis aligned bounding box overlap
|
||||
|
||||
btUnionFind unionFind;
|
||||
|
||||
int index = 0;
|
||||
{
|
||||
|
||||
int i;
|
||||
for (i=0;i<getCollisionObjectArray().size(); i++)
|
||||
{
|
||||
btCollisionObject* collisionObject= getCollisionObjectArray()[i];
|
||||
// btRigidBody* body = btRigidBody::upcast(collisionObject);
|
||||
//Adding filtering here
|
||||
#ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
|
||||
if (!collisionObject->isStaticOrKinematicObject())
|
||||
{
|
||||
collisionObject->setIslandTag(index++);
|
||||
} else
|
||||
{
|
||||
collisionObject->setIslandTag(-1);
|
||||
}
|
||||
#else
|
||||
collisionObject->setIslandTag(i);
|
||||
index=i+1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
unionFind.reset(index);
|
||||
|
||||
int numElem = unionFind.getNumElements();
|
||||
|
||||
for (int i=0;i<numManifolds;i++)
|
||||
{
|
||||
btPersistentManifold* manifold = getDispatcher()->getManifoldByIndexInternal(i);
|
||||
if (!manifold->getNumContacts())
|
||||
continue;
|
||||
|
||||
btScalar minDist = 1e30f;
|
||||
for (int v=0;v<manifold->getNumContacts();v++)
|
||||
{
|
||||
minDist = btMin(minDist,manifold->getContactPoint(v).getDistance());
|
||||
}
|
||||
if (minDist>0.)
|
||||
continue;
|
||||
|
||||
btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0();
|
||||
btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1();
|
||||
int tag0 = (colObj0)->getIslandTag();
|
||||
int tag1 = (colObj1)->getIslandTag();
|
||||
//btRigidBody* body0 = btRigidBody::upcast(colObj0);
|
||||
//btRigidBody* body1 = btRigidBody::upcast(colObj1);
|
||||
|
||||
|
||||
if (!colObj0->isStaticOrKinematicObject() && !colObj1->isStaticOrKinematicObject())
|
||||
{
|
||||
unionFind.unite(tag0, tag1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
numElem = unionFind.getNumElements();
|
||||
|
||||
|
||||
|
||||
index=0;
|
||||
for (int ai=0;ai<getCollisionObjectArray().size();ai++)
|
||||
{
|
||||
btCollisionObject* collisionObject= getCollisionObjectArray()[ai];
|
||||
if (!collisionObject->isStaticOrKinematicObject())
|
||||
{
|
||||
int tag = unionFind.find(index);
|
||||
|
||||
collisionObject->setIslandTag( tag);
|
||||
|
||||
//Set the correct object offset in Collision Object Array
|
||||
#if STATIC_SIMULATION_ISLAND_OPTIMIZATION
|
||||
unionFind.getElement(index).m_sz = ai;
|
||||
#endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
unionFind.sortIslands();
|
||||
|
||||
|
||||
|
||||
int endIslandIndex=1;
|
||||
int startIslandIndex;
|
||||
|
||||
btAlignedObjectArray<btCollisionObject*> removedObjects;
|
||||
|
||||
///iterate over all islands
|
||||
for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
|
||||
{
|
||||
int islandId = unionFind.getElement(startIslandIndex).m_id;
|
||||
for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (unionFind.getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
|
||||
{
|
||||
}
|
||||
|
||||
int fractureObjectIndex = -1;
|
||||
|
||||
int numObjects=0;
|
||||
|
||||
int idx;
|
||||
for (idx=startIslandIndex;idx<endIslandIndex;idx++)
|
||||
{
|
||||
int i = unionFind.getElement(idx).m_sz;
|
||||
btCollisionObject* colObj0 = getCollisionObjectArray()[i];
|
||||
if (colObj0->getInternalType()& CUSTOM_FRACTURE_TYPE)
|
||||
{
|
||||
fractureObjectIndex = i;
|
||||
}
|
||||
btRigidBody* otherObject = btRigidBody::upcast(colObj0);
|
||||
if (!otherObject || !otherObject->getInvMass())
|
||||
continue;
|
||||
numObjects++;
|
||||
}
|
||||
|
||||
///Then for each island that contains at least two objects and one fracture object
|
||||
if (fractureObjectIndex>=0 && numObjects>1)
|
||||
{
|
||||
|
||||
btFractureBody* fracObj = (btFractureBody*)getCollisionObjectArray()[fractureObjectIndex];
|
||||
|
||||
///glueing objects means creating a new compound and removing the old objects
|
||||
///delay the removal of old objects to avoid array indexing problems
|
||||
removedObjects.push_back(fracObj);
|
||||
m_fractureBodies.remove(fracObj);
|
||||
|
||||
btAlignedObjectArray<btScalar> massArray;
|
||||
|
||||
btAlignedObjectArray<btVector3> oldImpulses;
|
||||
btAlignedObjectArray<btVector3> oldCenterOfMassesWS;
|
||||
|
||||
oldImpulses.push_back(fracObj->getLinearVelocity()/1./fracObj->getInvMass());
|
||||
oldCenterOfMassesWS.push_back(fracObj->getCenterOfMassPosition());
|
||||
|
||||
btScalar totalMass = 0.f;
|
||||
|
||||
|
||||
btCompoundShape* compound = new btCompoundShape();
|
||||
if (fracObj->getCollisionShape()->isCompound())
|
||||
{
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
btCompoundShape* oldCompound = (btCompoundShape*)fracObj->getCollisionShape();
|
||||
for (int c=0;c<oldCompound->getNumChildShapes();c++)
|
||||
{
|
||||
compound->addChildShape(oldCompound->getChildTransform(c),oldCompound->getChildShape(c));
|
||||
massArray.push_back(fracObj->m_masses[c]);
|
||||
totalMass+=fracObj->m_masses[c];
|
||||
}
|
||||
|
||||
} else
|
||||
{
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
compound->addChildShape(tr,fracObj->getCollisionShape());
|
||||
massArray.push_back(fracObj->m_masses[0]);
|
||||
totalMass+=fracObj->m_masses[0];
|
||||
}
|
||||
|
||||
for (idx=startIslandIndex;idx<endIslandIndex;idx++)
|
||||
{
|
||||
|
||||
int i = unionFind.getElement(idx).m_sz;
|
||||
|
||||
if (i==fractureObjectIndex)
|
||||
continue;
|
||||
|
||||
btCollisionObject* otherCollider = getCollisionObjectArray()[i];
|
||||
|
||||
btRigidBody* otherObject = btRigidBody::upcast(otherCollider);
|
||||
//don't glue/merge with static objects right now, otherwise everything gets stuck to the ground
|
||||
///todo: expose this as a callback
|
||||
if (!otherObject || !otherObject->getInvMass())
|
||||
continue;
|
||||
|
||||
|
||||
oldImpulses.push_back(otherObject->getLinearVelocity()*(1.f/otherObject->getInvMass()));
|
||||
oldCenterOfMassesWS.push_back(otherObject->getCenterOfMassPosition());
|
||||
|
||||
removedObjects.push_back(otherObject);
|
||||
m_fractureBodies.remove((btFractureBody*)otherObject);
|
||||
|
||||
btScalar curMass = 1.f/otherObject->getInvMass();
|
||||
|
||||
|
||||
if (otherObject->getCollisionShape()->isCompound())
|
||||
{
|
||||
btTransform tr;
|
||||
btCompoundShape* oldCompound = (btCompoundShape*)otherObject->getCollisionShape();
|
||||
for (int c=0;c<oldCompound->getNumChildShapes();c++)
|
||||
{
|
||||
tr = fracObj->getWorldTransform().inverseTimes(otherObject->getWorldTransform()*oldCompound->getChildTransform(c));
|
||||
compound->addChildShape(tr,oldCompound->getChildShape(c));
|
||||
massArray.push_back(curMass/(btScalar)oldCompound->getNumChildShapes());
|
||||
|
||||
}
|
||||
} else
|
||||
{
|
||||
btTransform tr;
|
||||
tr = fracObj->getWorldTransform().inverseTimes(otherObject->getWorldTransform());
|
||||
compound->addChildShape(tr,otherObject->getCollisionShape());
|
||||
massArray.push_back(curMass);
|
||||
}
|
||||
totalMass+=curMass;
|
||||
}
|
||||
|
||||
|
||||
|
||||
btTransform shift;
|
||||
shift.setIdentity();
|
||||
btCompoundShape* newCompound = btFractureBody::shiftTransformDistributeMass(compound,totalMass,shift);
|
||||
int numChildren = newCompound->getNumChildShapes();
|
||||
btAssert(numChildren == massArray.size());
|
||||
|
||||
btVector3 localInertia;
|
||||
newCompound->calculateLocalInertia(totalMass,localInertia);
|
||||
btFractureBody* newBody = new btFractureBody(totalMass,0,newCompound,localInertia, &massArray[0], numChildren,this);
|
||||
newBody->recomputeConnectivity(this);
|
||||
newBody->setWorldTransform(fracObj->getWorldTransform()*shift);
|
||||
|
||||
//now the linear/angular velocity is still zero, apply the impulses
|
||||
|
||||
for (int i=0;i<oldImpulses.size();i++)
|
||||
{
|
||||
btVector3 rel_pos = oldCenterOfMassesWS[i]-newBody->getCenterOfMassPosition();
|
||||
const btVector3& imp = oldImpulses[i];
|
||||
newBody->applyImpulse(imp, rel_pos);
|
||||
}
|
||||
|
||||
addRigidBody(newBody);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//remove the objects from the world at the very end,
|
||||
//otherwise the island tags would not match the world collision object array indices anymore
|
||||
while (removedObjects.size())
|
||||
{
|
||||
btCollisionObject* otherCollider = removedObjects[removedObjects.size()-1];
|
||||
removedObjects.pop_back();
|
||||
|
||||
btRigidBody* otherObject = btRigidBody::upcast(otherCollider);
|
||||
if (!otherObject || !otherObject->getInvMass())
|
||||
continue;
|
||||
removeRigidBody(otherObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct btFracturePair
|
||||
{
|
||||
btFractureBody* m_fracObj;
|
||||
btAlignedObjectArray<btPersistentManifold*> m_contactManifolds;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void btFractureDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
|
||||
{
|
||||
// todo: after fracture we should run the solver again for better realism
|
||||
// for example
|
||||
// save all velocities and if one or more objects fracture:
|
||||
// 1) revert all velocties
|
||||
// 2) apply impulses for the fracture bodies at the contact locations
|
||||
// 3)and run the constaint solver again
|
||||
|
||||
btDiscreteDynamicsWorld::solveConstraints(solverInfo);
|
||||
|
||||
fractureCallback();
|
||||
}
|
||||
|
||||
btFractureBody* btFractureDynamicsWorld::addNewBody(const btTransform& oldTransform,btScalar* masses, btCompoundShape* oldCompound)
|
||||
{
|
||||
int i;
|
||||
|
||||
btTransform shift;
|
||||
shift.setIdentity();
|
||||
btVector3 localInertia;
|
||||
btCompoundShape* newCompound = btFractureBody::shiftTransform(oldCompound,masses,shift,localInertia);
|
||||
btScalar totalMass = 0;
|
||||
for (i=0;i<newCompound->getNumChildShapes();i++)
|
||||
totalMass += masses[i];
|
||||
//newCompound->calculateLocalInertia(totalMass,localInertia);
|
||||
|
||||
btFractureBody* newBody = new btFractureBody(totalMass,0,newCompound,localInertia, masses,newCompound->getNumChildShapes(), this);
|
||||
newBody->recomputeConnectivity(this);
|
||||
|
||||
newBody->setCollisionFlags(newBody->getCollisionFlags()|btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
|
||||
newBody->setWorldTransform(oldTransform*shift);
|
||||
addRigidBody(newBody);
|
||||
return newBody;
|
||||
}
|
||||
|
||||
void btFractureDynamicsWorld::addRigidBody(btRigidBody* body)
|
||||
{
|
||||
if (body->getInternalType() & CUSTOM_FRACTURE_TYPE)
|
||||
{
|
||||
btFractureBody* fbody = (btFractureBody*)body;
|
||||
m_fractureBodies.push_back(fbody);
|
||||
}
|
||||
btDiscreteDynamicsWorld::addRigidBody(body);
|
||||
}
|
||||
|
||||
void btFractureDynamicsWorld::removeRigidBody(btRigidBody* body)
|
||||
{
|
||||
if (body->getInternalType() & CUSTOM_FRACTURE_TYPE)
|
||||
{
|
||||
btFractureBody* fbody = (btFractureBody*)body;
|
||||
btAlignedObjectArray<btTypedConstraint*> tmpConstraints;
|
||||
|
||||
for (int i=0;i<fbody->getNumConstraintRefs();i++)
|
||||
{
|
||||
tmpConstraints.push_back(fbody->getConstraintRef(i));
|
||||
}
|
||||
|
||||
//remove all constraints attached to this rigid body too
|
||||
for (int i=0;i<tmpConstraints.size();i++)
|
||||
btDiscreteDynamicsWorld::removeConstraint(tmpConstraints[i]);
|
||||
|
||||
m_fractureBodies.remove(fbody);
|
||||
}
|
||||
|
||||
|
||||
|
||||
btDiscreteDynamicsWorld::removeRigidBody(body);
|
||||
}
|
||||
|
||||
void btFractureDynamicsWorld::breakDisconnectedParts( btFractureBody* fracObj)
|
||||
{
|
||||
|
||||
if (!fracObj->getCollisionShape()->isCompound())
|
||||
return;
|
||||
|
||||
btCompoundShape* compound = (btCompoundShape*)fracObj->getCollisionShape();
|
||||
int numChildren = compound->getNumChildShapes();
|
||||
|
||||
if (numChildren<=1)
|
||||
return;
|
||||
|
||||
//compute connectivity
|
||||
btUnionFind unionFind;
|
||||
|
||||
btAlignedObjectArray<int> tags;
|
||||
tags.resize(numChildren);
|
||||
int i, index = 0;
|
||||
for ( i=0;i<numChildren;i++)
|
||||
{
|
||||
#ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
|
||||
tags[i] = index++;
|
||||
#else
|
||||
tags[i] = i;
|
||||
index=i+1;
|
||||
#endif
|
||||
}
|
||||
|
||||
unionFind.reset(index);
|
||||
int numElem = unionFind.getNumElements();
|
||||
for (i=0;i<fracObj->m_connections.size();i++)
|
||||
{
|
||||
btConnection& connection = fracObj->m_connections[i];
|
||||
if (connection.m_strength > 0.)
|
||||
{
|
||||
int tag0 = tags[connection.m_childIndex0];
|
||||
int tag1 = tags[connection.m_childIndex1];
|
||||
unionFind.unite(tag0, tag1);
|
||||
}
|
||||
}
|
||||
numElem = unionFind.getNumElements();
|
||||
|
||||
index=0;
|
||||
for (int ai=0;ai<numChildren;ai++)
|
||||
{
|
||||
int tag = unionFind.find(index);
|
||||
tags[ai] = tag;
|
||||
//Set the correct object offset in Collision Object Array
|
||||
#if STATIC_SIMULATION_ISLAND_OPTIMIZATION
|
||||
unionFind.getElement(index).m_sz = ai;
|
||||
#endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
|
||||
index++;
|
||||
}
|
||||
unionFind.sortIslands();
|
||||
|
||||
int endIslandIndex=1;
|
||||
int startIslandIndex;
|
||||
|
||||
btAlignedObjectArray<btCollisionObject*> removedObjects;
|
||||
|
||||
int numIslands = 0;
|
||||
|
||||
for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
|
||||
{
|
||||
int islandId = unionFind.getElement(startIslandIndex).m_id;
|
||||
for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (unionFind.getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
|
||||
{
|
||||
}
|
||||
|
||||
// int fractureObjectIndex = -1;
|
||||
|
||||
int numShapes=0;
|
||||
|
||||
|
||||
btCompoundShape* newCompound = new btCompoundShape();
|
||||
btAlignedObjectArray<btScalar> masses;
|
||||
|
||||
int idx;
|
||||
for (idx=startIslandIndex;idx<endIslandIndex;idx++)
|
||||
{
|
||||
int i = unionFind.getElement(idx).m_sz;
|
||||
// btCollisionShape* shape = compound->getChildShape(i);
|
||||
newCompound->addChildShape(compound->getChildTransform(i),compound->getChildShape(i));
|
||||
masses.push_back(fracObj->m_masses[i]);
|
||||
numShapes++;
|
||||
}
|
||||
if (numShapes)
|
||||
{
|
||||
btFractureBody* newBody = addNewBody(fracObj->getWorldTransform(),&masses[0],newCompound);
|
||||
newBody->setLinearVelocity(fracObj->getLinearVelocity());
|
||||
newBody->setAngularVelocity(fracObj->getAngularVelocity());
|
||||
|
||||
numIslands++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
removeRigidBody(fracObj);//should it also be removed from the array?
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
void btFractureDynamicsWorld::fractureCallback( )
|
||||
{
|
||||
|
||||
btAlignedObjectArray<btFracturePair> sFracturePairs;
|
||||
|
||||
if (!m_fracturingMode)
|
||||
{
|
||||
glueCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
int numManifolds = getDispatcher()->getNumManifolds();
|
||||
|
||||
sFracturePairs.clear();
|
||||
|
||||
|
||||
for (int i=0;i<numManifolds;i++)
|
||||
{
|
||||
btPersistentManifold* manifold = getDispatcher()->getManifoldByIndexInternal(i);
|
||||
if (!manifold->getNumContacts())
|
||||
continue;
|
||||
|
||||
btScalar totalImpact = 0.f;
|
||||
for (int p=0;p<manifold->getNumContacts();p++)
|
||||
{
|
||||
totalImpact += manifold->getContactPoint(p).m_appliedImpulse;
|
||||
}
|
||||
|
||||
|
||||
// printf("totalImpact=%f\n",totalImpact);
|
||||
|
||||
static float maxImpact = 0;
|
||||
if (totalImpact>maxImpact)
|
||||
maxImpact = totalImpact;
|
||||
|
||||
//some threshold otherwise resting contact would break objects after a while
|
||||
if (totalImpact < 40.f)
|
||||
continue;
|
||||
|
||||
// printf("strong impact\n");
|
||||
|
||||
|
||||
//@todo: add better logic to decide what parts to fracture
|
||||
//For example use the idea from the SIGGRAPH talk about the fracture in the movie 2012:
|
||||
//
|
||||
//Breaking thresholds can be stored as connectivity information between child shapes in the fracture object
|
||||
//
|
||||
//You can calculate some "impact value" by simulating all the individual child shapes
|
||||
//as rigid bodies, without constraints, running it in a separate simulation world
|
||||
//(or by running the constraint solver without actually modifying the dynamics world)
|
||||
//Then measure some "impact value" using the offset and applied impulse for each child shape
|
||||
//weaken the connections based on this "impact value" and only break
|
||||
//if this impact value exceeds the breaking threshold.
|
||||
//you can propagate the weakening and breaking of connections using the connectivity information
|
||||
|
||||
int f0 = m_fractureBodies.findLinearSearch((btFractureBody*)manifold->getBody0());
|
||||
int f1 = m_fractureBodies.findLinearSearch((btFractureBody*)manifold->getBody1());
|
||||
|
||||
if (f0 == f1 == m_fractureBodies.size())
|
||||
continue;
|
||||
|
||||
|
||||
if (f0<m_fractureBodies.size())
|
||||
{
|
||||
int j=f0;
|
||||
|
||||
btCollisionObject* colOb = (btCollisionObject*)manifold->getBody1();
|
||||
// btRigidBody* otherOb = btRigidBody::upcast(colOb);
|
||||
// if (!otherOb->getInvMass())
|
||||
// continue;
|
||||
|
||||
int pi=-1;
|
||||
|
||||
for (int p=0;p<sFracturePairs.size();p++)
|
||||
{
|
||||
if (sFracturePairs[p].m_fracObj == m_fractureBodies[j])
|
||||
{
|
||||
pi = p; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pi<0)
|
||||
{
|
||||
btFracturePair p;
|
||||
p.m_fracObj = m_fractureBodies[j];
|
||||
p.m_contactManifolds.push_back(manifold);
|
||||
sFracturePairs.push_back(p);
|
||||
} else
|
||||
{
|
||||
btAssert(sFracturePairs[pi].m_contactManifolds.findLinearSearch(manifold)==sFracturePairs[pi].m_contactManifolds.size());
|
||||
sFracturePairs[pi].m_contactManifolds.push_back(manifold);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (f1 < m_fractureBodies.size())
|
||||
{
|
||||
int j=f1;
|
||||
{
|
||||
btCollisionObject* colOb = (btCollisionObject*)manifold->getBody0();
|
||||
btRigidBody* otherOb = btRigidBody::upcast(colOb);
|
||||
// if (!otherOb->getInvMass())
|
||||
// continue;
|
||||
|
||||
|
||||
int pi=-1;
|
||||
|
||||
for (int p=0;p<sFracturePairs.size();p++)
|
||||
{
|
||||
if (sFracturePairs[p].m_fracObj == m_fractureBodies[j])
|
||||
{
|
||||
pi = p; break;
|
||||
}
|
||||
}
|
||||
if (pi<0)
|
||||
{
|
||||
btFracturePair p;
|
||||
p.m_fracObj = m_fractureBodies[j];
|
||||
p.m_contactManifolds.push_back( manifold);
|
||||
sFracturePairs.push_back(p);
|
||||
} else
|
||||
{
|
||||
btAssert(sFracturePairs[pi].m_contactManifolds.findLinearSearch(manifold)==sFracturePairs[pi].m_contactManifolds.size());
|
||||
sFracturePairs[pi].m_contactManifolds.push_back(manifold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
}
|
||||
|
||||
//printf("m_fractureBodies size=%d\n",m_fractureBodies.size());
|
||||
//printf("sFracturePairs size=%d\n",sFracturePairs.size());
|
||||
if (!sFracturePairs.size())
|
||||
return;
|
||||
|
||||
|
||||
{
|
||||
// printf("fracturing\n");
|
||||
|
||||
for (int i=0;i<sFracturePairs.size();i++)
|
||||
{
|
||||
//check impulse/displacement at impact
|
||||
|
||||
//weaken/break connections (and propagate breaking)
|
||||
|
||||
//compute connectivity of connected child shapes
|
||||
|
||||
|
||||
if (sFracturePairs[i].m_fracObj->getCollisionShape()->isCompound())
|
||||
{
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
btCompoundShape* oldCompound = (btCompoundShape*)sFracturePairs[i].m_fracObj->getCollisionShape();
|
||||
if (oldCompound->getNumChildShapes()>1)
|
||||
{
|
||||
bool needsBreakingCheck = false;
|
||||
|
||||
|
||||
//weaken/break the connections
|
||||
|
||||
//@todo: propagate along the connection graph
|
||||
for (int j=0;j<sFracturePairs[i].m_contactManifolds.size();j++)
|
||||
{
|
||||
btPersistentManifold* manifold = sFracturePairs[i].m_contactManifolds[j];
|
||||
for (int k=0;k<manifold->getNumContacts();k++)
|
||||
{
|
||||
btManifoldPoint& pt = manifold->getContactPoint(k);
|
||||
if (manifold->getBody0()==sFracturePairs[i].m_fracObj)
|
||||
{
|
||||
for (int f=0;f<sFracturePairs[i].m_fracObj->m_connections.size();f++)
|
||||
{
|
||||
btConnection& connection = sFracturePairs[i].m_fracObj->m_connections[f];
|
||||
if ( (connection.m_childIndex0 == pt.m_index0) ||
|
||||
(connection.m_childIndex1 == pt.m_index0)
|
||||
)
|
||||
{
|
||||
connection.m_strength -= pt.m_appliedImpulse;
|
||||
if (connection.m_strength<0)
|
||||
{
|
||||
//remove or set to zero
|
||||
connection.m_strength=0.f;
|
||||
needsBreakingCheck = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (int f=0;f<sFracturePairs[i].m_fracObj->m_connections.size();f++)
|
||||
{
|
||||
btConnection& connection = sFracturePairs[i].m_fracObj->m_connections[f];
|
||||
if ( (connection.m_childIndex0 == pt.m_index1) ||
|
||||
(connection.m_childIndex1 == pt.m_index1)
|
||||
)
|
||||
{
|
||||
connection.m_strength -= pt.m_appliedImpulse;
|
||||
if (connection.m_strength<0)
|
||||
{
|
||||
//remove or set to zero
|
||||
connection.m_strength=0.f;
|
||||
needsBreakingCheck = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsBreakingCheck)
|
||||
{
|
||||
breakDisconnectedParts(sFracturePairs[i].m_fracObj);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sFracturePairs.clear();
|
||||
|
||||
}
|
||||
|
||||
51
ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.h
Normal file
51
ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef _BT_FRACTURE_DYNAMICS_WORLD_H
|
||||
#define _BT_FRACTURE_DYNAMICS_WORLD_H
|
||||
|
||||
#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
|
||||
class btFractureBody;
|
||||
class btCompoundShape;
|
||||
class btTransform;
|
||||
|
||||
|
||||
///The btFractureDynamicsWorld class enabled basic glue and fracture of objects.
|
||||
///If/once this implementation is stablized/tested we might merge it into btDiscreteDynamicsWorld and remove the class.
|
||||
class btFractureDynamicsWorld : public btDiscreteDynamicsWorld
|
||||
{
|
||||
btAlignedObjectArray<btFractureBody*> m_fractureBodies;
|
||||
|
||||
bool m_fracturingMode;
|
||||
|
||||
btFractureBody* addNewBody(const btTransform& oldTransform,btScalar* masses, btCompoundShape* oldCompound);
|
||||
|
||||
void breakDisconnectedParts( btFractureBody* fracObj);
|
||||
|
||||
public:
|
||||
|
||||
btFractureDynamicsWorld ( btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration);
|
||||
|
||||
virtual void addRigidBody(btRigidBody* body);
|
||||
|
||||
virtual void removeRigidBody(btRigidBody* body);
|
||||
|
||||
void solveConstraints(btContactSolverInfo& solverInfo);
|
||||
|
||||
///either fracture or glue (!fracture)
|
||||
void setFractureMode(bool fracture)
|
||||
{
|
||||
m_fracturingMode = fracture;
|
||||
}
|
||||
|
||||
bool getFractureMode() const { return m_fracturingMode;}
|
||||
|
||||
///normally those callbacks are called internally by the 'solveConstraints'
|
||||
void glueCallback();
|
||||
|
||||
///normally those callbacks are called internally by the 'solveConstraints'
|
||||
void fractureCallback();
|
||||
|
||||
};
|
||||
|
||||
#endif //_BT_FRACTURE_DYNAMICS_WORLD_H
|
||||
|
||||
42
ObsoleteDemos/FractureDemo/main.cpp
Normal file
42
ObsoleteDemos/FractureDemo/main.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2007 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 "FractureDemo.h"
|
||||
#include "GlutStuff.h"
|
||||
#include "GLDebugDrawer.h"
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "LinearMath/btHashMap.h"
|
||||
|
||||
|
||||
int main(int argc,char** argv)
|
||||
{
|
||||
GLDebugDrawer gDebugDrawer;
|
||||
|
||||
|
||||
FractureDemo ccdDemo;
|
||||
ccdDemo.initPhysics();
|
||||
ccdDemo.getDynamicsWorld()->setDebugDrawer(&gDebugDrawer);
|
||||
|
||||
|
||||
#ifdef CHECK_MEMORY_LEAKS
|
||||
ccdDemo.exitPhysics();
|
||||
#else
|
||||
return glutmain(argc, argv,640,480,"Bullet Physics Demo. http://bulletphysics.com",&ccdDemo);
|
||||
#endif
|
||||
|
||||
//default glut doesn't return from mainloop
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user