Added btGhostObject and btPairCachingGhostObject functionality.
It is a fast way to keep track of overlapping objects in an area, and doing rayTest and convexSweepTest for overlapping objects, instead of btCollisionWorld::rayTest/convexSweepTest. Updated KinematicCharacterController to use btPairCachingGhostObject.
This commit is contained in:
@@ -12,16 +12,12 @@ class CharacterControllerInterface
|
|||||||
public:
|
public:
|
||||||
CharacterControllerInterface () {};
|
CharacterControllerInterface () {};
|
||||||
virtual ~CharacterControllerInterface () {};
|
virtual ~CharacterControllerInterface () {};
|
||||||
virtual void setup (btScalar height = 2.0, btScalar width = 0.25, btScalar stepHeight = 0.25) = 0;
|
|
||||||
virtual void destroy () = 0;
|
|
||||||
|
|
||||||
virtual btCollisionObject* getCollisionObject () = 0;
|
|
||||||
|
|
||||||
virtual void reset () = 0;
|
virtual void reset () = 0;
|
||||||
virtual void warp (const btVector3& origin) = 0;
|
virtual void warp (const btVector3& origin) = 0;
|
||||||
virtual void registerPairCacheAndDispatcher (btOverlappingPairCache* pairCache, btCollisionDispatcher* dispatcher)=0;
|
|
||||||
virtual void preStep (const btCollisionWorld* collisionWorld) = 0;
|
virtual void preStep ( btCollisionWorld* collisionWorld) = 0;
|
||||||
virtual void playerStep (const btCollisionWorld* collisionWorld, btScalar dt,
|
virtual void playerStep (btCollisionWorld* collisionWorld, btScalar dt,
|
||||||
int forward,
|
int forward,
|
||||||
int backward,
|
int backward,
|
||||||
int left,
|
int left,
|
||||||
|
|||||||
@@ -13,13 +13,9 @@ subject to the following restrictions:
|
|||||||
3. This notice may not be removed or altered from any source distribution.
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// September 2006: CharacterDemo is work in progress, this file is mostly just a placeholder
|
|
||||||
/// This CharacterDemo file is very early in development, please check it later
|
|
||||||
/// One todo is a basic engine model:
|
|
||||||
/// A function that maps user input (throttle) into torque/force applied on the wheels
|
|
||||||
/// with gears etc.
|
|
||||||
#include "btBulletDynamicsCommon.h"
|
#include "btBulletDynamicsCommon.h"
|
||||||
#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
|
#include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
|
||||||
|
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
||||||
|
|
||||||
#include "GLDebugDrawer.h"
|
#include "GLDebugDrawer.h"
|
||||||
#include <stdio.h> //printf debugging
|
#include <stdio.h> //printf debugging
|
||||||
@@ -54,55 +50,6 @@ void playerStepCallback(btDynamicsWorld* dynamicsWorld, btScalar timeStep)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define QUAKE_BSP_IMPORTING 1
|
|
||||||
#ifdef QUAKE_BSP_IMPORTING
|
|
||||||
#include "../BspDemo/BspLoader.h"
|
|
||||||
#include "../BspDemo/BspConverter.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BspToBulletConverter : public BspConverter
|
|
||||||
{
|
|
||||||
CharacterDemo* m_demoApp;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
BspToBulletConverter(CharacterDemo* demoApp)
|
|
||||||
:m_demoApp(demoApp)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void addConvexVerticesCollider(btAlignedObjectArray<btVector3>& vertices, bool isEntity, const btVector3& entityTargetLocation)
|
|
||||||
{
|
|
||||||
///perhaps we can do something special with entities (isEntity)
|
|
||||||
///like adding a collision Triggering (as example)
|
|
||||||
|
|
||||||
if (vertices.size() > 0)
|
|
||||||
{
|
|
||||||
float mass = 0.f;
|
|
||||||
btTransform startTransform;
|
|
||||||
//can use a shift
|
|
||||||
startTransform.setIdentity();
|
|
||||||
startTransform.setOrigin(btVector3(0,-10.0f,0.0f));
|
|
||||||
//this create an internal copy of the vertices
|
|
||||||
for (int i = 0; i < vertices.size(); i++)
|
|
||||||
{
|
|
||||||
vertices[i] *= btScalar(0.5);
|
|
||||||
float t = vertices[i].getZ() * btScalar(0.75);
|
|
||||||
vertices[i].setZ(-vertices[i].getY());
|
|
||||||
vertices[i].setY(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
btCollisionShape* shape = new btConvexHullShape(&(vertices[0].getX()),vertices.size());
|
|
||||||
m_demoApp->m_collisionShapes.push_back(shape);
|
|
||||||
|
|
||||||
//btRigidBody* body = m_demoApp->localCreateRigidBody(mass, startTransform,shape);
|
|
||||||
m_demoApp->localCreateRigidBody(mass, startTransform,shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif //QUAKE_BSP_IMPORTING
|
|
||||||
CharacterDemo::CharacterDemo()
|
CharacterDemo::CharacterDemo()
|
||||||
:
|
:
|
||||||
m_cameraHeight(4.f),
|
m_cameraHeight(4.f),
|
||||||
@@ -115,130 +62,6 @@ m_vertices(0)
|
|||||||
m_cameraPosition = btVector3(30,30,30);
|
m_cameraPosition = btVector3(30,30,30);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterDemo::~CharacterDemo()
|
|
||||||
{
|
|
||||||
//cleanup in the reverse order of creation/initialization
|
|
||||||
if (m_character)
|
|
||||||
{
|
|
||||||
m_dynamicsWorld->removeCollisionObject(m_character->getCollisionObject());
|
|
||||||
m_character->destroy ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete m_indexVertexArrays;
|
|
||||||
delete m_vertices;
|
|
||||||
|
|
||||||
//delete dynamics world
|
|
||||||
delete m_dynamicsWorld;
|
|
||||||
|
|
||||||
//delete solver
|
|
||||||
delete m_constraintSolver;
|
|
||||||
|
|
||||||
//delete broadphase
|
|
||||||
delete m_overlappingPairCache;
|
|
||||||
|
|
||||||
//delete dispatcher
|
|
||||||
delete m_dispatcher;
|
|
||||||
|
|
||||||
delete m_collisionConfiguration;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyCustomOverlappingPairCallback : public btOverlappingPairCallback
|
|
||||||
{
|
|
||||||
|
|
||||||
CharacterDemo* m_characterDemo;
|
|
||||||
btCollisionObject* m_characterCollider;
|
|
||||||
|
|
||||||
btHashedOverlappingPairCache* m_hashPairCache;
|
|
||||||
|
|
||||||
struct customOverlapFilterCallback : public btOverlapFilterCallback
|
|
||||||
{
|
|
||||||
bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
|
|
||||||
{
|
|
||||||
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
|
|
||||||
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
|
|
||||||
return collides;
|
|
||||||
|
|
||||||
}
|
|
||||||
} myCustomOverlapFilterCallback;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
MyCustomOverlappingPairCallback(CharacterDemo* demo,btCollisionObject* characterCollider)
|
|
||||||
:m_characterDemo(demo),
|
|
||||||
m_characterCollider(characterCollider)
|
|
||||||
{
|
|
||||||
m_hashPairCache = new btHashedOverlappingPairCache();
|
|
||||||
m_hashPairCache->setOverlapFilterCallback (&myCustomOverlapFilterCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~MyCustomOverlappingPairCallback()
|
|
||||||
{
|
|
||||||
delete m_hashPairCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1)
|
|
||||||
{
|
|
||||||
if (proxy0->m_clientObject==m_characterCollider || proxy1->m_clientObject==m_characterCollider)
|
|
||||||
{
|
|
||||||
//printf("addOverlappingPair (%p,%p)\n",proxy0,proxy1);
|
|
||||||
return m_hashPairCache->addOverlappingPair(proxy0,proxy1);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher)
|
|
||||||
{
|
|
||||||
if (proxy0->m_clientObject==m_characterCollider || proxy1->m_clientObject==m_characterCollider)
|
|
||||||
{
|
|
||||||
//printf("removeOverlappingPair (%p,%p)\n",proxy0,proxy1);
|
|
||||||
return m_hashPairCache->removeOverlappingPair(proxy0,proxy1,dispatcher);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher)
|
|
||||||
{
|
|
||||||
if (proxy0->m_clientObject==m_characterCollider)
|
|
||||||
{
|
|
||||||
//printf("removeOverlappingPairsContainingProxy (%p)\n",proxy0);
|
|
||||||
m_hashPairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
btBroadphasePairArray& getOverlappingPairArray()
|
|
||||||
{
|
|
||||||
return m_hashPairCache->getOverlappingPairArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
btOverlappingPairCache* getOverlappingPairCache()
|
|
||||||
{
|
|
||||||
return m_hashPairCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
void CharacterDemo::initPhysics()
|
void CharacterDemo::initPhysics()
|
||||||
{
|
{
|
||||||
@@ -254,29 +77,56 @@ void CharacterDemo::initPhysics()
|
|||||||
m_constraintSolver = new btSequentialImpulseConstraintSolver();
|
m_constraintSolver = new btSequentialImpulseConstraintSolver();
|
||||||
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
|
m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration);
|
||||||
|
|
||||||
|
#ifdef DYNAMIC_CHARACTER_CONTROLLER
|
||||||
|
m_character = new DynamicCharacterController ();
|
||||||
|
#else
|
||||||
|
|
||||||
|
btTransform startTransform;
|
||||||
|
startTransform.setIdentity ();
|
||||||
|
startTransform.setOrigin (btVector3(0.0, 4.0, 0.0));
|
||||||
|
|
||||||
|
m_ghostObject = new btPairCachingGhostObject();
|
||||||
|
m_ghostObject->setWorldTransform(startTransform);
|
||||||
|
sweepBP->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
|
||||||
|
btScalar characterHeight=1.75;
|
||||||
|
btScalar characterWidth =1.75;
|
||||||
|
btConvexShape* capsule = new btCapsuleShape(characterWidth,characterHeight);
|
||||||
|
m_ghostObject->setCollisionShape (capsule);
|
||||||
|
m_ghostObject->setCollisionFlags (btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||||
|
|
||||||
|
btScalar stepHeight = btScalar(0.35);
|
||||||
|
m_character = new KinematicCharacterController (m_ghostObject,capsule,stepHeight);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
m_dynamicsWorld->setInternalTickCallback(playerStepCallback,m_character);
|
||||||
|
|
||||||
|
|
||||||
|
///only collide with static for now (no interaction with dynamic objects)
|
||||||
|
m_dynamicsWorld->addCollisionObject(m_ghostObject,btBroadphaseProxy::DebrisFilter, btBroadphaseProxy::StaticFilter);
|
||||||
|
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
/// Create some basic environment from a Quake level
|
||||||
|
|
||||||
//m_dynamicsWorld->setGravity(btVector3(0,0,0));
|
//m_dynamicsWorld->setGravity(btVector3(0,0,0));
|
||||||
btTransform tr;
|
btTransform tr;
|
||||||
tr.setIdentity();
|
tr.setIdentity();
|
||||||
|
|
||||||
|
|
||||||
#ifdef QUAKE_BSP_IMPORTING
|
|
||||||
char* bspfilename = "BspDemo.bsp";
|
char* bspfilename = "BspDemo.bsp";
|
||||||
void* memoryBuffer = 0;
|
void* memoryBuffer = 0;
|
||||||
|
|
||||||
FILE* file = fopen(bspfilename,"r");
|
FILE* file = fopen(bspfilename,"r");
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
//try again other path,
|
//visual studio leaves the current working directory in the projectfiles folder
|
||||||
//sight... visual studio leaves the current working directory in the projectfiles folder
|
|
||||||
//instead of executable folder. who wants this default behaviour?!?
|
|
||||||
bspfilename = "../../BspDemo.bsp";
|
bspfilename = "../../BspDemo.bsp";
|
||||||
file = fopen(bspfilename,"r");
|
file = fopen(bspfilename,"r");
|
||||||
}
|
}
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
//try again other path,
|
//visual studio leaves the current working directory in the projectfiles folder
|
||||||
//sight... visual studio leaves the current working directory in the projectfiles folder
|
|
||||||
//instead of executable folder. who wants this default behaviour?!?
|
|
||||||
bspfilename = "BspDemo.bsp";
|
bspfilename = "BspDemo.bsp";
|
||||||
file = fopen(bspfilename,"r");
|
file = fopen(bspfilename,"r");
|
||||||
}
|
}
|
||||||
@@ -302,211 +152,11 @@ void CharacterDemo::initPhysics()
|
|||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
///////////////
|
||||||
#define USE_TRIMESH_GROUND 1
|
|
||||||
#ifdef USE_TRIMESH_GROUND
|
|
||||||
int i;
|
|
||||||
|
|
||||||
const float TRIANGLE_SIZE=20.f;
|
|
||||||
|
|
||||||
//create a triangle-mesh ground
|
|
||||||
int vertStride = sizeof(btVector3);
|
|
||||||
int indexStride = 3*sizeof(int);
|
|
||||||
|
|
||||||
const int NUM_VERTS_X = 20;
|
|
||||||
const int NUM_VERTS_Y = 20;
|
|
||||||
const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y;
|
|
||||||
|
|
||||||
const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1);
|
|
||||||
|
|
||||||
m_vertices = new btVector3[totalVerts];
|
|
||||||
int* gIndices = new int[totalTriangles*3];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for ( i=0;i<NUM_VERTS_X;i++)
|
|
||||||
{
|
|
||||||
for (int j=0;j<NUM_VERTS_Y;j++)
|
|
||||||
{
|
|
||||||
float wl = .2f;
|
|
||||||
//height set to zero, but can also use curved landscape, just uncomment out the code
|
|
||||||
float height = 20.f*sinf(float(i)*wl)*cosf(float(j)*wl);
|
|
||||||
#ifdef FORCE_ZAXIS_UP
|
|
||||||
m_vertices[i+j*NUM_VERTS_X].setValue(
|
|
||||||
(i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
|
|
||||||
(j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE,
|
|
||||||
height
|
|
||||||
);
|
|
||||||
|
|
||||||
#else
|
|
||||||
m_vertices[i+j*NUM_VERTS_X].setValue(
|
|
||||||
(i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
|
|
||||||
height,
|
|
||||||
(j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int index=0;
|
|
||||||
for ( i=0;i<NUM_VERTS_X-1;i++)
|
|
||||||
{
|
|
||||||
for (int j=0;j<NUM_VERTS_Y-1;j++)
|
|
||||||
{
|
|
||||||
gIndices[index++] = j*NUM_VERTS_X+i;
|
|
||||||
gIndices[index++] = j*NUM_VERTS_X+i+1;
|
|
||||||
gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
|
||||||
|
|
||||||
gIndices[index++] = j*NUM_VERTS_X+i;
|
|
||||||
gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
|
||||||
gIndices[index++] = (j+1)*NUM_VERTS_X+i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_indexVertexArrays = new btTriangleIndexVertexArray(totalTriangles,
|
|
||||||
gIndices,
|
|
||||||
indexStride,
|
|
||||||
totalVerts,(btScalar*) &m_vertices[0].x(),vertStride);
|
|
||||||
|
|
||||||
bool useQuantizedAabbCompression = true;
|
|
||||||
groundShape = new btBvhTriangleMeshShape(m_indexVertexArrays,useQuantizedAabbCompression);
|
|
||||||
|
|
||||||
tr.setOrigin(btVector3(0,-4.5f,0));
|
|
||||||
|
|
||||||
#else
|
|
||||||
//testing btHeightfieldTerrainShape
|
|
||||||
int width=128;
|
|
||||||
int length=128;
|
|
||||||
unsigned char* heightfieldData = new unsigned char[width*length];
|
|
||||||
{
|
|
||||||
for (int i=0;i<width*length;i++)
|
|
||||||
{
|
|
||||||
heightfieldData[i]=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char* filename="heightfield128x128.raw";
|
|
||||||
FILE* heightfieldFile = fopen(filename,"r");
|
|
||||||
if (!heightfieldFile)
|
|
||||||
{
|
|
||||||
filename="../../heightfield128x128.raw";
|
|
||||||
heightfieldFile = fopen(filename,"r");
|
|
||||||
}
|
|
||||||
if (heightfieldFile)
|
|
||||||
{
|
|
||||||
int numBytes =fread(heightfieldData,1,width*length,heightfieldFile);
|
|
||||||
//btAssert(numBytes);
|
|
||||||
if (!numBytes)
|
|
||||||
{
|
|
||||||
printf("couldn't read heightfield at %s\n",filename);
|
|
||||||
}
|
|
||||||
fclose (heightfieldFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
btScalar maxHeight = 20000.f;
|
|
||||||
|
|
||||||
bool useFloatDatam=false;
|
|
||||||
bool flipQuadEdges=false;
|
|
||||||
|
|
||||||
btHeightfieldTerrainShape* heightFieldShape = new btHeightfieldTerrainShape(width,length,heightfieldData,maxHeight,upIndex,useFloatDatam,flipQuadEdges);;
|
|
||||||
groundShape = heightFieldShape;
|
|
||||||
|
|
||||||
heightFieldShape->setUseDiamondSubdivision(true);
|
|
||||||
|
|
||||||
btVector3 localScaling(20,20,20);
|
|
||||||
localScaling[upIndex]=1.f;
|
|
||||||
groundShape->setLocalScaling(localScaling);
|
|
||||||
|
|
||||||
tr.setOrigin(btVector3(0,-64.5f,0));
|
|
||||||
|
|
||||||
#endif //
|
|
||||||
|
|
||||||
m_collisionShapes.push_back(groundShape);
|
|
||||||
//create ground object
|
|
||||||
localCreateRigidBody(0,tr,groundShape);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define CUBE_HALF_EXTENTS 0.5
|
|
||||||
#define EXTRA_HEIGHT 10.0
|
|
||||||
btBoxShape* boxShape = new btBoxShape (btVector3(1.0, 1.0, 1.0));
|
|
||||||
m_collisionShapes.push_back (boxShape);
|
|
||||||
#define DO_WALL
|
|
||||||
#ifdef DO_WALL
|
|
||||||
for (i=0;i<50;i++)
|
|
||||||
{
|
|
||||||
btCollisionShape* shape = boxShape;
|
|
||||||
//shape->setMargin(gCollisionMargin);
|
|
||||||
|
|
||||||
bool isDyna = i>0;
|
|
||||||
|
|
||||||
btTransform trans;
|
|
||||||
trans.setIdentity();
|
|
||||||
|
|
||||||
if (i>0)
|
|
||||||
{
|
|
||||||
//stack them
|
|
||||||
int colsize = 10;
|
|
||||||
int row = (i*CUBE_HALF_EXTENTS*2)/(colsize*2*CUBE_HALF_EXTENTS);
|
|
||||||
int row2 = row;
|
|
||||||
int col = (i)%(colsize)-colsize/2;
|
|
||||||
|
|
||||||
|
|
||||||
if (col>3)
|
|
||||||
{
|
|
||||||
col=11;
|
|
||||||
row2 |=1;
|
|
||||||
}
|
|
||||||
|
|
||||||
btVector3 pos(col*2*CUBE_HALF_EXTENTS + (row2%2)*CUBE_HALF_EXTENTS,
|
|
||||||
row*2*CUBE_HALF_EXTENTS+CUBE_HALF_EXTENTS+EXTRA_HEIGHT,0);
|
|
||||||
|
|
||||||
trans.setOrigin(pos);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
trans.setOrigin(btVector3(0,EXTRA_HEIGHT-CUBE_HALF_EXTENTS,0));
|
|
||||||
}
|
|
||||||
|
|
||||||
float mass = 1.f;
|
|
||||||
|
|
||||||
if (!isDyna)
|
|
||||||
mass = 0.f;
|
|
||||||
|
|
||||||
btRigidBody* body = localCreateRigidBody(mass,trans,shape);
|
|
||||||
#ifdef USE_KINEMATIC_GROUND
|
|
||||||
if (mass == 0.f)
|
|
||||||
{
|
|
||||||
body->setCollisionFlags( body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
|
|
||||||
body->setActivationState(DISABLE_DEACTIVATION);
|
|
||||||
}
|
|
||||||
#endif //USE_KINEMATIC_GROUND
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef DYNAMIC_CHARACTER_CONTROLLER
|
|
||||||
m_character = new DynamicCharacterController ();
|
|
||||||
#else
|
|
||||||
m_character = new KinematicCharacterController ();
|
|
||||||
#endif
|
|
||||||
m_character->setup ();
|
|
||||||
|
|
||||||
m_dynamicsWorld->setInternalTickCallback(playerStepCallback,m_character);
|
|
||||||
|
|
||||||
//some custom callback sample
|
|
||||||
m_customPairCallback = new MyCustomOverlappingPairCallback(this,m_character->getCollisionObject());
|
|
||||||
sweepBP->setOverlappingPairUserCallback(m_customPairCallback);
|
|
||||||
m_character->registerPairCacheAndDispatcher (m_customPairCallback->getOverlappingPairCache(), m_dispatcher);
|
|
||||||
|
|
||||||
///only collide with static for now (no interaction with dynamic objects)
|
|
||||||
m_dynamicsWorld->addCollisionObject(m_character->getCollisionObject(),btBroadphaseProxy::DebrisFilter, btBroadphaseProxy::StaticFilter);
|
|
||||||
|
|
||||||
clientResetScene();
|
clientResetScene();
|
||||||
|
|
||||||
setCameraDistance(26.f);
|
setCameraDistance(56.f);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,13 +176,16 @@ void CharacterDemo::debugDrawContacts()
|
|||||||
// printf("numPairs = %d\n",m_customPairCallback->getOverlappingPairArray().size());
|
// printf("numPairs = %d\n",m_customPairCallback->getOverlappingPairArray().size());
|
||||||
{
|
{
|
||||||
btManifoldArray manifoldArray;
|
btManifoldArray manifoldArray;
|
||||||
for (int i=0;i<m_customPairCallback->getOverlappingPairArray().size();i++)
|
btBroadphasePairArray& pairArray = m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray();
|
||||||
|
int numPairs = pairArray.size();
|
||||||
|
|
||||||
|
for (int i=0;i<numPairs;i++)
|
||||||
{
|
{
|
||||||
manifoldArray.clear();
|
manifoldArray.clear();
|
||||||
|
|
||||||
const btBroadphasePair& pair = m_customPairCallback->getOverlappingPairArray()[i];
|
const btBroadphasePair& pair = pairArray[i];
|
||||||
btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
|
|
||||||
|
|
||||||
|
btBroadphasePair* collisionPair = m_overlappingPairCache->getOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1);
|
||||||
if (!collisionPair)
|
if (!collisionPair)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -546,7 +199,8 @@ void CharacterDemo::debugDrawContacts()
|
|||||||
{
|
{
|
||||||
const btManifoldPoint&pt = manifold->getContactPoint(p);
|
const btManifoldPoint&pt = manifold->getContactPoint(p);
|
||||||
|
|
||||||
m_dynamicsWorld->getDebugDrawer()->drawContactPoint(pt.getPositionWorldOnB(),pt.m_normalWorldOnB,pt.getDistance(),pt.getLifeTime(),btVector3(1.f,1.f,0.f));
|
btVector3 color(255,255,255);
|
||||||
|
m_dynamicsWorld->getDebugDrawer()->drawContactPoint(pt.getPositionWorldOnB(),pt.m_normalWorldOnB,pt.getDistance(),pt.getLifeTime(),color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,7 +299,7 @@ void CharacterDemo::displayCallback(void)
|
|||||||
|
|
||||||
void CharacterDemo::clientResetScene()
|
void CharacterDemo::clientResetScene()
|
||||||
{
|
{
|
||||||
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_character->getCollisionObject()->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
|
m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(m_ghostObject->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
|
||||||
|
|
||||||
m_character->reset ();
|
m_character->reset ();
|
||||||
///WTF
|
///WTF
|
||||||
@@ -741,14 +395,14 @@ void CharacterDemo::updateCamera()
|
|||||||
btTransform characterWorldTrans;
|
btTransform characterWorldTrans;
|
||||||
|
|
||||||
//look at the vehicle
|
//look at the vehicle
|
||||||
characterWorldTrans = m_character->getCollisionObject()->getWorldTransform();
|
characterWorldTrans = m_ghostObject->getWorldTransform();
|
||||||
btVector3 up = characterWorldTrans.getBasis()[1];
|
btVector3 up = characterWorldTrans.getBasis()[1];
|
||||||
btVector3 backward = -characterWorldTrans.getBasis()[2];
|
btVector3 backward = -characterWorldTrans.getBasis()[2];
|
||||||
up.normalize ();
|
up.normalize ();
|
||||||
backward.normalize ();
|
backward.normalize ();
|
||||||
|
|
||||||
m_cameraTargetPosition = characterWorldTrans.getOrigin();
|
m_cameraTargetPosition = characterWorldTrans.getOrigin();
|
||||||
m_cameraPosition = m_cameraTargetPosition + up * 2.0 + backward * 2.0;
|
m_cameraPosition = m_cameraTargetPosition + up * 2.0 + backward * 12.0;
|
||||||
|
|
||||||
//update OpenGL camera settings
|
//update OpenGL camera settings
|
||||||
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);
|
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.0, 10000.0);
|
||||||
@@ -764,3 +418,51 @@ void CharacterDemo::updateCamera()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CharacterDemo::~CharacterDemo()
|
||||||
|
{
|
||||||
|
//cleanup in the reverse order of creation/initialization
|
||||||
|
if (m_character)
|
||||||
|
{
|
||||||
|
m_dynamicsWorld->removeCollisionObject(m_ghostObject);
|
||||||
|
}
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_indexVertexArrays;
|
||||||
|
delete m_vertices;
|
||||||
|
|
||||||
|
//delete dynamics world
|
||||||
|
delete m_dynamicsWorld;
|
||||||
|
|
||||||
|
//delete solver
|
||||||
|
delete m_constraintSolver;
|
||||||
|
|
||||||
|
//delete broadphase
|
||||||
|
delete m_overlappingPairCache;
|
||||||
|
|
||||||
|
//delete dispatcher
|
||||||
|
delete m_dispatcher;
|
||||||
|
|
||||||
|
delete m_collisionConfiguration;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ subject to the following restrictions:
|
|||||||
#define CHARACTER_DEMO_H
|
#define CHARACTER_DEMO_H
|
||||||
|
|
||||||
|
|
||||||
///DYNAMIC_CHARACTER_CONTROLLER is not supported/obsolete at the moment
|
///DYNAMIC_CHARACTER_CONTROLLER is not at the moment
|
||||||
//#define DYNAMIC_CHARACTER_CONTROLLER 1
|
//#define DYNAMIC_CHARACTER_CONTROLLER 1
|
||||||
|
|
||||||
|
#include "BulletCollision/CollisionShapes/btConvexHullShape.h"
|
||||||
|
|
||||||
class CharacterControllerInterface;
|
class CharacterControllerInterface;
|
||||||
class DynamicCharacterController;
|
class DynamicCharacterController;
|
||||||
class KinematicCharacterController;
|
class KinematicCharacterController;
|
||||||
@@ -37,6 +39,7 @@ class CharacterDemo : public DemoApplication
|
|||||||
CharacterControllerInterface* m_character;
|
CharacterControllerInterface* m_character;
|
||||||
#else
|
#else
|
||||||
KinematicCharacterController* m_character;
|
KinematicCharacterController* m_character;
|
||||||
|
class btPairCachingGhostObject* m_ghostObject;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
|
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
|
||||||
@@ -51,8 +54,6 @@ class CharacterDemo : public DemoApplication
|
|||||||
|
|
||||||
class btTriangleIndexVertexArray* m_indexVertexArrays;
|
class btTriangleIndexVertexArray* m_indexVertexArrays;
|
||||||
|
|
||||||
class MyCustomOverlappingPairCallback* m_customPairCallback;
|
|
||||||
|
|
||||||
btVector3* m_vertices;
|
btVector3* m_vertices;
|
||||||
|
|
||||||
void debugDrawContacts();
|
void debugDrawContacts();
|
||||||
@@ -93,6 +94,59 @@ class CharacterDemo : public DemoApplication
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define QUAKE_BSP_IMPORTING 1
|
||||||
|
#ifdef QUAKE_BSP_IMPORTING
|
||||||
|
#include "../BspDemo/BspLoader.h"
|
||||||
|
#include "../BspDemo/BspConverter.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BspToBulletConverter : public BspConverter
|
||||||
|
{
|
||||||
|
CharacterDemo* m_demoApp;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
BspToBulletConverter(CharacterDemo* demoApp)
|
||||||
|
:m_demoApp(demoApp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void addConvexVerticesCollider(btAlignedObjectArray<btVector3>& vertices, bool isEntity, const btVector3& entityTargetLocation)
|
||||||
|
{
|
||||||
|
///perhaps we can do something special with entities (isEntity)
|
||||||
|
///like adding a collision Triggering (as example)
|
||||||
|
|
||||||
|
if (vertices.size() > 0)
|
||||||
|
{
|
||||||
|
float mass = 0.f;
|
||||||
|
btTransform startTransform;
|
||||||
|
//can use a shift
|
||||||
|
startTransform.setIdentity();
|
||||||
|
startTransform.setOrigin(btVector3(0,-10.0f,0.0f));
|
||||||
|
//this create an internal copy of the vertices
|
||||||
|
for (int i = 0; i < vertices.size(); i++)
|
||||||
|
{
|
||||||
|
vertices[i] *= btScalar(0.5);
|
||||||
|
float t = vertices[i].getZ() * btScalar(0.75);
|
||||||
|
vertices[i].setZ(-vertices[i].getY());
|
||||||
|
vertices[i].setY(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
btCollisionShape* shape = new btConvexHullShape(&(vertices[0].getX()),vertices.size());
|
||||||
|
m_demoApp->m_collisionShapes.push_back(shape);
|
||||||
|
|
||||||
|
//btRigidBody* body = m_demoApp->localCreateRigidBody(mass, startTransform,shape);
|
||||||
|
m_demoApp->localCreateRigidBody(mass, startTransform,shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif //QUAKE_BSP_IMPORTING
|
||||||
|
|
||||||
|
|
||||||
#endif //CHARACTER_DEMO_H
|
#endif //CHARACTER_DEMO_H
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
#include "GLDebugDrawer.h"
|
#include "GLDebugDrawer.h"
|
||||||
|
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
|
||||||
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
||||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
||||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||||
@@ -81,85 +81,42 @@ btVector3 perpindicularComponent (const btVector3& direction, const btVector3& n
|
|||||||
return direction - parallelComponent(direction, normal);
|
return direction - parallelComponent(direction, normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
KinematicCharacterController::KinematicCharacterController ()
|
KinematicCharacterController::KinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight)
|
||||||
{
|
{
|
||||||
|
m_useGhostObjectSweepTest = true;
|
||||||
|
m_ghostObject = ghostObject;
|
||||||
|
m_stepHeight = stepHeight;
|
||||||
m_turnAngle = btScalar(0.0);
|
m_turnAngle = btScalar(0.0);
|
||||||
m_walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
|
m_walkVelocity = btScalar(1.1) * 4.0; // 4 km/h -> 1.1 m/s
|
||||||
m_shape = NULL;
|
m_convexShape=convexShape;
|
||||||
m_pairCache = NULL;
|
|
||||||
m_collisionObject = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KinematicCharacterController::~KinematicCharacterController ()
|
KinematicCharacterController::~KinematicCharacterController ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::setup (btScalar height, btScalar width, btScalar stepHeight)
|
|
||||||
|
btPairCachingGhostObject* KinematicCharacterController::getGhostObject()
|
||||||
{
|
{
|
||||||
btVector3 spherePositions[2];
|
return m_ghostObject;
|
||||||
btScalar sphereRadii[2];
|
|
||||||
|
|
||||||
sphereRadii[0] = width;
|
|
||||||
sphereRadii[1] = width;
|
|
||||||
spherePositions[0] = btVector3 (0.0, (height/btScalar(2.0) ), 0.0);
|
|
||||||
spherePositions[1] = btVector3 (0.0, (-height/btScalar(2.0)), 0.0);
|
|
||||||
|
|
||||||
m_halfHeight = height/btScalar(2.0);
|
|
||||||
|
|
||||||
m_shape = new btMultiSphereShape (btVector3(width/btScalar(2.0), height/btScalar(2.0), width/btScalar(2.0)), &spherePositions[0], &sphereRadii[0], 2);
|
|
||||||
m_stepHeight = stepHeight;
|
|
||||||
m_height = height;
|
|
||||||
m_width = width;
|
|
||||||
btTransform startTransform;
|
|
||||||
startTransform.setIdentity ();
|
|
||||||
startTransform.setOrigin (btVector3(0.0, 4.0, 0.0));
|
|
||||||
//btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
|
||||||
|
|
||||||
m_collisionObject = new btCollisionObject ();
|
|
||||||
|
|
||||||
m_collisionObject->setWorldTransform(startTransform);
|
|
||||||
m_collisionObject->setCollisionShape (m_shape);
|
|
||||||
m_collisionObject->setCollisionFlags (btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::destroy ()
|
bool KinematicCharacterController::recoverFromPenetration (btCollisionWorld* collisionWorld)
|
||||||
{
|
{
|
||||||
if (m_collisionObject)
|
|
||||||
{
|
|
||||||
delete m_collisionObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_shape)
|
|
||||||
{
|
|
||||||
delete m_shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
btCollisionObject* KinematicCharacterController::getCollisionObject ()
|
|
||||||
{
|
|
||||||
return m_collisionObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KinematicCharacterController::recoverFromPenetration (const btCollisionWorld* collisionWorld)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (m_pairCache == NULL)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool penetration = false;
|
bool penetration = false;
|
||||||
|
|
||||||
|
collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher());
|
||||||
|
|
||||||
m_dispatcher->dispatchAllCollisionPairs (m_pairCache, collisionWorld->getDispatchInfo(), m_dispatcher);
|
m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||||
|
|
||||||
m_currentPosition = m_collisionObject->getWorldTransform().getOrigin();
|
|
||||||
|
|
||||||
btScalar maxPen = btScalar(0.0);
|
btScalar maxPen = btScalar(0.0);
|
||||||
for (int i = 0; i < m_pairCache->getNumOverlappingPairs(); i++)
|
for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
|
||||||
{
|
{
|
||||||
m_manifoldArray.resize(0);
|
m_manifoldArray.resize(0);
|
||||||
|
|
||||||
btBroadphasePair* collisionPair = &m_pairCache->getOverlappingPairArray()[i];
|
btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||||
|
|
||||||
if (collisionPair->m_algorithm)
|
if (collisionPair->m_algorithm)
|
||||||
collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
|
collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
|
||||||
@@ -168,7 +125,7 @@ bool KinematicCharacterController::recoverFromPenetration (const btCollisionWorl
|
|||||||
for (int j=0;j<m_manifoldArray.size();j++)
|
for (int j=0;j<m_manifoldArray.size();j++)
|
||||||
{
|
{
|
||||||
btPersistentManifold* manifold = m_manifoldArray[j];
|
btPersistentManifold* manifold = m_manifoldArray[j];
|
||||||
btScalar directionSign = manifold->getBody0() == m_collisionObject ? btScalar(-1.0) : btScalar(1.0);
|
btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0);
|
||||||
for (int p=0;p<manifold->getNumContacts();p++)
|
for (int p=0;p<manifold->getNumContacts();p++)
|
||||||
{
|
{
|
||||||
const btManifoldPoint&pt = manifold->getContactPoint(p);
|
const btManifoldPoint&pt = manifold->getContactPoint(p);
|
||||||
@@ -191,14 +148,14 @@ bool KinematicCharacterController::recoverFromPenetration (const btCollisionWorl
|
|||||||
//manifold->clearManifold();
|
//manifold->clearManifold();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
btTransform newTrans = m_collisionObject->getWorldTransform();
|
btTransform newTrans = m_ghostObject->getWorldTransform();
|
||||||
newTrans.setOrigin(m_currentPosition);
|
newTrans.setOrigin(m_currentPosition);
|
||||||
m_collisionObject->setWorldTransform(newTrans);
|
m_ghostObject->setWorldTransform(newTrans);
|
||||||
// printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
|
// printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]);
|
||||||
return penetration;
|
return penetration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::stepUp (const btCollisionWorld* world)
|
void KinematicCharacterController::stepUp ( btCollisionWorld* world)
|
||||||
{
|
{
|
||||||
// phase 1: up
|
// phase 1: up
|
||||||
btTransform start, end;
|
btTransform start, end;
|
||||||
@@ -211,11 +168,18 @@ void KinematicCharacterController::stepUp (const btCollisionWorld* world)
|
|||||||
start.setOrigin (m_currentPosition + btVector3(btScalar(0.0), btScalar(0.1), btScalar(0.0)));
|
start.setOrigin (m_currentPosition + btVector3(btScalar(0.0), btScalar(0.1), btScalar(0.0)));
|
||||||
end.setOrigin (m_targetPosition);
|
end.setOrigin (m_targetPosition);
|
||||||
|
|
||||||
ClosestNotMeConvexResultCallback callback (m_collisionObject);
|
ClosestNotMeConvexResultCallback callback (m_ghostObject);
|
||||||
callback.m_collisionFilterGroup = getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
callback.m_collisionFilterMask = getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
|
|
||||||
world->convexSweepTest (m_shape, start, end, callback);
|
if (m_useGhostObjectSweepTest)
|
||||||
|
{
|
||||||
|
m_ghostObject->convexSweepTest (m_convexShape, start, end, world->getDispatchInfo().m_allowedCcdPenetration,callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
world->convexSweepTest (m_convexShape, start, end, callback);
|
||||||
|
}
|
||||||
|
|
||||||
if (callback.hasHit())
|
if (callback.hasHit())
|
||||||
{
|
{
|
||||||
@@ -264,7 +228,7 @@ void KinematicCharacterController::updateTargetPositionBasedOnCollision (const b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::stepForwardAndStrafe (const btCollisionWorld* collisionWorld, const btVector3& walkMove)
|
void KinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove)
|
||||||
{
|
{
|
||||||
|
|
||||||
btVector3 originalDir = walkMove.normalized();
|
btVector3 originalDir = walkMove.normalized();
|
||||||
@@ -296,15 +260,23 @@ void KinematicCharacterController::stepForwardAndStrafe (const btCollisionWorld*
|
|||||||
start.setOrigin (m_currentPosition);
|
start.setOrigin (m_currentPosition);
|
||||||
end.setOrigin (m_targetPosition);
|
end.setOrigin (m_targetPosition);
|
||||||
|
|
||||||
ClosestNotMeConvexResultCallback callback (m_collisionObject);
|
ClosestNotMeConvexResultCallback callback (m_ghostObject);
|
||||||
callback.m_collisionFilterGroup = getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
callback.m_collisionFilterMask = getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
|
|
||||||
|
|
||||||
//btScalar margin = m_shape->getMargin();
|
//btScalar margin = m_convexShape->getMargin();
|
||||||
//m_shape->setMargin(margin - 0.06f);
|
//m_convexShape->setMargin(margin - 0.06f);
|
||||||
collisionWorld->convexSweepTest (m_shape, start, end, callback);
|
|
||||||
//m_shape->setMargin(margin);
|
if (m_useGhostObjectSweepTest)
|
||||||
|
{
|
||||||
|
m_ghostObject->convexSweepTest (m_convexShape, start, end, collisionWorld->getDispatchInfo().m_allowedCcdPenetration,callback);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
collisionWorld->convexSweepTest (m_convexShape, start, end, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
//m_convexShape->setMargin(margin);
|
||||||
|
|
||||||
|
|
||||||
fraction -= callback.m_closestHitFraction;
|
fraction -= callback.m_closestHitFraction;
|
||||||
@@ -352,7 +324,7 @@ void KinematicCharacterController::stepForwardAndStrafe (const btCollisionWorld*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::stepDown (const btCollisionWorld* collisionWorld, btScalar dt)
|
void KinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt)
|
||||||
{
|
{
|
||||||
btTransform start, end;
|
btTransform start, end;
|
||||||
|
|
||||||
@@ -367,11 +339,17 @@ void KinematicCharacterController::stepDown (const btCollisionWorld* collisionWo
|
|||||||
start.setOrigin (m_currentPosition);
|
start.setOrigin (m_currentPosition);
|
||||||
end.setOrigin (m_targetPosition);
|
end.setOrigin (m_targetPosition);
|
||||||
|
|
||||||
ClosestNotMeConvexResultCallback callback (m_collisionObject);
|
ClosestNotMeConvexResultCallback callback (m_ghostObject);
|
||||||
callback.m_collisionFilterGroup = getCollisionObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
callback.m_collisionFilterMask = getCollisionObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||||
|
|
||||||
collisionWorld->convexSweepTest (m_shape, start, end, callback);
|
if (m_useGhostObjectSweepTest)
|
||||||
|
{
|
||||||
|
m_ghostObject->convexSweepTest (m_convexShape, start, end, collisionWorld->getDispatchInfo().m_allowedCcdPenetration,callback);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
collisionWorld->convexSweepTest (m_convexShape, start, end, callback);
|
||||||
|
}
|
||||||
|
|
||||||
if (callback.hasHit())
|
if (callback.hasHit())
|
||||||
{
|
{
|
||||||
@@ -393,16 +371,11 @@ void KinematicCharacterController::warp (const btVector3& origin)
|
|||||||
btTransform xform;
|
btTransform xform;
|
||||||
xform.setIdentity();
|
xform.setIdentity();
|
||||||
xform.setOrigin (origin);
|
xform.setOrigin (origin);
|
||||||
m_collisionObject->setWorldTransform (xform);
|
m_ghostObject->setWorldTransform (xform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::registerPairCacheAndDispatcher (btOverlappingPairCache* pairCache, btCollisionDispatcher* dispatcher)
|
|
||||||
{
|
|
||||||
m_pairCache = pairCache;
|
|
||||||
m_dispatcher = dispatcher;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KinematicCharacterController::preStep (const btCollisionWorld* collisionWorld)
|
void KinematicCharacterController::preStep ( btCollisionWorld* collisionWorld)
|
||||||
{
|
{
|
||||||
|
|
||||||
int numPenetrationLoops = 0;
|
int numPenetrationLoops = 0;
|
||||||
@@ -418,7 +391,7 @@ void KinematicCharacterController::preStep (const btCollisionWorld* collisionWor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
btTransform xform;
|
btTransform xform;
|
||||||
xform = m_collisionObject->getWorldTransform ();
|
xform = m_ghostObject->getWorldTransform ();
|
||||||
|
|
||||||
btVector3 forwardDir = xform.getBasis()[2];
|
btVector3 forwardDir = xform.getBasis()[2];
|
||||||
// printf("forwardDir=%f,%f,%f\n",forwardDir[0],forwardDir[1],forwardDir[2]);
|
// printf("forwardDir=%f,%f,%f\n",forwardDir[0],forwardDir[1],forwardDir[2]);
|
||||||
@@ -439,7 +412,7 @@ void KinematicCharacterController::preStep (const btCollisionWorld* collisionWor
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::playerStep (const btCollisionWorld* collisionWorld,
|
void KinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld,
|
||||||
btScalar dt,
|
btScalar dt,
|
||||||
int forward,
|
int forward,
|
||||||
int backward,
|
int backward,
|
||||||
@@ -463,7 +436,7 @@ void KinematicCharacterController::playerStep (const btCollisionWorld* collision
|
|||||||
walkDirection -= m_forwardDirection;
|
walkDirection -= m_forwardDirection;
|
||||||
|
|
||||||
btTransform xform;
|
btTransform xform;
|
||||||
xform = m_collisionObject->getWorldTransform ();
|
xform = m_ghostObject->getWorldTransform ();
|
||||||
|
|
||||||
// printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
|
// printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
|
||||||
// printf("walkSpeed=%f\n",walkSpeed);
|
// printf("walkSpeed=%f\n",walkSpeed);
|
||||||
@@ -473,7 +446,7 @@ void KinematicCharacterController::playerStep (const btCollisionWorld* collision
|
|||||||
stepDown (collisionWorld, dt);
|
stepDown (collisionWorld, dt);
|
||||||
|
|
||||||
xform.setOrigin (m_currentPosition);
|
xform.setOrigin (m_currentPosition);
|
||||||
m_collisionObject->setWorldTransform (xform);
|
m_ghostObject->setWorldTransform (xform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KinematicCharacterController::setFallSpeed (btScalar fallSpeed)
|
void KinematicCharacterController::setFallSpeed (btScalar fallSpeed)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class btCollisionShape;
|
|||||||
class btRigidBody;
|
class btRigidBody;
|
||||||
class btCollisionWorld;
|
class btCollisionWorld;
|
||||||
class btCollisionDispatcher;
|
class btCollisionDispatcher;
|
||||||
|
class btPairCachingGhostObject;
|
||||||
|
|
||||||
///KinematicCharacterController is a collision object with support for sliding motion in a world.
|
///KinematicCharacterController is a collision object with support for sliding motion in a world.
|
||||||
///It uses the convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.
|
///It uses the convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.
|
||||||
@@ -18,10 +18,9 @@ class KinematicCharacterController : public CharacterControllerInterface
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
btScalar m_halfHeight;
|
btScalar m_halfHeight;
|
||||||
btConvexShape* m_shape;
|
|
||||||
btCollisionObject* m_collisionObject;
|
btPairCachingGhostObject* m_ghostObject;
|
||||||
btOverlappingPairCache* m_pairCache;
|
btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast
|
||||||
btCollisionDispatcher* m_dispatcher;
|
|
||||||
|
|
||||||
btScalar m_fallSpeed;
|
btScalar m_fallSpeed;
|
||||||
btScalar m_jumpSpeed;
|
btScalar m_jumpSpeed;
|
||||||
@@ -30,8 +29,6 @@ protected:
|
|||||||
btScalar m_turnAngle;
|
btScalar m_turnAngle;
|
||||||
btScalar m_walkVelocity;
|
btScalar m_walkVelocity;
|
||||||
|
|
||||||
btScalar m_height;
|
|
||||||
btScalar m_width;
|
|
||||||
btScalar m_stepHeight;
|
btScalar m_stepHeight;
|
||||||
|
|
||||||
btVector3 m_upDirection;
|
btVector3 m_upDirection;
|
||||||
@@ -47,25 +44,25 @@ protected:
|
|||||||
bool m_touchingContact;
|
bool m_touchingContact;
|
||||||
btVector3 m_touchingNormal;
|
btVector3 m_touchingNormal;
|
||||||
|
|
||||||
bool recoverFromPenetration (const btCollisionWorld* collisionWorld);
|
bool m_useGhostObjectSweepTest;
|
||||||
void stepUp (const btCollisionWorld* collisionWorld);
|
|
||||||
void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
|
|
||||||
void stepForwardAndStrafe (const btCollisionWorld* collisionWorld, const btVector3& walkMove);
|
|
||||||
void stepDown (const btCollisionWorld* collisionWorld, btScalar dt);
|
|
||||||
public:
|
|
||||||
KinematicCharacterController ();
|
|
||||||
~KinematicCharacterController ();
|
|
||||||
void setup (btScalar height = btScalar(1.75), btScalar width = btScalar(0.4), btScalar stepHeight = btScalar(0.35));
|
|
||||||
void destroy ();
|
|
||||||
|
|
||||||
btCollisionObject* getCollisionObject ();
|
bool recoverFromPenetration (btCollisionWorld* collisionWorld);
|
||||||
|
void stepUp (btCollisionWorld* collisionWorld);
|
||||||
|
void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
|
||||||
|
void stepForwardAndStrafe (btCollisionWorld* collisionWorld, const btVector3& walkMove);
|
||||||
|
void stepDown (btCollisionWorld* collisionWorld, btScalar dt);
|
||||||
|
public:
|
||||||
|
KinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight);
|
||||||
|
~KinematicCharacterController ();
|
||||||
|
|
||||||
|
|
||||||
|
btPairCachingGhostObject* getGhostObject();
|
||||||
|
|
||||||
void reset ();
|
void reset ();
|
||||||
void warp (const btVector3& origin);
|
void warp (const btVector3& origin);
|
||||||
|
|
||||||
virtual void registerPairCacheAndDispatcher (btOverlappingPairCache* pairCache, btCollisionDispatcher* dispatcher);
|
void preStep ( btCollisionWorld* collisionWorld);
|
||||||
void preStep (const btCollisionWorld* collisionWorld);
|
void playerStep (btCollisionWorld* collisionWorld, btScalar dt,
|
||||||
void playerStep (const btCollisionWorld* collisionWorld, btScalar dt,
|
|
||||||
int forward,
|
int forward,
|
||||||
int backward,
|
int backward,
|
||||||
int left,
|
int left,
|
||||||
@@ -77,6 +74,10 @@ public:
|
|||||||
void setMaxJumpHeight (btScalar maxJumpHeight);
|
void setMaxJumpHeight (btScalar maxJumpHeight);
|
||||||
bool canJump () const;
|
bool canJump () const;
|
||||||
void jump ();
|
void jump ();
|
||||||
|
void setUseGhostSweepTest(bool useGhostObjectSweepTest)
|
||||||
|
{
|
||||||
|
m_useGhostObjectSweepTest = useGhostObjectSweepTest;
|
||||||
|
}
|
||||||
|
|
||||||
bool onGround () const;
|
bool onGround () const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btV
|
|||||||
// if (m_debugMode > 0)
|
// if (m_debugMode > 0)
|
||||||
{
|
{
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glColor3f(color.getX(), color.getY(), color.getZ());
|
glColor4f(color.getX(), color.getY(), color.getZ(),1.f);
|
||||||
glVertex3d(from.getX(), from.getY(), from.getZ());
|
glVertex3d(from.getX(), from.getY(), from.getZ());
|
||||||
glVertex3d(to.getX(), to.getY(), to.getZ());
|
glVertex3d(to.getX(), to.getY(), to.getZ());
|
||||||
glEnd();
|
glEnd();
|
||||||
@@ -72,8 +72,10 @@ void GLDebugDrawer::drawContactPoint(const btVector3& pointOnB,const btVector3&
|
|||||||
{
|
{
|
||||||
btVector3 to=pointOnB+normalOnB*distance;
|
btVector3 to=pointOnB+normalOnB*distance;
|
||||||
const btVector3&from = pointOnB;
|
const btVector3&from = pointOnB;
|
||||||
|
glColor4f(color.getX(), color.getY(), color.getZ(),1.f);
|
||||||
|
//glColor4f(0,0,0,1.f);
|
||||||
|
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glColor3f(color.getX(), color.getY(), color.getZ());
|
|
||||||
glVertex3d(from.getX(), from.getY(), from.getZ());
|
glVertex3d(from.getX(), from.getY(), from.getZ());
|
||||||
glVertex3d(to.getX(), to.getY(), to.getZ());
|
glVertex3d(to.getX(), to.getY(), to.getZ());
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ int gFindPairs =0;
|
|||||||
|
|
||||||
btHashedOverlappingPairCache::btHashedOverlappingPairCache():
|
btHashedOverlappingPairCache::btHashedOverlappingPairCache():
|
||||||
m_overlapFilterCallback(0),
|
m_overlapFilterCallback(0),
|
||||||
m_blockedForChanges(false)
|
m_blockedForChanges(false),
|
||||||
|
m_ghostPairCallback(0)
|
||||||
{
|
{
|
||||||
int initialAllocatedSize= 2;
|
int initialAllocatedSize= 2;
|
||||||
m_overlappingPairArray.reserve(initialAllocatedSize);
|
m_overlappingPairArray.reserve(initialAllocatedSize);
|
||||||
@@ -238,6 +239,11 @@ btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProx
|
|||||||
int count = m_overlappingPairArray.size();
|
int count = m_overlappingPairArray.size();
|
||||||
int oldCapacity = m_overlappingPairArray.capacity();
|
int oldCapacity = m_overlappingPairArray.capacity();
|
||||||
void* mem = &m_overlappingPairArray.expand();
|
void* mem = &m_overlappingPairArray.expand();
|
||||||
|
|
||||||
|
//this is where we add an actual pair, so also call the 'ghost'
|
||||||
|
if (m_ghostPairCallback)
|
||||||
|
m_ghostPairCallback->addOverlappingPair(proxy0,proxy1);
|
||||||
|
|
||||||
int newCapacity = m_overlappingPairArray.capacity();
|
int newCapacity = m_overlappingPairArray.capacity();
|
||||||
|
|
||||||
if (oldCapacity < newCapacity)
|
if (oldCapacity < newCapacity)
|
||||||
@@ -317,6 +323,9 @@ void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro
|
|||||||
|
|
||||||
int lastPairIndex = m_overlappingPairArray.size() - 1;
|
int lastPairIndex = m_overlappingPairArray.size() - 1;
|
||||||
|
|
||||||
|
if (m_ghostPairCallback)
|
||||||
|
m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher);
|
||||||
|
|
||||||
// If the removed pair is the last pair, we are done.
|
// If the removed pair is the last pair, we are done.
|
||||||
if (lastPairIndex == pairIndex)
|
if (lastPairIndex == pairIndex)
|
||||||
{
|
{
|
||||||
@@ -399,6 +408,8 @@ void* btSortedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro
|
|||||||
btBroadphasePair& pair = m_overlappingPairArray[findIndex];
|
btBroadphasePair& pair = m_overlappingPairArray[findIndex];
|
||||||
void* userData = pair.m_userInfo;
|
void* userData = pair.m_userInfo;
|
||||||
cleanOverlappingPair(pair,dispatcher);
|
cleanOverlappingPair(pair,dispatcher);
|
||||||
|
if (m_ghostPairCallback)
|
||||||
|
m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher);
|
||||||
|
|
||||||
m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1);
|
m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1);
|
||||||
m_overlappingPairArray.pop_back();
|
m_overlappingPairArray.pop_back();
|
||||||
@@ -426,8 +437,12 @@ btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseP
|
|||||||
|
|
||||||
void* mem = &m_overlappingPairArray.expand();
|
void* mem = &m_overlappingPairArray.expand();
|
||||||
btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1);
|
btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1);
|
||||||
|
|
||||||
gOverlappingPairs++;
|
gOverlappingPairs++;
|
||||||
gAddedPairs++;
|
gAddedPairs++;
|
||||||
|
|
||||||
|
if (m_ghostPairCallback)
|
||||||
|
m_ghostPairCallback->addOverlappingPair(proxy0, proxy1);
|
||||||
return pair;
|
return pair;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -493,7 +508,8 @@ void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback*
|
|||||||
btSortedOverlappingPairCache::btSortedOverlappingPairCache():
|
btSortedOverlappingPairCache::btSortedOverlappingPairCache():
|
||||||
m_blockedForChanges(false),
|
m_blockedForChanges(false),
|
||||||
m_hasDeferredRemoval(true),
|
m_hasDeferredRemoval(true),
|
||||||
m_overlapFilterCallback(0)
|
m_overlapFilterCallback(0),
|
||||||
|
m_ghostPairCallback(0)
|
||||||
{
|
{
|
||||||
int initialAllocatedSize= 2;
|
int initialAllocatedSize= 2;
|
||||||
m_overlappingPairArray.reserve(initialAllocatedSize);
|
m_overlappingPairArray.reserve(initialAllocatedSize);
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ public:
|
|||||||
|
|
||||||
virtual bool hasDeferredRemoval() = 0;
|
virtual bool hasDeferredRemoval() = 0;
|
||||||
|
|
||||||
|
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)=0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com
|
/// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com
|
||||||
@@ -253,10 +255,16 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)
|
||||||
|
{
|
||||||
|
m_ghostPairCallback = ghostPairCallback;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
btAlignedObjectArray<int> m_hashTable;
|
btAlignedObjectArray<int> m_hashTable;
|
||||||
btAlignedObjectArray<int> m_next;
|
btAlignedObjectArray<int> m_next;
|
||||||
|
btOverlappingPairCallback* m_ghostPairCallback;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -280,6 +288,8 @@ class btSortedOverlappingPairCache : public btOverlappingPairCache
|
|||||||
//if set, use the callback instead of the built in filter in needBroadphaseCollision
|
//if set, use the callback instead of the built in filter in needBroadphaseCollision
|
||||||
btOverlapFilterCallback* m_overlapFilterCallback;
|
btOverlapFilterCallback* m_overlapFilterCallback;
|
||||||
|
|
||||||
|
btOverlappingPairCallback* m_ghostPairCallback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
btSortedOverlappingPairCache();
|
btSortedOverlappingPairCache();
|
||||||
@@ -355,12 +365,17 @@ class btSortedOverlappingPairCache : public btOverlappingPairCache
|
|||||||
return m_hasDeferredRemoval;
|
return m_hasDeferredRemoval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)
|
||||||
|
{
|
||||||
|
m_ghostPairCallback = ghostPairCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and testing.
|
///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and unit testing.
|
||||||
class btNullPairCache : public btOverlappingPairCache
|
class btNullPairCache : public btOverlappingPairCache
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -414,6 +429,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/)
|
virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -429,6 +448,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ subject to the following restrictions:
|
|||||||
#define COLLISION_CREATE_FUNC
|
#define COLLISION_CREATE_FUNC
|
||||||
|
|
||||||
#include "LinearMath/btAlignedObjectArray.h"
|
#include "LinearMath/btAlignedObjectArray.h"
|
||||||
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray;
|
|
||||||
class btCollisionAlgorithm;
|
class btCollisionAlgorithm;
|
||||||
class btCollisionObject;
|
class btCollisionObject;
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,11 @@ struct btBroadphaseProxy;
|
|||||||
class btCollisionShape;
|
class btCollisionShape;
|
||||||
#include "LinearMath/btMotionState.h"
|
#include "LinearMath/btMotionState.h"
|
||||||
#include "LinearMath/btAlignedAllocator.h"
|
#include "LinearMath/btAlignedAllocator.h"
|
||||||
|
#include "LinearMath/btAlignedObjectArray.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef btAlignedObjectArray<class btCollisionObject*> btCollisionObjectArray;
|
||||||
|
|
||||||
|
|
||||||
/// btCollisionObject can be used to manage collision detection objects.
|
/// btCollisionObject can be used to manage collision detection objects.
|
||||||
/// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy.
|
/// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy.
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class btBroadphaseInterface;
|
|||||||
#include "LinearMath/btVector3.h"
|
#include "LinearMath/btVector3.h"
|
||||||
#include "LinearMath/btTransform.h"
|
#include "LinearMath/btTransform.h"
|
||||||
#include "btCollisionObject.h"
|
#include "btCollisionObject.h"
|
||||||
#include "btCollisionDispatcher.h" //for definition of btCollisionObjectArray
|
#include "btCollisionDispatcher.h"
|
||||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
||||||
#include "LinearMath/btAlignedObjectArray.h"
|
#include "LinearMath/btAlignedObjectArray.h"
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,149 @@ subject to the following restrictions:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "btGhostObject.h"
|
#include "btGhostObject.h"
|
||||||
|
#include "btCollisionWorld.h"
|
||||||
|
#include "BulletCollision/CollisionShapes/btConvexShape.h"
|
||||||
|
#include "LinearMath/btAabbUtil2.h"
|
||||||
|
|
||||||
btGhostObject::btGhostObject()
|
btGhostObject::btGhostObject()
|
||||||
{
|
{
|
||||||
m_internalType = CO_GHOST_OBJECT;
|
m_internalType = CO_GHOST_OBJECT;
|
||||||
|
|
||||||
m_overlappingPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
|
|
||||||
m_overlappingPairCache->setOverlapFilterCallback(&m_ghostOverlapFilterCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
btGhostObject::~btGhostObject()
|
btGhostObject::~btGhostObject()
|
||||||
{
|
{
|
||||||
btAlignedFree(m_overlappingPairCache);
|
///btGhostObject should have been removed from the world, so no overlapping objects
|
||||||
|
btAssert(!m_overlappingObjects.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void btGhostObject::addOverlappingObject(btBroadphaseProxy* otherProxy)
|
||||||
|
{
|
||||||
|
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
|
||||||
|
btAssert(otherObject);
|
||||||
|
int index = m_overlappingObjects.findLinearSearch(otherObject);
|
||||||
|
if (index==m_overlappingObjects.size())
|
||||||
|
{
|
||||||
|
m_overlappingObjects.push_back(otherObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void btGhostObject::removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher)
|
||||||
|
{
|
||||||
|
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
|
||||||
|
btAssert(otherObject);
|
||||||
|
int index = m_overlappingObjects.findLinearSearch(otherObject);
|
||||||
|
if (index<m_overlappingObjects.size())
|
||||||
|
{
|
||||||
|
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1];
|
||||||
|
m_overlappingObjects.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
btPairCachingGhostObject::btPairCachingGhostObject()
|
||||||
|
{
|
||||||
|
m_hashPairCache = new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
btPairCachingGhostObject::~btPairCachingGhostObject()
|
||||||
|
{
|
||||||
|
btAlignedFree( m_hashPairCache );
|
||||||
|
}
|
||||||
|
|
||||||
|
void btPairCachingGhostObject::addOverlappingObject(btBroadphaseProxy* otherProxy)
|
||||||
|
{
|
||||||
|
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
|
||||||
|
btAssert(otherObject);
|
||||||
|
int index = m_overlappingObjects.findLinearSearch(otherObject);
|
||||||
|
if (index==m_overlappingObjects.size())
|
||||||
|
{
|
||||||
|
m_overlappingObjects.push_back(otherObject);
|
||||||
|
m_hashPairCache->addOverlappingPair(getBroadphaseHandle(),otherProxy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void btPairCachingGhostObject::removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher)
|
||||||
|
{
|
||||||
|
btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject;
|
||||||
|
btAssert(otherObject);
|
||||||
|
int index = m_overlappingObjects.findLinearSearch(otherObject);
|
||||||
|
if (index<m_overlappingObjects.size())
|
||||||
|
{
|
||||||
|
m_overlappingObjects[index] = m_overlappingObjects[m_overlappingObjects.size()-1];
|
||||||
|
m_overlappingObjects.pop_back();
|
||||||
|
m_hashPairCache->removeOverlappingPair(getBroadphaseHandle(),otherProxy,dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void btGhostObject::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btScalar allowedCcdPenetration, btCollisionWorld::ConvexResultCallback& resultCallback) const
|
||||||
|
{
|
||||||
|
btTransform convexFromTrans,convexToTrans;
|
||||||
|
convexFromTrans = convexFromWorld;
|
||||||
|
convexToTrans = convexToWorld;
|
||||||
|
btVector3 castShapeAabbMin, castShapeAabbMax;
|
||||||
|
/* Compute AABB that encompasses angular movement */
|
||||||
|
{
|
||||||
|
btVector3 linVel, angVel;
|
||||||
|
btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel);
|
||||||
|
btTransform R;
|
||||||
|
R.setIdentity ();
|
||||||
|
R.setRotation (convexFromTrans.getRotation());
|
||||||
|
castShape->calculateTemporalAabb (R, linVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// go over all objects, and if the ray intersects their aabb + cast shape aabb,
|
||||||
|
// do a ray-shape query using convexCaster (CCD)
|
||||||
|
int i;
|
||||||
|
for (i=0;i<m_overlappingObjects.size();i++)
|
||||||
|
{
|
||||||
|
btCollisionObject* collisionObject= m_overlappingObjects[i];
|
||||||
|
//only perform raycast if filterMask matches
|
||||||
|
if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) {
|
||||||
|
//RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject();
|
||||||
|
btVector3 collisionObjectAabbMin,collisionObjectAabbMax;
|
||||||
|
collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax);
|
||||||
|
AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax);
|
||||||
|
btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing
|
||||||
|
btVector3 hitNormal;
|
||||||
|
if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal))
|
||||||
|
{
|
||||||
|
btCollisionWorld::objectQuerySingle(castShape, convexFromTrans,convexToTrans,
|
||||||
|
collisionObject,
|
||||||
|
collisionObject->getCollisionShape(),
|
||||||
|
collisionObject->getWorldTransform(),
|
||||||
|
resultCallback,
|
||||||
|
allowedCcdPenetration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void btGhostObject::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const
|
||||||
|
{
|
||||||
|
btTransform rayFromTrans;
|
||||||
|
rayFromTrans.setIdentity();
|
||||||
|
rayFromTrans.setOrigin(rayFromWorld);
|
||||||
|
btTransform rayToTrans;
|
||||||
|
rayToTrans.setIdentity();
|
||||||
|
rayToTrans.setOrigin(rayToWorld);
|
||||||
|
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i=0;i<m_overlappingObjects.size();i++)
|
||||||
|
{
|
||||||
|
btCollisionObject* collisionObject= m_overlappingObjects[i];
|
||||||
|
//only perform raycast if filterMask matches
|
||||||
|
if(resultCallback.needsCollision(collisionObject->getBroadphaseHandle()))
|
||||||
|
{
|
||||||
|
btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,
|
||||||
|
collisionObject,
|
||||||
|
collisionObject->getCollisionShape(),
|
||||||
|
collisionObject->getWorldTransform(),
|
||||||
|
resultCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,11 @@ subject to the following restrictions:
|
|||||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h"
|
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h"
|
||||||
#include "LinearMath/btAlignedAllocator.h"
|
#include "LinearMath/btAlignedAllocator.h"
|
||||||
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
|
||||||
|
#include "btCollisionWorld.h"
|
||||||
|
|
||||||
///work-in-progress, not complete
|
class btConvexShape;
|
||||||
|
|
||||||
|
class btDispatcher;
|
||||||
|
|
||||||
///The btGhostObject can keep track of all objects that are overlapping
|
///The btGhostObject can keep track of all objects that are overlapping
|
||||||
///By default, this overlap is based on the AABB
|
///By default, this overlap is based on the AABB
|
||||||
@@ -32,20 +35,7 @@ ATTRIBUTE_ALIGNED16(class) btGhostObject : public btCollisionObject
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
btOverlappingPairCache* m_overlappingPairCache;
|
btAlignedObjectArray<btCollisionObject*> m_overlappingObjects;
|
||||||
|
|
||||||
struct btGhostOverlapFilterCallback : public btOverlapFilterCallback
|
|
||||||
{
|
|
||||||
bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const
|
|
||||||
{
|
|
||||||
bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
|
|
||||||
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
|
|
||||||
return collides;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
btGhostOverlapFilterCallback m_ghostOverlapFilterCallback;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -53,33 +43,41 @@ public:
|
|||||||
|
|
||||||
virtual ~btGhostObject();
|
virtual ~btGhostObject();
|
||||||
|
|
||||||
|
void convexSweepTest(const class btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btScalar allowedCcdPenetration,btCollisionWorld::ConvexResultCallback& resultCallback) const;
|
||||||
|
|
||||||
virtual void addOverlappingObject(btCollisionObject* otherObject);
|
void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const;
|
||||||
|
|
||||||
virtual void removeOverlappingObject(btCollisionObject* otherObject);
|
virtual void addOverlappingObject(btBroadphaseProxy* otherProxy);
|
||||||
|
|
||||||
btOverlappingPairCache* getPairCache()
|
virtual void removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher);
|
||||||
|
|
||||||
|
int getNumOverlappingObjects() const
|
||||||
{
|
{
|
||||||
return m_overlappingPairCache;
|
return m_overlappingObjects.size();
|
||||||
};
|
|
||||||
|
|
||||||
const btOverlappingPairCache* getPairCache() const
|
|
||||||
{
|
|
||||||
return m_overlappingPairCache;
|
|
||||||
};
|
|
||||||
|
|
||||||
btBroadphasePairArray& getOverlappingPairArray()
|
|
||||||
{
|
|
||||||
return m_overlappingPairCache->getOverlappingPairArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
btOverlappingPairCache* getOverlappingPairCache()
|
btCollisionObject* getOverlappingObject(int index)
|
||||||
{
|
{
|
||||||
return m_overlappingPairCache;
|
return m_overlappingObjects[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const btCollisionObject* getOverlappingObject(int index) const
|
||||||
|
{
|
||||||
|
return m_overlappingObjects[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
btAlignedObjectArray<btCollisionObject*>& getOverlappingPairs()
|
||||||
|
{
|
||||||
|
return m_overlappingObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
const btAlignedObjectArray<btCollisionObject*> getOverlappingPairs() const
|
||||||
|
{
|
||||||
|
return m_overlappingObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Cast
|
// internal cast
|
||||||
//
|
//
|
||||||
|
|
||||||
static const btGhostObject* upcast(const btCollisionObject* colObj)
|
static const btGhostObject* upcast(const btCollisionObject* colObj)
|
||||||
@@ -95,11 +93,31 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class btPairCachingGhostObject : public btGhostObject
|
||||||
|
{
|
||||||
|
btHashedOverlappingPairCache* m_hashPairCache;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
btPairCachingGhostObject();
|
||||||
|
|
||||||
|
virtual ~btPairCachingGhostObject();
|
||||||
|
|
||||||
|
virtual void addOverlappingObject(btBroadphaseProxy* otherProxy);
|
||||||
|
|
||||||
|
virtual void removeOverlappingObject(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher);
|
||||||
|
|
||||||
|
btHashedOverlappingPairCache* getOverlappingPairCache()
|
||||||
|
{
|
||||||
|
return m_hashPairCache;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///btGhostPairCache keeps track of overlapping objects that have AABB overlap with the ghost
|
///btGhostPairCache keeps track of overlapping objects that have AABB overlap with the ghost
|
||||||
class btGhostPairCallback : public btOverlappingPairCallback
|
class btGhostPairCallback : public btOverlappingPairCallback
|
||||||
{
|
{
|
||||||
@@ -121,9 +139,10 @@ public:
|
|||||||
btGhostObject* ghost0 = btGhostObject::upcast(colObj0);
|
btGhostObject* ghost0 = btGhostObject::upcast(colObj0);
|
||||||
btGhostObject* ghost1 = btGhostObject::upcast(colObj1);
|
btGhostObject* ghost1 = btGhostObject::upcast(colObj1);
|
||||||
if (ghost0)
|
if (ghost0)
|
||||||
ghost0->addOverlappingObject(colObj1);
|
ghost0->addOverlappingObject(proxy1);
|
||||||
if (ghost1)
|
if (ghost1)
|
||||||
ghost1->addOverlappingObject(colObj0);
|
ghost1->addOverlappingObject(proxy0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher)
|
virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher)
|
||||||
@@ -133,9 +152,10 @@ public:
|
|||||||
btGhostObject* ghost0 = btGhostObject::upcast(colObj0);
|
btGhostObject* ghost0 = btGhostObject::upcast(colObj0);
|
||||||
btGhostObject* ghost1 = btGhostObject::upcast(colObj1);
|
btGhostObject* ghost1 = btGhostObject::upcast(colObj1);
|
||||||
if (ghost0)
|
if (ghost0)
|
||||||
ghost0->removeOverlappingObject(colObj1);
|
ghost0->removeOverlappingObject(proxy1,dispatcher);
|
||||||
if (ghost1)
|
if (ghost1)
|
||||||
ghost1->removeOverlappingObject(colObj0);
|
ghost1->removeOverlappingObject(proxy0,dispatcher);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher)
|
virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ subject to the following restrictions:
|
|||||||
#include "BulletCollision/CollisionDispatch/btUnionFind.h"
|
#include "BulletCollision/CollisionDispatch/btUnionFind.h"
|
||||||
#include "btCollisionCreateFunc.h"
|
#include "btCollisionCreateFunc.h"
|
||||||
#include "LinearMath/btAlignedObjectArray.h"
|
#include "LinearMath/btAlignedObjectArray.h"
|
||||||
|
#include "btCollisionObject.h"
|
||||||
|
|
||||||
class btCollisionObject;
|
class btCollisionObject;
|
||||||
class btCollisionWorld;
|
class btCollisionWorld;
|
||||||
|
|||||||
Reference in New Issue
Block a user