mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 07:34:45 +00:00
Bullet 2.85 update
This commit is contained in:
parent
38bf2b8175
commit
540c9b72c0
391 changed files with 32183 additions and 58559 deletions
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's.
|
||||
Work in progress, functionality will be added on demand.
|
||||
|
||||
If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h"
|
||||
*/
|
||||
|
||||
#ifndef BULLET_C_API_H
|
||||
#define BULLET_C_API_H
|
||||
|
||||
#define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
|
||||
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
typedef double plReal;
|
||||
#else
|
||||
typedef float plReal;
|
||||
#endif
|
||||
|
||||
typedef plReal plVector3[3];
|
||||
typedef plReal plQuaternion[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Particular physics SDK (C-API) */
|
||||
PL_DECLARE_HANDLE(plPhysicsSdkHandle);
|
||||
|
||||
/** Dynamics world, belonging to some physics SDK (C-API)*/
|
||||
PL_DECLARE_HANDLE(plDynamicsWorldHandle);
|
||||
|
||||
/** Rigid Body that can be part of a Dynamics World (C-API)*/
|
||||
PL_DECLARE_HANDLE(plRigidBodyHandle);
|
||||
|
||||
/** Collision Shape/Geometry, property of a Rigid Body (C-API)*/
|
||||
PL_DECLARE_HANDLE(plCollisionShapeHandle);
|
||||
|
||||
/** Constraint for Rigid Bodies (C-API)*/
|
||||
PL_DECLARE_HANDLE(plConstraintHandle);
|
||||
|
||||
/** Triangle Mesh interface (C-API)*/
|
||||
PL_DECLARE_HANDLE(plMeshInterfaceHandle);
|
||||
|
||||
/** Broadphase Scene/Proxy Handles (C-API)*/
|
||||
PL_DECLARE_HANDLE(plCollisionBroadphaseHandle);
|
||||
PL_DECLARE_HANDLE(plBroadphaseProxyHandle);
|
||||
PL_DECLARE_HANDLE(plCollisionWorldHandle);
|
||||
|
||||
/**
|
||||
Create and Delete a Physics SDK
|
||||
*/
|
||||
|
||||
extern plPhysicsSdkHandle plNewBulletSdk(void); //this could be also another sdk, like ODE, PhysX etc.
|
||||
extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk);
|
||||
|
||||
/** Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */
|
||||
|
||||
typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2);
|
||||
|
||||
extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback);
|
||||
|
||||
extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp);
|
||||
|
||||
extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ);
|
||||
|
||||
extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle);
|
||||
|
||||
extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ);
|
||||
|
||||
/* todo: add pair cache support with queries like add/remove/find pair */
|
||||
|
||||
extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk);
|
||||
|
||||
/* todo: add/remove objects */
|
||||
|
||||
|
||||
/* Dynamics World */
|
||||
|
||||
extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk);
|
||||
|
||||
extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world);
|
||||
|
||||
extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep);
|
||||
|
||||
extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object);
|
||||
|
||||
extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object);
|
||||
|
||||
|
||||
/* Rigid Body */
|
||||
|
||||
extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape );
|
||||
|
||||
extern void plDeleteRigidBody(plRigidBodyHandle body);
|
||||
|
||||
|
||||
/* Collision Shape definition */
|
||||
|
||||
extern plCollisionShapeHandle plNewSphereShape(plReal radius);
|
||||
extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z);
|
||||
extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height);
|
||||
extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height);
|
||||
extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height);
|
||||
extern plCollisionShapeHandle plNewCompoundShape(void);
|
||||
extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn);
|
||||
|
||||
extern void plDeleteShape(plCollisionShapeHandle shape);
|
||||
|
||||
/* Convex Meshes */
|
||||
extern plCollisionShapeHandle plNewConvexHullShape(void);
|
||||
extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z);
|
||||
/* Concave static triangle meshes */
|
||||
extern plMeshInterfaceHandle plNewMeshInterface(void);
|
||||
extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2);
|
||||
extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle);
|
||||
|
||||
extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling);
|
||||
|
||||
/* SOLID has Response Callback/Table/Management */
|
||||
/* PhysX has Triggers, User Callbacks and filtering */
|
||||
/* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */
|
||||
|
||||
/* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */
|
||||
/* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */
|
||||
|
||||
/* get world transform */
|
||||
extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix);
|
||||
extern void plGetPosition(plRigidBodyHandle object,plVector3 position);
|
||||
extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation);
|
||||
|
||||
/* set world transform (position/orientation) */
|
||||
extern void plSetPosition(plRigidBodyHandle object, const plVector3 position);
|
||||
extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation);
|
||||
extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient);
|
||||
extern void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix);
|
||||
|
||||
typedef struct plRayCastResult {
|
||||
plRigidBodyHandle m_body;
|
||||
plCollisionShapeHandle m_shape;
|
||||
plVector3 m_positionWorld;
|
||||
plVector3 m_normalWorld;
|
||||
} plRayCastResult;
|
||||
|
||||
extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res);
|
||||
|
||||
/* Sweep API */
|
||||
|
||||
/* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */
|
||||
|
||||
/* Continuous Collision Detection API */
|
||||
|
||||
// needed for source/blender/blenkernel/intern/collision.c
|
||||
double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //BULLET_C_API_H
|
||||
|
||||
|
|
@ -38,8 +38,9 @@ static DBVT_INLINE btDbvtVolume merge( const btDbvtVolume& a,
|
|||
const btDbvtVolume& b)
|
||||
{
|
||||
#if (DBVT_MERGE_IMPL==DBVT_IMPL_SSE)
|
||||
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtAabbMm)]);
|
||||
btDbvtVolume& res=*(btDbvtVolume*)locals;
|
||||
ATTRIBUTE_ALIGNED16( char locals[sizeof(btDbvtAabbMm)]);
|
||||
btDbvtVolume* ptr = (btDbvtVolume*) locals;
|
||||
btDbvtVolume& res=*ptr;
|
||||
#else
|
||||
btDbvtVolume res;
|
||||
#endif
|
||||
|
|
@ -250,7 +251,8 @@ static btDbvtVolume bounds( const tNodeArray& leaves)
|
|||
{
|
||||
#if DBVT_MERGE_IMPL==DBVT_IMPL_SSE
|
||||
ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]);
|
||||
btDbvtVolume& volume=*(btDbvtVolume*)locals;
|
||||
btDbvtVolume* ptr = (btDbvtVolume*) locals;
|
||||
btDbvtVolume& volume=*ptr;
|
||||
volume=leaves[0]->volume;
|
||||
#else
|
||||
btDbvtVolume volume=leaves[0]->volume;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ subject to the following restrictions:
|
|||
#error "DBVT_INT0_IMPL undefined"
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// Defaults volumes
|
||||
//
|
||||
|
|
@ -188,6 +189,9 @@ struct btDbvtNode
|
|||
};
|
||||
};
|
||||
|
||||
typedef btAlignedObjectArray<const btDbvtNode*> btNodeStack;
|
||||
|
||||
|
||||
///The btDbvt class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree).
|
||||
///This btDbvt is used for soft body collision detection and for the btDbvtBroadphase. It has a fast insert, remove and update of nodes.
|
||||
///Unlike the btQuantizedBvh, nodes can be dynamically moved around, which allows for change in topology of the underlying data structure.
|
||||
|
|
@ -263,7 +267,6 @@ struct btDbvt
|
|||
|
||||
|
||||
btAlignedObjectArray<sStkNN> m_stkStack;
|
||||
mutable btAlignedObjectArray<const btDbvtNode*> m_rayTestStack;
|
||||
|
||||
|
||||
// Methods
|
||||
|
|
@ -325,6 +328,16 @@ struct btDbvt
|
|||
void collideTV( const btDbvtNode* root,
|
||||
const btDbvtVolume& volume,
|
||||
DBVT_IPOLICY) const;
|
||||
|
||||
DBVT_PREFIX
|
||||
void collideTVNoStackAlloc( const btDbvtNode* root,
|
||||
const btDbvtVolume& volume,
|
||||
btNodeStack& stack,
|
||||
DBVT_IPOLICY) const;
|
||||
|
||||
|
||||
|
||||
|
||||
///rayTest is a re-entrant ray test, and can be called in parallel as long as the btAlignedAlloc is thread-safe (uses locking etc)
|
||||
///rayTest is slower than rayTestInternal, because it builds a local stack, using memory allocations, and it recomputes signs/rayDirectionInverses each time
|
||||
DBVT_PREFIX
|
||||
|
|
@ -343,6 +356,7 @@ struct btDbvt
|
|||
btScalar lambda_max,
|
||||
const btVector3& aabbMin,
|
||||
const btVector3& aabbMax,
|
||||
btAlignedObjectArray<const btDbvtNode*>& stack,
|
||||
DBVT_IPOLICY) const;
|
||||
|
||||
DBVT_PREFIX
|
||||
|
|
@ -917,39 +931,72 @@ inline void btDbvt::collideTT( const btDbvtNode* root0,
|
|||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
DBVT_PREFIX
|
||||
inline void btDbvt::collideTV( const btDbvtNode* root,
|
||||
const btDbvtVolume& vol,
|
||||
DBVT_IPOLICY) const
|
||||
{
|
||||
DBVT_CHECKTYPE
|
||||
if(root)
|
||||
{
|
||||
ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol);
|
||||
btAlignedObjectArray<const btDbvtNode*> stack;
|
||||
stack.resize(0);
|
||||
stack.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(root);
|
||||
do {
|
||||
const btDbvtNode* n=stack[stack.size()-1];
|
||||
stack.pop_back();
|
||||
if(Intersect(n->volume,volume))
|
||||
if(root)
|
||||
{
|
||||
ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol);
|
||||
btAlignedObjectArray<const btDbvtNode*> stack;
|
||||
stack.resize(0);
|
||||
stack.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(root);
|
||||
do {
|
||||
const btDbvtNode* n=stack[stack.size()-1];
|
||||
stack.pop_back();
|
||||
if(Intersect(n->volume,volume))
|
||||
{
|
||||
if(n->isinternal())
|
||||
{
|
||||
if(n->isinternal())
|
||||
{
|
||||
stack.push_back(n->childs[0]);
|
||||
stack.push_back(n->childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
policy.Process(n);
|
||||
}
|
||||
stack.push_back(n->childs[0]);
|
||||
stack.push_back(n->childs[1]);
|
||||
}
|
||||
} while(stack.size()>0);
|
||||
}
|
||||
else
|
||||
{
|
||||
policy.Process(n);
|
||||
}
|
||||
}
|
||||
} while(stack.size()>0);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
DBVT_PREFIX
|
||||
inline void btDbvt::collideTVNoStackAlloc( const btDbvtNode* root,
|
||||
const btDbvtVolume& vol,
|
||||
btNodeStack& stack,
|
||||
DBVT_IPOLICY) const
|
||||
{
|
||||
DBVT_CHECKTYPE
|
||||
if(root)
|
||||
{
|
||||
ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol);
|
||||
stack.resize(0);
|
||||
stack.reserve(SIMPLE_STACKSIZE);
|
||||
stack.push_back(root);
|
||||
do {
|
||||
const btDbvtNode* n=stack[stack.size()-1];
|
||||
stack.pop_back();
|
||||
if(Intersect(n->volume,volume))
|
||||
{
|
||||
if(n->isinternal())
|
||||
{
|
||||
stack.push_back(n->childs[0]);
|
||||
stack.push_back(n->childs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
policy.Process(n);
|
||||
}
|
||||
}
|
||||
} while(stack.size()>0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DBVT_PREFIX
|
||||
inline void btDbvt::rayTestInternal( const btDbvtNode* root,
|
||||
const btVector3& rayFrom,
|
||||
|
|
@ -959,7 +1006,8 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root,
|
|||
btScalar lambda_max,
|
||||
const btVector3& aabbMin,
|
||||
const btVector3& aabbMax,
|
||||
DBVT_IPOLICY) const
|
||||
btAlignedObjectArray<const btDbvtNode*>& stack,
|
||||
DBVT_IPOLICY ) const
|
||||
{
|
||||
(void) rayTo;
|
||||
DBVT_CHECKTYPE
|
||||
|
|
@ -969,7 +1017,6 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root,
|
|||
|
||||
int depth=1;
|
||||
int treshold=DOUBLE_STACKSIZE-2;
|
||||
btAlignedObjectArray<const btDbvtNode*>& stack = m_rayTestStack;
|
||||
stack.resize(DOUBLE_STACKSIZE);
|
||||
stack[0]=root;
|
||||
btVector3 bounds[2];
|
||||
|
|
@ -1193,19 +1240,34 @@ inline void btDbvt::collideOCL( const btDbvtNode* root,
|
|||
/* Insert 0 */
|
||||
j=nearest(&stack[0],&stock[0],nes[q].value,0,stack.size());
|
||||
stack.push_back(0);
|
||||
|
||||
//void * memmove ( void * destination, const void * source, size_t num );
|
||||
|
||||
#if DBVT_USE_MEMMOVE
|
||||
memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1));
|
||||
{
|
||||
int num_items_to_move = stack.size()-1-j;
|
||||
if(num_items_to_move > 0)
|
||||
memmove(&stack[j+1],&stack[j],sizeof(int)*num_items_to_move);
|
||||
}
|
||||
#else
|
||||
for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1];
|
||||
for(int k=stack.size()-1;k>j;--k) {
|
||||
stack[k]=stack[k-1];
|
||||
}
|
||||
#endif
|
||||
stack[j]=allocate(ifree,stock,nes[q]);
|
||||
/* Insert 1 */
|
||||
j=nearest(&stack[0],&stock[0],nes[1-q].value,j,stack.size());
|
||||
stack.push_back(0);
|
||||
#if DBVT_USE_MEMMOVE
|
||||
memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1));
|
||||
{
|
||||
int num_items_to_move = stack.size()-1-j;
|
||||
if(num_items_to_move > 0)
|
||||
memmove(&stack[j+1],&stack[j],sizeof(int)*num_items_to_move);
|
||||
}
|
||||
#else
|
||||
for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1];
|
||||
for(int k=stack.size()-1;k>j;--k) {
|
||||
stack[k]=stack[k-1];
|
||||
}
|
||||
#endif
|
||||
stack[j]=allocate(ifree,stock,nes[1-q]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ subject to the following restrictions:
|
|||
///btDbvtBroadphase implementation by Nathanael Presson
|
||||
|
||||
#include "btDbvtBroadphase.h"
|
||||
#include "LinearMath/btThreads.h"
|
||||
|
||||
//
|
||||
// Profiling
|
||||
|
|
@ -142,6 +143,11 @@ btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache)
|
|||
{
|
||||
m_stageRoots[i]=0;
|
||||
}
|
||||
#if BT_THREADSAFE
|
||||
m_rayTestStacks.resize(BT_MAX_THREAD_COUNT);
|
||||
#else
|
||||
m_rayTestStacks.resize(1);
|
||||
#endif
|
||||
#if DBVT_BP_PROFILE
|
||||
clear(m_profiling);
|
||||
#endif
|
||||
|
|
@ -227,6 +233,23 @@ struct BroadphaseRayTester : btDbvt::ICollide
|
|||
void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax)
|
||||
{
|
||||
BroadphaseRayTester callback(rayCallback);
|
||||
btAlignedObjectArray<const btDbvtNode*>* stack = &m_rayTestStacks[0];
|
||||
#if BT_THREADSAFE
|
||||
// for this function to be threadsafe, each thread must have a separate copy
|
||||
// of this stack. This could be thread-local static to avoid dynamic allocations,
|
||||
// instead of just a local.
|
||||
int threadIndex = btGetCurrentThreadIndex();
|
||||
btAlignedObjectArray<const btDbvtNode*> localStack;
|
||||
if (threadIndex < m_rayTestStacks.size())
|
||||
{
|
||||
// use per-thread preallocated stack if possible to avoid dynamic allocations
|
||||
stack = &m_rayTestStacks[threadIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
stack = &localStack;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_sets[0].rayTestInternal( m_sets[0].m_root,
|
||||
rayFrom,
|
||||
|
|
@ -236,6 +259,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo,
|
|||
rayCallback.m_lambda_max,
|
||||
aabbMin,
|
||||
aabbMax,
|
||||
*stack,
|
||||
callback);
|
||||
|
||||
m_sets[1].rayTestInternal( m_sets[1].m_root,
|
||||
|
|
@ -246,6 +270,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo,
|
|||
rayCallback.m_lambda_max,
|
||||
aabbMin,
|
||||
aabbMax,
|
||||
*stack,
|
||||
callback);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ struct btDbvtBroadphase : btBroadphaseInterface
|
|||
bool m_releasepaircache; // Release pair cache on delete
|
||||
bool m_deferedcollide; // Defere dynamic/static collision to collide call
|
||||
bool m_needcleanup; // Need to run cleanup?
|
||||
btAlignedObjectArray< btAlignedObjectArray<const btDbvtNode*> > m_rayTestStacks;
|
||||
#if DBVT_BP_PROFILE
|
||||
btClock m_clock;
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ struct btDispatcherInfo
|
|||
btScalar m_convexConservativeDistanceThreshold;
|
||||
};
|
||||
|
||||
enum ebtDispatcherQueryType
|
||||
{
|
||||
BT_CONTACT_POINT_ALGORITHMS = 1,
|
||||
BT_CLOSEST_POINT_ALGORITHMS = 2
|
||||
};
|
||||
|
||||
///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs.
|
||||
///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic).
|
||||
class btDispatcher
|
||||
|
|
@ -73,7 +79,7 @@ class btDispatcher
|
|||
public:
|
||||
virtual ~btDispatcher() ;
|
||||
|
||||
virtual btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold=0) = 0;
|
||||
virtual btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType queryType) = 0;
|
||||
|
||||
virtual btPersistentManifold* getNewManifold(const btCollisionObject* b0,const btCollisionObject* b1)=0;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ int gFindPairs =0;
|
|||
|
||||
btHashedOverlappingPairCache::btHashedOverlappingPairCache():
|
||||
m_overlapFilterCallback(0),
|
||||
m_blockedForChanges(false),
|
||||
m_ghostPairCallback(0)
|
||||
{
|
||||
int initialAllocatedSize= 2;
|
||||
|
|
@ -373,10 +372,10 @@ void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro
|
|||
return userData;
|
||||
}
|
||||
//#include <stdio.h>
|
||||
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher)
|
||||
{
|
||||
|
||||
BT_PROFILE("btHashedOverlappingPairCache::processAllOverlappingPairs");
|
||||
int i;
|
||||
|
||||
// printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size());
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache
|
|||
{
|
||||
btBroadphasePairArray m_overlappingPairArray;
|
||||
btOverlapFilterCallback* m_overlapFilterCallback;
|
||||
bool m_blockedForChanges;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,8 @@ void btQuantizedBvh::setQuantizationValues(const btVector3& bvhAabbMin,const btV
|
|||
v = unQuantize(vecIn);
|
||||
m_bvhAabbMin.setMin(v-clampValue);
|
||||
}
|
||||
aabbSize = m_bvhAabbMax - m_bvhAabbMin;
|
||||
m_bvhQuantization = btVector3(btScalar(65533.0),btScalar(65533.0),btScalar(65533.0)) / aabbSize;
|
||||
{
|
||||
quantize(vecIn,m_bvhAabbMax,true);
|
||||
v = unQuantize(vecIn);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ SET(BulletCollision_SRCS
|
|||
CollisionDispatch/btCollisionDispatcher.cpp
|
||||
CollisionDispatch/btCollisionObject.cpp
|
||||
CollisionDispatch/btCollisionWorld.cpp
|
||||
CollisionDispatch/btCollisionWorldImporter.cpp
|
||||
CollisionDispatch/btCompoundCollisionAlgorithm.cpp
|
||||
CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp
|
||||
CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp
|
||||
|
|
@ -126,6 +127,7 @@ SET(CollisionDispatch_HDRS
|
|||
CollisionDispatch/btCollisionObject.h
|
||||
CollisionDispatch/btCollisionObjectWrapper.h
|
||||
CollisionDispatch/btCollisionWorld.h
|
||||
CollisionDispatch/btCollisionWorldImporter.h
|
||||
CollisionDispatch/btCompoundCollisionAlgorithm.h
|
||||
CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h
|
||||
CollisionDispatch/btConvexConcaveCollisionAlgorithm.h
|
||||
|
|
@ -269,10 +271,10 @@ DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" E
|
|||
DESTINATION ${INCLUDE_INSTALL_DIR}/BulletCollision)
|
||||
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
|
||||
ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
|
||||
|
||||
|
||||
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
|
||||
SET_TARGET_PROPERTIES(BulletCollision PROPERTIES FRAMEWORK true)
|
||||
|
||||
|
||||
SET_TARGET_PROPERTIES(BulletCollision PROPERTIES PUBLIC_HEADER "${Root_HDRS}")
|
||||
# Have to list out sub-directories manually:
|
||||
SET_PROPERTY(SOURCE ${BroadphaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/BroadphaseCollision)
|
||||
|
|
@ -280,7 +282,7 @@ DESTINATION ${INCLUDE_INSTALL_DIR}/BulletCollision)
|
|||
SET_PROPERTY(SOURCE ${CollisionShapes_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/CollisionShapes)
|
||||
SET_PROPERTY(SOURCE ${Gimpact_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Gimpact)
|
||||
SET_PROPERTY(SOURCE ${NarrowPhaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/NarrowPhaseCollision)
|
||||
|
||||
|
||||
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
|
||||
ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
|
||||
ENDIF (INSTALL_LIBS)
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &po
|
|||
btScalar radiusWithThreshold = radius + contactBreakingThreshold;
|
||||
|
||||
btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]);
|
||||
normal.normalize();
|
||||
normal.safeNormalize();
|
||||
btVector3 p1ToCentre = sphereCenter - vertices[0];
|
||||
btScalar distanceFromPlane = p1ToCentre.dot(normal);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ public:
|
|||
|
||||
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0;
|
||||
|
||||
virtual btCollisionAlgorithmCreateFunc* getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //BT_COLLISION_CONFIGURATION
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ subject to the following restrictions:
|
|||
|
||||
|
||||
#include "btCollisionDispatcher.h"
|
||||
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
|
||||
#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
|
||||
|
||||
|
|
@ -50,8 +50,10 @@ m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESH
|
|||
{
|
||||
for (int j=0;j<MAX_BROADPHASE_COLLISION_TYPES;j++)
|
||||
{
|
||||
m_doubleDispatch[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j);
|
||||
btAssert(m_doubleDispatch[i][j]);
|
||||
m_doubleDispatchContactPoints[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j);
|
||||
btAssert(m_doubleDispatchContactPoints[i][j]);
|
||||
m_doubleDispatchClosestPoints[i][j] = m_collisionConfiguration->getClosestPointsAlgorithmCreateFunc(i, j);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +63,12 @@ m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESH
|
|||
|
||||
void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc)
|
||||
{
|
||||
m_doubleDispatch[proxyType0][proxyType1] = createFunc;
|
||||
m_doubleDispatchContactPoints[proxyType0][proxyType1] = createFunc;
|
||||
}
|
||||
|
||||
void btCollisionDispatcher::registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc)
|
||||
{
|
||||
m_doubleDispatchClosestPoints[proxyType0][proxyType1] = createFunc;
|
||||
}
|
||||
|
||||
btCollisionDispatcher::~btCollisionDispatcher()
|
||||
|
|
@ -84,14 +91,10 @@ btPersistentManifold* btCollisionDispatcher::getNewManifold(const btCollisionObj
|
|||
|
||||
btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold());
|
||||
|
||||
void* mem = 0;
|
||||
|
||||
if (m_persistentManifoldPoolAllocator->getFreeCount())
|
||||
void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) );
|
||||
if (NULL == mem)
|
||||
{
|
||||
mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold));
|
||||
} else
|
||||
{
|
||||
//we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
|
||||
//we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
|
||||
if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0)
|
||||
{
|
||||
mem = btAlignedAlloc(sizeof(btPersistentManifold),16);
|
||||
|
|
@ -142,14 +145,23 @@ void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold)
|
|||
|
||||
|
||||
|
||||
btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold)
|
||||
|
||||
btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType algoType)
|
||||
{
|
||||
|
||||
btCollisionAlgorithmConstructionInfo ci;
|
||||
|
||||
ci.m_dispatcher1 = this;
|
||||
ci.m_manifold = sharedManifold;
|
||||
btCollisionAlgorithm* algo = m_doubleDispatch[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0Wrap,body1Wrap);
|
||||
btCollisionAlgorithm* algo = 0;
|
||||
if (algoType == BT_CONTACT_POINT_ALGORITHMS)
|
||||
{
|
||||
algo = m_doubleDispatchContactPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap);
|
||||
}
|
||||
else
|
||||
{
|
||||
algo = m_doubleDispatchClosestPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap);
|
||||
}
|
||||
|
||||
return algo;
|
||||
}
|
||||
|
|
@ -189,7 +201,7 @@ bool btCollisionDispatcher::needsCollision(const btCollisionObject* body0,const
|
|||
|
||||
if ((!body0->isActive()) && (!body1->isActive()))
|
||||
needsCollision = false;
|
||||
else if (!body0->checkCollideWith(body1))
|
||||
else if ((!body0->checkCollideWith(body1)) || (!body1->checkCollideWith(body0)))
|
||||
needsCollision = false;
|
||||
|
||||
return needsCollision ;
|
||||
|
|
@ -227,6 +239,8 @@ public:
|
|||
|
||||
virtual bool processOverlap(btBroadphasePair& pair)
|
||||
{
|
||||
BT_PROFILE("btCollisionDispatcher::processOverlap");
|
||||
|
||||
(*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo);
|
||||
|
||||
return false;
|
||||
|
|
@ -249,7 +263,6 @@ void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pa
|
|||
|
||||
|
||||
|
||||
|
||||
//by default, Bullet will use this near callback
|
||||
void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo)
|
||||
{
|
||||
|
|
@ -265,7 +278,7 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair,
|
|||
//dispatcher will keep algorithms persistent in the collision pair
|
||||
if (!collisionPair.m_algorithm)
|
||||
{
|
||||
collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap);
|
||||
collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap,0, BT_CONTACT_POINT_ALGORITHMS);
|
||||
}
|
||||
|
||||
if (collisionPair.m_algorithm)
|
||||
|
|
@ -293,13 +306,13 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair,
|
|||
|
||||
void* btCollisionDispatcher::allocateCollisionAlgorithm(int size)
|
||||
{
|
||||
if (m_collisionAlgorithmPoolAllocator->getFreeCount())
|
||||
{
|
||||
return m_collisionAlgorithmPoolAllocator->allocate(size);
|
||||
}
|
||||
|
||||
//warn user for overflow?
|
||||
return btAlignedAlloc(static_cast<size_t>(size), 16);
|
||||
void* mem = m_collisionAlgorithmPoolAllocator->allocate( size );
|
||||
if (NULL == mem)
|
||||
{
|
||||
//warn user for overflow?
|
||||
return btAlignedAlloc(static_cast<size_t>(size), 16);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,9 @@ protected:
|
|||
|
||||
btPoolAllocator* m_persistentManifoldPoolAllocator;
|
||||
|
||||
btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES];
|
||||
btCollisionAlgorithmCreateFunc* m_doubleDispatchContactPoints[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES];
|
||||
|
||||
btCollisionAlgorithmCreateFunc* m_doubleDispatchClosestPoints[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES];
|
||||
|
||||
btCollisionConfiguration* m_collisionConfiguration;
|
||||
|
||||
|
|
@ -84,6 +86,8 @@ public:
|
|||
///registerCollisionCreateFunc allows registration of custom/alternative collision create functions
|
||||
void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc);
|
||||
|
||||
void registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc);
|
||||
|
||||
int getNumManifolds() const
|
||||
{
|
||||
return int( m_manifoldsPtr.size());
|
||||
|
|
@ -115,7 +119,7 @@ public:
|
|||
|
||||
virtual void clearManifold(btPersistentManifold* manifold);
|
||||
|
||||
btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold = 0);
|
||||
btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType queryType);
|
||||
|
||||
virtual bool needsCollision(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ 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,
|
||||
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.
|
||||
|
|
@ -28,13 +28,19 @@ btCollisionObject::btCollisionObject()
|
|||
m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT),
|
||||
m_islandTag1(-1),
|
||||
m_companionId(-1),
|
||||
m_worldArrayIndex(-1),
|
||||
m_activationState1(1),
|
||||
m_deactivationTime(btScalar(0.)),
|
||||
m_friction(btScalar(0.5)),
|
||||
m_rollingFriction(0.0f),
|
||||
m_restitution(btScalar(0.)),
|
||||
m_rollingFriction(0.0f),
|
||||
m_spinningFriction(0.f),
|
||||
m_contactDamping(.1),
|
||||
m_contactStiffness(1e4),
|
||||
m_internalType(CO_COLLISION_OBJECT),
|
||||
m_userObjectPointer(0),
|
||||
m_userIndex2(-1),
|
||||
m_userIndex(-1),
|
||||
m_hitFraction(btScalar(1.)),
|
||||
m_ccdSweptSphereRadius(btScalar(0.)),
|
||||
m_ccdMotionThreshold(btScalar(0.)),
|
||||
|
|
@ -90,6 +96,8 @@ const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* seriali
|
|||
dataOut->m_deactivationTime = m_deactivationTime;
|
||||
dataOut->m_friction = m_friction;
|
||||
dataOut->m_rollingFriction = m_rollingFriction;
|
||||
dataOut->m_contactDamping = m_contactDamping;
|
||||
dataOut->m_contactStiffness = m_contactStiffness;
|
||||
dataOut->m_restitution = m_restitution;
|
||||
dataOut->m_internalType = m_internalType;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,24 +79,31 @@ protected:
|
|||
|
||||
int m_islandTag1;
|
||||
int m_companionId;
|
||||
int m_worldArrayIndex; // index of object in world's collisionObjects array
|
||||
|
||||
mutable int m_activationState1;
|
||||
mutable btScalar m_deactivationTime;
|
||||
|
||||
btScalar m_friction;
|
||||
btScalar m_restitution;
|
||||
btScalar m_rollingFriction;
|
||||
btScalar m_rollingFriction;//torsional friction orthogonal to contact normal (useful to stop spheres rolling forever)
|
||||
btScalar m_spinningFriction; // torsional friction around the contact normal (useful for grasping)
|
||||
btScalar m_contactDamping;
|
||||
btScalar m_contactStiffness;
|
||||
|
||||
|
||||
|
||||
///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc.
|
||||
///do not assign your own m_internalType unless you write a new dynamics object class.
|
||||
int m_internalType;
|
||||
|
||||
///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer
|
||||
union
|
||||
{
|
||||
void* m_userObjectPointer;
|
||||
int m_userIndex;
|
||||
};
|
||||
|
||||
void* m_userObjectPointer;
|
||||
|
||||
int m_userIndex2;
|
||||
|
||||
int m_userIndex;
|
||||
|
||||
///time of impact calculation
|
||||
btScalar m_hitFraction;
|
||||
|
|
@ -110,13 +117,12 @@ protected:
|
|||
/// If some object should have elaborate collision filtering by sub-classes
|
||||
int m_checkCollideWith;
|
||||
|
||||
btAlignedObjectArray<const btCollisionObject*> m_objectsWithoutCollisionCheck;
|
||||
|
||||
///internal update revision number. It will be increased when the object changes. This allows some subsystems to perform lazy evaluation.
|
||||
int m_updateRevision;
|
||||
|
||||
virtual bool checkCollideWithOverride(const btCollisionObject* /* co */) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
btVector3 m_customDebugColorRGB;
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -130,7 +136,9 @@ public:
|
|||
CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution)
|
||||
CF_CHARACTER_OBJECT = 16,
|
||||
CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing
|
||||
CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing
|
||||
CF_DISABLE_SPU_COLLISION_PROCESSING = 64,//disable parallel/SPU processing
|
||||
CF_HAS_CONTACT_STIFFNESS_DAMPING = 128,
|
||||
CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR = 256,
|
||||
};
|
||||
|
||||
enum CollisionObjectTypes
|
||||
|
|
@ -225,7 +233,34 @@ public:
|
|||
return m_collisionShape;
|
||||
}
|
||||
|
||||
|
||||
void setIgnoreCollisionCheck(const btCollisionObject* co, bool ignoreCollisionCheck)
|
||||
{
|
||||
if (ignoreCollisionCheck)
|
||||
{
|
||||
//We don't check for duplicates. Is it ok to leave that up to the user of this API?
|
||||
//int index = m_objectsWithoutCollisionCheck.findLinearSearch(co);
|
||||
//if (index == m_objectsWithoutCollisionCheck.size())
|
||||
//{
|
||||
m_objectsWithoutCollisionCheck.push_back(co);
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_objectsWithoutCollisionCheck.remove(co);
|
||||
}
|
||||
m_checkCollideWith = m_objectsWithoutCollisionCheck.size() > 0;
|
||||
}
|
||||
|
||||
virtual bool checkCollideWithOverride(const btCollisionObject* co) const
|
||||
{
|
||||
int index = m_objectsWithoutCollisionCheck.findLinearSearch(co);
|
||||
if (index < m_objectsWithoutCollisionCheck.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -292,8 +327,40 @@ public:
|
|||
{
|
||||
return m_rollingFriction;
|
||||
}
|
||||
|
||||
|
||||
void setSpinningFriction(btScalar frict)
|
||||
{
|
||||
m_updateRevision++;
|
||||
m_spinningFriction = frict;
|
||||
}
|
||||
btScalar getSpinningFriction() const
|
||||
{
|
||||
return m_spinningFriction;
|
||||
}
|
||||
void setContactStiffnessAndDamping(btScalar stiffness, btScalar damping)
|
||||
{
|
||||
m_updateRevision++;
|
||||
m_contactStiffness = stiffness;
|
||||
m_contactDamping = damping;
|
||||
|
||||
m_collisionFlags |=CF_HAS_CONTACT_STIFFNESS_DAMPING;
|
||||
|
||||
//avoid divisions by zero...
|
||||
if (m_contactStiffness< SIMD_EPSILON)
|
||||
{
|
||||
m_contactStiffness = SIMD_EPSILON;
|
||||
}
|
||||
}
|
||||
|
||||
btScalar getContactStiffness() const
|
||||
{
|
||||
return m_contactStiffness;
|
||||
}
|
||||
|
||||
btScalar getContactDamping() const
|
||||
{
|
||||
return m_contactDamping;
|
||||
}
|
||||
|
||||
///reserved for Bullet internal usage
|
||||
int getInternalType() const
|
||||
{
|
||||
|
|
@ -391,7 +458,18 @@ public:
|
|||
m_companionId = id;
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE btScalar getHitFraction() const
|
||||
SIMD_FORCE_INLINE int getWorldArrayIndex() const
|
||||
{
|
||||
return m_worldArrayIndex;
|
||||
}
|
||||
|
||||
// only should be called by CollisionWorld
|
||||
void setWorldArrayIndex(int ix)
|
||||
{
|
||||
m_worldArrayIndex = ix;
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE btScalar getHitFraction() const
|
||||
{
|
||||
return m_hitFraction;
|
||||
}
|
||||
|
|
@ -452,6 +530,12 @@ public:
|
|||
{
|
||||
return m_userIndex;
|
||||
}
|
||||
|
||||
int getUserIndex2() const
|
||||
{
|
||||
return m_userIndex2;
|
||||
}
|
||||
|
||||
///users can point to their objects, userPointer is not used by Bullet
|
||||
void setUserPointer(void* userPointer)
|
||||
{
|
||||
|
|
@ -463,12 +547,37 @@ public:
|
|||
{
|
||||
m_userIndex = index;
|
||||
}
|
||||
|
||||
void setUserIndex2(int index)
|
||||
{
|
||||
m_userIndex2 = index;
|
||||
}
|
||||
|
||||
int getUpdateRevisionInternal() const
|
||||
{
|
||||
return m_updateRevision;
|
||||
}
|
||||
|
||||
void setCustomDebugColor(const btVector3& colorRGB)
|
||||
{
|
||||
m_customDebugColorRGB = colorRGB;
|
||||
m_collisionFlags |= CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR;
|
||||
}
|
||||
|
||||
void removeCustomDebugColor()
|
||||
{
|
||||
m_collisionFlags &= ~CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR;
|
||||
}
|
||||
|
||||
bool getCustomDebugColor(btVector3& colorRGB) const
|
||||
{
|
||||
bool hasCustomColor = (0!=(m_collisionFlags&CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR));
|
||||
if (hasCustomColor)
|
||||
{
|
||||
colorRGB = m_customDebugColorRGB;
|
||||
}
|
||||
return hasCustomColor;
|
||||
}
|
||||
|
||||
inline bool checkCollideWith(const btCollisionObject* co) const
|
||||
{
|
||||
|
|
@ -504,6 +613,8 @@ struct btCollisionObjectDoubleData
|
|||
double m_deactivationTime;
|
||||
double m_friction;
|
||||
double m_rollingFriction;
|
||||
double m_contactDamping;
|
||||
double m_contactStiffness;
|
||||
double m_restitution;
|
||||
double m_hitFraction;
|
||||
double m_ccdSweptSphereRadius;
|
||||
|
|
@ -537,7 +648,8 @@ struct btCollisionObjectFloatData
|
|||
float m_deactivationTime;
|
||||
float m_friction;
|
||||
float m_rollingFriction;
|
||||
|
||||
float m_contactDamping;
|
||||
float m_contactStiffness;
|
||||
float m_restitution;
|
||||
float m_hitFraction;
|
||||
float m_ccdSweptSphereRadius;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ subject to the following restrictions:
|
|||
#include "LinearMath/btSerializer.h"
|
||||
#include "BulletCollision/CollisionShapes/btConvexPolyhedron.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h"
|
||||
#include "BulletCollision/Gimpact/btGImpactShape.h"
|
||||
|
||||
//#define DISABLE_DBVT_COMPOUNDSHAPE_RAYCAST_ACCELERATION
|
||||
|
||||
|
||||
|
|
@ -115,7 +115,9 @@ void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,sho
|
|||
|
||||
//check that the object isn't already added
|
||||
btAssert( m_collisionObjects.findLinearSearch(collisionObject) == m_collisionObjects.size());
|
||||
btAssert(collisionObject->getWorldArrayIndex() == -1); // do not add the same object to more than one collision world
|
||||
|
||||
collisionObject->setWorldArrayIndex(m_collisionObjects.size());
|
||||
m_collisionObjects.push_back(collisionObject);
|
||||
|
||||
//calculate new AABB
|
||||
|
|
@ -195,6 +197,7 @@ void btCollisionWorld::updateAabbs()
|
|||
for ( int i=0;i<m_collisionObjects.size();i++)
|
||||
{
|
||||
btCollisionObject* colObj = m_collisionObjects[i];
|
||||
btAssert(colObj->getWorldArrayIndex() == i);
|
||||
|
||||
//only update aabb of active objects
|
||||
if (m_forceUpdateAllAabbs || colObj->isActive())
|
||||
|
|
@ -253,9 +256,25 @@ void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject)
|
|||
}
|
||||
|
||||
|
||||
//swapremove
|
||||
m_collisionObjects.remove(collisionObject);
|
||||
|
||||
int iObj = collisionObject->getWorldArrayIndex();
|
||||
btAssert(iObj >= 0 && iObj < m_collisionObjects.size()); // trying to remove an object that was never added or already removed previously?
|
||||
if (iObj >= 0 && iObj < m_collisionObjects.size())
|
||||
{
|
||||
btAssert(collisionObject == m_collisionObjects[iObj]);
|
||||
m_collisionObjects.swap(iObj, m_collisionObjects.size()-1);
|
||||
m_collisionObjects.pop_back();
|
||||
if (iObj < m_collisionObjects.size())
|
||||
{
|
||||
m_collisionObjects[iObj]->setWorldArrayIndex(iObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// slow linear search
|
||||
//swapremove
|
||||
m_collisionObjects.remove(collisionObject);
|
||||
}
|
||||
collisionObject->setWorldArrayIndex(-1);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -292,12 +311,13 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con
|
|||
btGjkConvexCast gjkConvexCaster(castShape,convexShape,&simplexSolver);
|
||||
|
||||
//btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0);
|
||||
bool condition = true;
|
||||
|
||||
btConvexCast* convexCasterPtr = 0;
|
||||
if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest)
|
||||
convexCasterPtr = &subSimplexConvexCaster;
|
||||
else
|
||||
//use kF_UseSubSimplexConvexCastRaytest by default
|
||||
if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest)
|
||||
convexCasterPtr = &gjkConvexCaster;
|
||||
else
|
||||
convexCasterPtr = &subSimplexConvexCaster;
|
||||
|
||||
btConvexCast& convexCaster = *convexCasterPtr;
|
||||
|
||||
|
|
@ -308,6 +328,7 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con
|
|||
{
|
||||
if (castResult.m_fraction < resultCallback.m_closestHitFraction)
|
||||
{
|
||||
//todo: figure out what this is about. When is rayFromTest.getBasis() not identity?
|
||||
#ifdef USE_SUBSIMPLEX_CONVEX_CAST
|
||||
//rotate normal into worldspace
|
||||
castResult.m_normal = rayFromTrans.getBasis() * castResult.m_normal;
|
||||
|
|
@ -387,14 +408,7 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con
|
|||
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
|
||||
triangleMesh->performRaycast(&rcb,rayFromLocal,rayToLocal);
|
||||
}
|
||||
else if(collisionShape->getShapeType()==GIMPACT_SHAPE_PROXYTYPE)
|
||||
{
|
||||
btGImpactMeshShape* concaveShape = (btGImpactMeshShape*)collisionShape;
|
||||
|
||||
BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObjectWrap->getCollisionObject(),concaveShape, colObjWorldTransform);
|
||||
rcb.m_hitFraction = resultCallback.m_closestHitFraction;
|
||||
concaveShape->processAllTrianglesRay(&rcb,rayFromLocal,rayToLocal);
|
||||
}else
|
||||
else
|
||||
{
|
||||
//generic (slower) case
|
||||
btConcaveShape* concaveShape = (btConcaveShape*)collisionShape;
|
||||
|
|
@ -770,7 +784,7 @@ void btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape,
|
|||
hitPointLocal,
|
||||
hitFraction);
|
||||
|
||||
bool normalInWorldSpace = false;
|
||||
bool normalInWorldSpace = true;
|
||||
|
||||
return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace);
|
||||
}
|
||||
|
|
@ -795,23 +809,50 @@ void btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
///@todo : use AABB tree or other BVH acceleration structure!
|
||||
if (collisionShape->isCompound())
|
||||
{
|
||||
BT_PROFILE("convexSweepCompound");
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
|
||||
int i=0;
|
||||
for (i=0;i<compoundShape->getNumChildShapes();i++)
|
||||
struct btCompoundLeafCallback : btDbvt::ICollide
|
||||
{
|
||||
btTransform childTrans = compoundShape->getChildTransform(i);
|
||||
const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i);
|
||||
btTransform childWorldTrans = colObjWorldTransform * childTrans;
|
||||
|
||||
struct LocalInfoAdder : public ConvexResultCallback {
|
||||
ConvexResultCallback* m_userCallback;
|
||||
btCompoundLeafCallback(
|
||||
const btCollisionObjectWrapper* colObjWrap,
|
||||
const btConvexShape* castShape,
|
||||
const btTransform& convexFromTrans,
|
||||
const btTransform& convexToTrans,
|
||||
btScalar allowedPenetration,
|
||||
const btCompoundShape* compoundShape,
|
||||
const btTransform& colObjWorldTransform,
|
||||
ConvexResultCallback& resultCallback)
|
||||
:
|
||||
m_colObjWrap(colObjWrap),
|
||||
m_castShape(castShape),
|
||||
m_convexFromTrans(convexFromTrans),
|
||||
m_convexToTrans(convexToTrans),
|
||||
m_allowedPenetration(allowedPenetration),
|
||||
m_compoundShape(compoundShape),
|
||||
m_colObjWorldTransform(colObjWorldTransform),
|
||||
m_resultCallback(resultCallback) {
|
||||
}
|
||||
|
||||
const btCollisionObjectWrapper* m_colObjWrap;
|
||||
const btConvexShape* m_castShape;
|
||||
const btTransform& m_convexFromTrans;
|
||||
const btTransform& m_convexToTrans;
|
||||
btScalar m_allowedPenetration;
|
||||
const btCompoundShape* m_compoundShape;
|
||||
const btTransform& m_colObjWorldTransform;
|
||||
ConvexResultCallback& m_resultCallback;
|
||||
|
||||
public:
|
||||
|
||||
void ProcessChild(int index, const btTransform& childTrans, const btCollisionShape* childCollisionShape)
|
||||
{
|
||||
btTransform childWorldTrans = m_colObjWorldTransform * childTrans;
|
||||
|
||||
struct LocalInfoAdder : public ConvexResultCallback {
|
||||
ConvexResultCallback* m_userCallback;
|
||||
int m_i;
|
||||
|
||||
LocalInfoAdder (int i, ConvexResultCallback *user)
|
||||
LocalInfoAdder(int i, ConvexResultCallback *user)
|
||||
: m_userCallback(user), m_i(i)
|
||||
{
|
||||
m_closestHitFraction = m_userCallback->m_closestHitFraction;
|
||||
|
|
@ -820,27 +861,66 @@ void btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape,
|
|||
{
|
||||
return m_userCallback->needsCollision(p);
|
||||
}
|
||||
virtual btScalar addSingleResult (btCollisionWorld::LocalConvexResult& r, bool b)
|
||||
{
|
||||
btCollisionWorld::LocalShapeInfo shapeInfo;
|
||||
shapeInfo.m_shapePart = -1;
|
||||
shapeInfo.m_triangleIndex = m_i;
|
||||
if (r.m_localShapeInfo == NULL)
|
||||
r.m_localShapeInfo = &shapeInfo;
|
||||
const btScalar result = m_userCallback->addSingleResult(r, b);
|
||||
m_closestHitFraction = m_userCallback->m_closestHitFraction;
|
||||
return result;
|
||||
|
||||
}
|
||||
};
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& r, bool b)
|
||||
{
|
||||
btCollisionWorld::LocalShapeInfo shapeInfo;
|
||||
shapeInfo.m_shapePart = -1;
|
||||
shapeInfo.m_triangleIndex = m_i;
|
||||
if (r.m_localShapeInfo == NULL)
|
||||
r.m_localShapeInfo = &shapeInfo;
|
||||
const btScalar result = m_userCallback->addSingleResult(r, b);
|
||||
m_closestHitFraction = m_userCallback->m_closestHitFraction;
|
||||
return result;
|
||||
|
||||
LocalInfoAdder my_cb(i, &resultCallback);
|
||||
|
||||
btCollisionObjectWrapper tmpObj(colObjWrap,childCollisionShape,colObjWrap->getCollisionObject(),childWorldTrans,-1,i);
|
||||
}
|
||||
};
|
||||
|
||||
objectQuerySingleInternal(castShape, convexFromTrans,convexToTrans,
|
||||
&tmpObj,my_cb, allowedPenetration);
|
||||
|
||||
LocalInfoAdder my_cb(index, &m_resultCallback);
|
||||
|
||||
btCollisionObjectWrapper tmpObj(m_colObjWrap, childCollisionShape, m_colObjWrap->getCollisionObject(), childWorldTrans, -1, index);
|
||||
|
||||
objectQuerySingleInternal(m_castShape, m_convexFromTrans, m_convexToTrans, &tmpObj, my_cb, m_allowedPenetration);
|
||||
}
|
||||
|
||||
void Process(const btDbvtNode* leaf)
|
||||
{
|
||||
// Processing leaf node
|
||||
int index = leaf->dataAsInt;
|
||||
|
||||
btTransform childTrans = m_compoundShape->getChildTransform(index);
|
||||
const btCollisionShape* childCollisionShape = m_compoundShape->getChildShape(index);
|
||||
|
||||
ProcessChild(index, childTrans, childCollisionShape);
|
||||
}
|
||||
};
|
||||
|
||||
BT_PROFILE("convexSweepCompound");
|
||||
const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(collisionShape);
|
||||
|
||||
btVector3 fromLocalAabbMin, fromLocalAabbMax;
|
||||
btVector3 toLocalAabbMin, toLocalAabbMax;
|
||||
|
||||
castShape->getAabb(colObjWorldTransform.inverse() * convexFromTrans, fromLocalAabbMin, fromLocalAabbMax);
|
||||
castShape->getAabb(colObjWorldTransform.inverse() * convexToTrans, toLocalAabbMin, toLocalAabbMax);
|
||||
|
||||
fromLocalAabbMin.setMin(toLocalAabbMin);
|
||||
fromLocalAabbMax.setMax(toLocalAabbMax);
|
||||
|
||||
btCompoundLeafCallback callback(colObjWrap, castShape, convexFromTrans, convexToTrans,
|
||||
allowedPenetration, compoundShape, colObjWorldTransform, resultCallback);
|
||||
|
||||
const btDbvt* tree = compoundShape->getDynamicAabbTree();
|
||||
if (tree) {
|
||||
const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds = btDbvtVolume::FromMM(fromLocalAabbMin, fromLocalAabbMax);
|
||||
tree->collideTV(tree->m_root, bounds, callback);
|
||||
} else {
|
||||
int i;
|
||||
for (i=0;i<compoundShape->getNumChildShapes();i++)
|
||||
{
|
||||
const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i);
|
||||
btTransform childTrans = compoundShape->getChildTransform(i);
|
||||
callback.ProcessChild(i, childTrans, childCollisionShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1151,7 +1231,7 @@ struct btSingleContactCallback : public btBroadphaseAabbCallback
|
|||
btCollisionObjectWrapper ob0(0,m_collisionObject->getCollisionShape(),m_collisionObject,m_collisionObject->getWorldTransform(),-1,-1);
|
||||
btCollisionObjectWrapper ob1(0,collisionObject->getCollisionShape(),collisionObject,collisionObject->getWorldTransform(),-1,-1);
|
||||
|
||||
btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1);
|
||||
btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1,0, BT_CLOSEST_POINT_ALGORITHMS);
|
||||
if (algorithm)
|
||||
{
|
||||
btBridgedManifoldResult contactPointResult(&ob0,&ob1, m_resultCallback);
|
||||
|
|
@ -1187,10 +1267,11 @@ void btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionOb
|
|||
btCollisionObjectWrapper obA(0,colObjA->getCollisionShape(),colObjA,colObjA->getWorldTransform(),-1,-1);
|
||||
btCollisionObjectWrapper obB(0,colObjB->getCollisionShape(),colObjB,colObjB->getWorldTransform(),-1,-1);
|
||||
|
||||
btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB);
|
||||
btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB, 0, BT_CLOSEST_POINT_ALGORITHMS);
|
||||
if (algorithm)
|
||||
{
|
||||
btBridgedManifoldResult contactPointResult(&obA,&obB, resultCallback);
|
||||
contactPointResult.m_closestPointDistanceThreshold = resultCallback.m_closestDistanceThreshold;
|
||||
//discrete collision detection query
|
||||
algorithm->processCollision(&obA,&obB, getDispatchInfo(),&contactPointResult);
|
||||
|
||||
|
|
@ -1251,7 +1332,10 @@ public:
|
|||
void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color)
|
||||
{
|
||||
// Draw a small simplex at the center of the object
|
||||
getDebugDrawer()->drawTransform(worldTransform,1);
|
||||
if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawFrames)
|
||||
{
|
||||
getDebugDrawer()->drawTransform(worldTransform,1);
|
||||
}
|
||||
|
||||
if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE)
|
||||
{
|
||||
|
|
@ -1429,81 +1513,93 @@ void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const
|
|||
|
||||
void btCollisionWorld::debugDrawWorld()
|
||||
{
|
||||
if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)
|
||||
if (getDebugDrawer())
|
||||
{
|
||||
int numManifolds = getDispatcher()->getNumManifolds();
|
||||
btVector3 color(1,1,0);
|
||||
for (int i=0;i<numManifolds;i++)
|
||||
{
|
||||
btPersistentManifold* contactManifold = getDispatcher()->getManifoldByIndexInternal(i);
|
||||
//btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
|
||||
//btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
|
||||
btIDebugDraw::DefaultColors defaultColors = getDebugDrawer()->getDefaultColors();
|
||||
|
||||
int numContacts = contactManifold->getNumContacts();
|
||||
for (int j=0;j<numContacts;j++)
|
||||
if ( getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)
|
||||
{
|
||||
|
||||
|
||||
if (getDispatcher())
|
||||
{
|
||||
btManifoldPoint& cp = contactManifold->getContactPoint(j);
|
||||
getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color);
|
||||
int numManifolds = getDispatcher()->getNumManifolds();
|
||||
|
||||
for (int i=0;i<numManifolds;i++)
|
||||
{
|
||||
btPersistentManifold* contactManifold = getDispatcher()->getManifoldByIndexInternal(i);
|
||||
//btCollisionObject* obA = static_cast<btCollisionObject*>(contactManifold->getBody0());
|
||||
//btCollisionObject* obB = static_cast<btCollisionObject*>(contactManifold->getBody1());
|
||||
|
||||
int numContacts = contactManifold->getNumContacts();
|
||||
for (int j=0;j<numContacts;j++)
|
||||
{
|
||||
btManifoldPoint& cp = contactManifold->getContactPoint(j);
|
||||
getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),defaultColors.m_contactPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)))
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=0;i<m_collisionObjects.size();i++)
|
||||
if ((getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)))
|
||||
{
|
||||
btCollisionObject* colObj = m_collisionObjects[i];
|
||||
if ((colObj->getCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0)
|
||||
int i;
|
||||
|
||||
for ( i=0;i<m_collisionObjects.size();i++)
|
||||
{
|
||||
if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe))
|
||||
btCollisionObject* colObj = m_collisionObjects[i];
|
||||
if ((colObj->getCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0)
|
||||
{
|
||||
btVector3 color(btScalar(1.),btScalar(1.),btScalar(1.));
|
||||
switch(colObj->getActivationState())
|
||||
if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe))
|
||||
{
|
||||
case ACTIVE_TAG:
|
||||
color = btVector3(btScalar(1.),btScalar(1.),btScalar(1.)); break;
|
||||
case ISLAND_SLEEPING:
|
||||
color = btVector3(btScalar(0.),btScalar(1.),btScalar(0.));break;
|
||||
case WANTS_DEACTIVATION:
|
||||
color = btVector3(btScalar(0.),btScalar(1.),btScalar(1.));break;
|
||||
case DISABLE_DEACTIVATION:
|
||||
color = btVector3(btScalar(1.),btScalar(0.),btScalar(0.));break;
|
||||
case DISABLE_SIMULATION:
|
||||
color = btVector3(btScalar(1.),btScalar(1.),btScalar(0.));break;
|
||||
default:
|
||||
btVector3 color(btScalar(0.4),btScalar(0.4),btScalar(0.4));
|
||||
|
||||
switch(colObj->getActivationState())
|
||||
{
|
||||
color = btVector3(btScalar(1),btScalar(0.),btScalar(0.));
|
||||
}
|
||||
};
|
||||
case ACTIVE_TAG:
|
||||
color = defaultColors.m_activeObject; break;
|
||||
case ISLAND_SLEEPING:
|
||||
color = defaultColors.m_deactivatedObject;break;
|
||||
case WANTS_DEACTIVATION:
|
||||
color = defaultColors.m_wantsDeactivationObject;break;
|
||||
case DISABLE_DEACTIVATION:
|
||||
color = defaultColors.m_disabledDeactivationObject;break;
|
||||
case DISABLE_SIMULATION:
|
||||
color = defaultColors.m_disabledSimulationObject;break;
|
||||
default:
|
||||
{
|
||||
color = btVector3(btScalar(.3),btScalar(0.3),btScalar(0.3));
|
||||
}
|
||||
};
|
||||
|
||||
debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color);
|
||||
}
|
||||
if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
|
||||
{
|
||||
btVector3 minAabb,maxAabb;
|
||||
btVector3 colorvec(1,0,0);
|
||||
colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
|
||||
btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold);
|
||||
minAabb -= contactThreshold;
|
||||
maxAabb += contactThreshold;
|
||||
colObj->getCustomDebugColor(color);
|
||||
|
||||
btVector3 minAabb2,maxAabb2;
|
||||
|
||||
if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject())
|
||||
{
|
||||
colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2);
|
||||
minAabb2 -= contactThreshold;
|
||||
maxAabb2 += contactThreshold;
|
||||
minAabb.setMin(minAabb2);
|
||||
maxAabb.setMax(maxAabb2);
|
||||
debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color);
|
||||
}
|
||||
if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
|
||||
{
|
||||
btVector3 minAabb,maxAabb;
|
||||
btVector3 colorvec = defaultColors.m_aabb;
|
||||
colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb);
|
||||
btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold);
|
||||
minAabb -= contactThreshold;
|
||||
maxAabb += contactThreshold;
|
||||
|
||||
m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec);
|
||||
btVector3 minAabb2,maxAabb2;
|
||||
|
||||
if(getDispatchInfo().m_useContinuous && colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY && !colObj->isStaticOrKinematicObject())
|
||||
{
|
||||
colObj->getCollisionShape()->getAabb(colObj->getInterpolationWorldTransform(),minAabb2,maxAabb2);
|
||||
minAabb2 -= contactThreshold;
|
||||
maxAabb2 += contactThreshold;
|
||||
minAabb.setMin(minAabb2);
|
||||
maxAabb.setMax(maxAabb2);
|
||||
}
|
||||
|
||||
m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1512,15 +1608,6 @@ void btCollisionWorld::debugDrawWorld()
|
|||
void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
|
||||
{
|
||||
int i;
|
||||
//serialize all collision objects
|
||||
for (i=0;i<m_collisionObjects.size();i++)
|
||||
{
|
||||
btCollisionObject* colObj = m_collisionObjects[i];
|
||||
if (colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT)
|
||||
{
|
||||
colObj->serializeSingleObject(serializer);
|
||||
}
|
||||
}
|
||||
|
||||
///keep track of shapes already serialized
|
||||
btHashMap<btHashPtr,btCollisionShape*> serializedShapes;
|
||||
|
|
@ -1537,6 +1624,15 @@ void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer)
|
|||
}
|
||||
}
|
||||
|
||||
//serialize all collision objects
|
||||
for (i=0;i<m_collisionObjects.size();i++)
|
||||
{
|
||||
btCollisionObject* colObj = m_collisionObjects[i];
|
||||
if ((colObj->getInternalType() == btCollisionObject::CO_COLLISION_OBJECT) || (colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK))
|
||||
{
|
||||
colObj->serializeSingleObject(serializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ subject to the following restrictions:
|
|||
* @section install_sec Installation
|
||||
*
|
||||
* @subsection step1 Step 1: Download
|
||||
* You can download the Bullet Physics Library from the Google Code repository: http://code.google.com/p/bullet/downloads/list
|
||||
* You can download the Bullet Physics Library from the github repository: https://github.com/bulletphysics/bullet3/releases
|
||||
*
|
||||
* @subsection step2 Step 2: Building
|
||||
* Bullet has multiple build systems, including premake, cmake and autotools. Premake and cmake support all platforms.
|
||||
|
|
@ -412,10 +412,12 @@ public:
|
|||
{
|
||||
short int m_collisionFilterGroup;
|
||||
short int m_collisionFilterMask;
|
||||
|
||||
btScalar m_closestDistanceThreshold;
|
||||
|
||||
ContactResultCallback()
|
||||
:m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter),
|
||||
m_collisionFilterMask(btBroadphaseProxy::AllFilter)
|
||||
m_collisionFilterMask(btBroadphaseProxy::AllFilter),
|
||||
m_closestDistanceThreshold(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2014 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BT_COLLISION_WORLD_IMPORTER_H
|
||||
#define BT_COLLISION_WORLD_IMPORTER_H
|
||||
|
||||
#include "LinearMath/btTransform.h"
|
||||
#include "LinearMath/btVector3.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "LinearMath/btHashMap.h"
|
||||
|
||||
class btCollisionShape;
|
||||
class btCollisionObject;
|
||||
struct btBulletSerializedArrays;
|
||||
|
||||
|
||||
struct ConstraintInput;
|
||||
class btCollisionWorld;
|
||||
struct btCollisionShapeData;
|
||||
class btTriangleIndexVertexArray;
|
||||
class btStridingMeshInterface;
|
||||
struct btStridingMeshInterfaceData;
|
||||
class btGImpactMeshShape;
|
||||
class btOptimizedBvh;
|
||||
struct btTriangleInfoMap;
|
||||
class btBvhTriangleMeshShape;
|
||||
class btPoint2PointConstraint;
|
||||
class btHingeConstraint;
|
||||
class btConeTwistConstraint;
|
||||
class btGeneric6DofConstraint;
|
||||
class btGeneric6DofSpringConstraint;
|
||||
class btSliderConstraint;
|
||||
class btGearConstraint;
|
||||
struct btContactSolverInfo;
|
||||
|
||||
|
||||
|
||||
|
||||
class btCollisionWorldImporter
|
||||
{
|
||||
protected:
|
||||
btCollisionWorld* m_collisionWorld;
|
||||
|
||||
int m_verboseMode;
|
||||
|
||||
btAlignedObjectArray<btCollisionShape*> m_allocatedCollisionShapes;
|
||||
btAlignedObjectArray<btCollisionObject*> m_allocatedRigidBodies;
|
||||
|
||||
btAlignedObjectArray<btOptimizedBvh*> m_allocatedBvhs;
|
||||
btAlignedObjectArray<btTriangleInfoMap*> m_allocatedTriangleInfoMaps;
|
||||
btAlignedObjectArray<btTriangleIndexVertexArray*> m_allocatedTriangleIndexArrays;
|
||||
btAlignedObjectArray<btStridingMeshInterfaceData*> m_allocatedbtStridingMeshInterfaceDatas;
|
||||
btAlignedObjectArray<btCollisionObject*> m_allocatedCollisionObjects;
|
||||
|
||||
|
||||
btAlignedObjectArray<char*> m_allocatedNames;
|
||||
|
||||
btAlignedObjectArray<int*> m_indexArrays;
|
||||
btAlignedObjectArray<short int*> m_shortIndexArrays;
|
||||
btAlignedObjectArray<unsigned char*> m_charIndexArrays;
|
||||
|
||||
btAlignedObjectArray<btVector3FloatData*> m_floatVertexArrays;
|
||||
btAlignedObjectArray<btVector3DoubleData*> m_doubleVertexArrays;
|
||||
|
||||
|
||||
btHashMap<btHashPtr,btOptimizedBvh*> m_bvhMap;
|
||||
btHashMap<btHashPtr,btTriangleInfoMap*> m_timMap;
|
||||
|
||||
btHashMap<btHashString,btCollisionShape*> m_nameShapeMap;
|
||||
btHashMap<btHashString,btCollisionObject*> m_nameColObjMap;
|
||||
|
||||
btHashMap<btHashPtr,const char*> m_objectNameMap;
|
||||
|
||||
btHashMap<btHashPtr,btCollisionShape*> m_shapeMap;
|
||||
btHashMap<btHashPtr,btCollisionObject*> m_bodyMap;
|
||||
|
||||
|
||||
//methods
|
||||
|
||||
|
||||
|
||||
char* duplicateName(const char* name);
|
||||
|
||||
btCollisionShape* convertCollisionShape( btCollisionShapeData* shapeData );
|
||||
|
||||
|
||||
public:
|
||||
|
||||
btCollisionWorldImporter(btCollisionWorld* world);
|
||||
|
||||
virtual ~btCollisionWorldImporter();
|
||||
|
||||
bool convertAllObjects( btBulletSerializedArrays* arrays);
|
||||
|
||||
///delete all memory collision shapes, rigid bodies, constraints etc. allocated during the load.
|
||||
///make sure you don't use the dynamics world containing objects after you call this method
|
||||
virtual void deleteAllData();
|
||||
|
||||
void setVerboseMode(int verboseMode)
|
||||
{
|
||||
m_verboseMode = verboseMode;
|
||||
}
|
||||
|
||||
int getVerboseMode() const
|
||||
{
|
||||
return m_verboseMode;
|
||||
}
|
||||
|
||||
// query for data
|
||||
int getNumCollisionShapes() const;
|
||||
btCollisionShape* getCollisionShapeByIndex(int index);
|
||||
int getNumRigidBodies() const;
|
||||
btCollisionObject* getRigidBodyByIndex(int index) const;
|
||||
int getNumConstraints() const;
|
||||
|
||||
int getNumBvhs() const;
|
||||
btOptimizedBvh* getBvhByIndex(int index) const;
|
||||
int getNumTriangleInfoMaps() const;
|
||||
btTriangleInfoMap* getTriangleInfoMapByIndex(int index) const;
|
||||
|
||||
// queris involving named objects
|
||||
btCollisionShape* getCollisionShapeByName(const char* name);
|
||||
btCollisionObject* getCollisionObjectByName(const char* name);
|
||||
|
||||
|
||||
const char* getNameForPointer(const void* ptr) const;
|
||||
|
||||
///those virtuals are called by load and can be overridden by the user
|
||||
|
||||
|
||||
|
||||
//bodies
|
||||
|
||||
virtual btCollisionObject* createCollisionObject( const btTransform& startTransform, btCollisionShape* shape,const char* bodyName);
|
||||
|
||||
///shapes
|
||||
|
||||
virtual btCollisionShape* createPlaneShape(const btVector3& planeNormal,btScalar planeConstant);
|
||||
virtual btCollisionShape* createBoxShape(const btVector3& halfExtents);
|
||||
virtual btCollisionShape* createSphereShape(btScalar radius);
|
||||
virtual btCollisionShape* createCapsuleShapeX(btScalar radius, btScalar height);
|
||||
virtual btCollisionShape* createCapsuleShapeY(btScalar radius, btScalar height);
|
||||
virtual btCollisionShape* createCapsuleShapeZ(btScalar radius, btScalar height);
|
||||
|
||||
virtual btCollisionShape* createCylinderShapeX(btScalar radius,btScalar height);
|
||||
virtual btCollisionShape* createCylinderShapeY(btScalar radius,btScalar height);
|
||||
virtual btCollisionShape* createCylinderShapeZ(btScalar radius,btScalar height);
|
||||
virtual btCollisionShape* createConeShapeX(btScalar radius,btScalar height);
|
||||
virtual btCollisionShape* createConeShapeY(btScalar radius,btScalar height);
|
||||
virtual btCollisionShape* createConeShapeZ(btScalar radius,btScalar height);
|
||||
virtual class btTriangleIndexVertexArray* createTriangleMeshContainer();
|
||||
virtual btBvhTriangleMeshShape* createBvhTriangleMeshShape(btStridingMeshInterface* trimesh, btOptimizedBvh* bvh);
|
||||
virtual btCollisionShape* createConvexTriangleMeshShape(btStridingMeshInterface* trimesh);
|
||||
#ifdef SUPPORT_GIMPACT_SHAPE_IMPORT
|
||||
virtual btGImpactMeshShape* createGimpactShape(btStridingMeshInterface* trimesh);
|
||||
#endif //SUPPORT_GIMPACT_SHAPE_IMPORT
|
||||
virtual btStridingMeshInterfaceData* createStridingMeshInterfaceData(btStridingMeshInterfaceData* interfaceData);
|
||||
|
||||
virtual class btConvexHullShape* createConvexHullShape();
|
||||
virtual class btCompoundShape* createCompoundShape();
|
||||
virtual class btScaledBvhTriangleMeshShape* createScaledTrangleMeshShape(btBvhTriangleMeshShape* meshShape,const btVector3& localScalingbtBvhTriangleMeshShape);
|
||||
|
||||
virtual class btMultiSphereShape* createMultiSphereShape(const btVector3* positions,const btScalar* radi,int numSpheres);
|
||||
|
||||
virtual btTriangleIndexVertexArray* createMeshInterface(btStridingMeshInterfaceData& meshData);
|
||||
|
||||
///acceleration and connectivity structures
|
||||
virtual btOptimizedBvh* createOptimizedBvh();
|
||||
virtual btTriangleInfoMap* createTriangleInfoMap();
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //BT_WORLD_IMPORTER_H
|
||||
|
|
@ -65,7 +65,13 @@ void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(const btCollisionO
|
|||
const btCollisionShape* childShape = compoundShape->getChildShape(i);
|
||||
|
||||
btCollisionObjectWrapper childWrap(colObjWrap,childShape,colObjWrap->getCollisionObject(),colObjWrap->getWorldTransform(),-1,i);//wrong child trans, but unused (hopefully)
|
||||
m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap,otherObjWrap,m_sharedManifold);
|
||||
m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap,otherObjWrap,m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS);
|
||||
|
||||
|
||||
btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithmsContact;
|
||||
btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithmsClosestPoints;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,13 +129,19 @@ public:
|
|||
|
||||
//backup
|
||||
btTransform orgTrans = m_compoundColObjWrap->getWorldTransform();
|
||||
btTransform orgInterpolationTrans = m_compoundColObjWrap->getWorldTransform();
|
||||
|
||||
const btTransform& childTrans = compoundShape->getChildTransform(index);
|
||||
btTransform newChildWorldTrans = orgTrans*childTrans ;
|
||||
|
||||
//perform an AABB check first
|
||||
btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1;
|
||||
btVector3 aabbMin0,aabbMax0;
|
||||
childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0);
|
||||
|
||||
btVector3 extendAabb(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold);
|
||||
aabbMin0 -= extendAabb;
|
||||
aabbMax0 += extendAabb;
|
||||
|
||||
btVector3 aabbMin1, aabbMax1;
|
||||
m_otherObjWrap->getCollisionShape()->getAabb(m_otherObjWrap->getWorldTransform(),aabbMin1,aabbMax1);
|
||||
|
||||
if (gCompoundChildShapePairCallback)
|
||||
|
|
@ -142,12 +154,22 @@ public:
|
|||
{
|
||||
|
||||
btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap,childShape,m_compoundColObjWrap->getCollisionObject(),newChildWorldTrans,-1,index);
|
||||
|
||||
btCollisionAlgorithm* algo = 0;
|
||||
|
||||
|
||||
//the contactpoint is still projected back using the original inverted worldtrans
|
||||
if (!m_childCollisionAlgorithms[index])
|
||||
m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap,m_otherObjWrap,m_sharedManifold);
|
||||
|
||||
if (m_resultOut->m_closestPointDistanceThreshold > 0)
|
||||
{
|
||||
algo = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, 0, BT_CLOSEST_POINT_ALGORITHMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
//the contactpoint is still projected back using the original inverted worldtrans
|
||||
if (!m_childCollisionAlgorithms[index])
|
||||
{
|
||||
m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS);
|
||||
}
|
||||
algo = m_childCollisionAlgorithms[index];
|
||||
}
|
||||
|
||||
const btCollisionObjectWrapper* tmpWrap = 0;
|
||||
|
||||
|
|
@ -164,8 +186,7 @@ public:
|
|||
m_resultOut->setShapeIdentifiersB(-1,index);
|
||||
}
|
||||
|
||||
|
||||
m_childCollisionAlgorithms[index]->processCollision(&compoundWrap,m_otherObjWrap,m_dispatchInfo,m_resultOut);
|
||||
algo->processCollision(&compoundWrap,m_otherObjWrap,m_dispatchInfo,m_resultOut);
|
||||
|
||||
#if 0
|
||||
if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb))
|
||||
|
|
@ -229,9 +250,12 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
|
|||
removeChildAlgorithms();
|
||||
|
||||
preallocateChildAlgorithms(body0Wrap,body1Wrap);
|
||||
m_compoundShapeRevision = compoundShape->getUpdateRevision();
|
||||
}
|
||||
|
||||
|
||||
if (m_childCollisionAlgorithms.size()==0)
|
||||
return;
|
||||
|
||||
const btDbvt* tree = compoundShape->getDynamicAabbTree();
|
||||
//use a dynamic aabb tree to cull potential child-overlaps
|
||||
btCompoundLeafCallback callback(colObjWrap,otherObjWrap,m_dispatcher,dispatchInfo,resultOut,&m_childCollisionAlgorithms[0],m_sharedManifold);
|
||||
|
|
@ -241,7 +265,7 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
|
|||
///so we should add a 'refreshManifolds' in the btCollisionAlgorithm
|
||||
{
|
||||
int i;
|
||||
btManifoldArray manifoldArray;
|
||||
manifoldArray.resize(0);
|
||||
for (i=0;i<m_childCollisionAlgorithms.size();i++)
|
||||
{
|
||||
if (m_childCollisionAlgorithms[i])
|
||||
|
|
@ -268,10 +292,13 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
|
|||
btTransform otherInCompoundSpace;
|
||||
otherInCompoundSpace = colObjWrap->getWorldTransform().inverse() * otherObjWrap->getWorldTransform();
|
||||
otherObjWrap->getCollisionShape()->getAabb(otherInCompoundSpace,localAabbMin,localAabbMax);
|
||||
btVector3 extraExtends(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold);
|
||||
localAabbMin -= extraExtends;
|
||||
localAabbMax += extraExtends;
|
||||
|
||||
const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax);
|
||||
//process all children, that overlap with the given AABB bounds
|
||||
tree->collideTV(tree->m_root,bounds,callback);
|
||||
tree->collideTVNoStackAlloc(tree->m_root,bounds,stack2,callback);
|
||||
|
||||
} else
|
||||
{
|
||||
|
|
@ -288,10 +315,10 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
|
|||
//iterate over all children, perform an AABB check inside ProcessChildShape
|
||||
int numChildren = m_childCollisionAlgorithms.size();
|
||||
int i;
|
||||
btManifoldArray manifoldArray;
|
||||
manifoldArray.resize(0);
|
||||
const btCollisionShape* childShape = 0;
|
||||
btTransform orgTrans;
|
||||
btTransform orgInterpolationTrans;
|
||||
|
||||
btTransform newChildWorldTrans;
|
||||
btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1;
|
||||
|
||||
|
|
@ -301,8 +328,8 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
|
|||
{
|
||||
childShape = compoundShape->getChildShape(i);
|
||||
//if not longer overlapping, remove the algorithm
|
||||
orgTrans = colObjWrap->getWorldTransform();
|
||||
orgInterpolationTrans = colObjWrap->getWorldTransform();
|
||||
orgTrans = colObjWrap->getWorldTransform();
|
||||
|
||||
const btTransform& childTrans = compoundShape->getChildTransform(i);
|
||||
newChildWorldTrans = orgTrans*childTrans ;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class btDispatcher;
|
|||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
|
||||
#include "btCollisionCreateFunc.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btDbvt.h"
|
||||
class btDispatcher;
|
||||
class btCollisionObject;
|
||||
|
||||
|
|
@ -36,6 +37,10 @@ extern btShapePairCallback gCompoundChildShapePairCallback;
|
|||
/// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes
|
||||
class btCompoundCollisionAlgorithm : public btActivatingCollisionAlgorithm
|
||||
{
|
||||
btNodeStack stack2;
|
||||
btManifoldArray manifoldArray;
|
||||
|
||||
protected:
|
||||
btAlignedObjectArray<btCollisionAlgorithm*> m_childCollisionAlgorithms;
|
||||
bool m_isSwapped;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ subject to the following restrictions:
|
|||
*/
|
||||
|
||||
#include "btCompoundCompoundCollisionAlgorithm.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
||||
#include "BulletCollision/CollisionShapes/btCompoundShape.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btDbvt.h"
|
||||
|
|
@ -27,10 +28,8 @@ subject to the following restrictions:
|
|||
btShapePairCallback gCompoundCompoundChildShapePairCallback = 0;
|
||||
|
||||
btCompoundCompoundCollisionAlgorithm::btCompoundCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped)
|
||||
:btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap),
|
||||
m_sharedManifold(ci.m_manifold)
|
||||
:btCompoundCollisionAlgorithm(ci,body0Wrap,body1Wrap,isSwapped)
|
||||
{
|
||||
m_ownsManifold = false;
|
||||
|
||||
void* ptr = btAlignedAlloc(sizeof(btHashedSimplePairCache),16);
|
||||
m_childCollisionAlgorithmCache= new(ptr) btHashedSimplePairCache();
|
||||
|
|
@ -114,10 +113,9 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
|
|||
btManifoldResult* resultOut,
|
||||
btHashedSimplePairCache* childAlgorithmsCache,
|
||||
btPersistentManifold* sharedManifold)
|
||||
:m_compound0ColObjWrap(compound1ObjWrap),m_compound1ColObjWrap(compound0ObjWrap),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut),
|
||||
:m_numOverlapPairs(0),m_compound0ColObjWrap(compound1ObjWrap),m_compound1ColObjWrap(compound0ObjWrap),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut),
|
||||
m_childCollisionAlgorithmCache(childAlgorithmsCache),
|
||||
m_sharedManifold(sharedManifold),
|
||||
m_numOverlapPairs(0)
|
||||
m_sharedManifold(sharedManifold)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -127,6 +125,7 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
|
|||
|
||||
void Process(const btDbvtNode* leaf0,const btDbvtNode* leaf1)
|
||||
{
|
||||
BT_PROFILE("btCompoundCompoundLeafCallback::Process");
|
||||
m_numOverlapPairs++;
|
||||
|
||||
|
||||
|
|
@ -162,6 +161,11 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
|
|||
childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0);
|
||||
childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1);
|
||||
|
||||
btVector3 thresholdVec(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold);
|
||||
|
||||
aabbMin0 -= thresholdVec;
|
||||
aabbMax0 += thresholdVec;
|
||||
|
||||
if (gCompoundCompoundChildShapePairCallback)
|
||||
{
|
||||
if (!gCompoundCompoundChildShapePairCallback(childShape0,childShape1))
|
||||
|
|
@ -177,17 +181,24 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
|
|||
btSimplePair* pair = m_childCollisionAlgorithmCache->findPair(childIndex0,childIndex1);
|
||||
|
||||
btCollisionAlgorithm* colAlgo = 0;
|
||||
if (m_resultOut->m_closestPointDistanceThreshold > 0)
|
||||
{
|
||||
colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, 0, BT_CLOSEST_POINT_ALGORITHMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pair)
|
||||
{
|
||||
colAlgo = (btCollisionAlgorithm*)pair->m_userPointer;
|
||||
|
||||
if (pair)
|
||||
{
|
||||
colAlgo = (btCollisionAlgorithm*)pair->m_userPointer;
|
||||
|
||||
} else
|
||||
{
|
||||
colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0,&compoundWrap1,m_sharedManifold);
|
||||
pair = m_childCollisionAlgorithmCache->addOverlappingPair(childIndex0,childIndex1);
|
||||
btAssert(pair);
|
||||
pair->m_userPointer = colAlgo;
|
||||
}
|
||||
else
|
||||
{
|
||||
colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS);
|
||||
pair = m_childCollisionAlgorithmCache->addOverlappingPair(childIndex0, childIndex1);
|
||||
btAssert(pair);
|
||||
pair->m_userPointer = colAlgo;
|
||||
}
|
||||
}
|
||||
|
||||
btAssert(colAlgo);
|
||||
|
|
@ -218,10 +229,12 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide
|
|||
|
||||
|
||||
static DBVT_INLINE bool MyIntersect( const btDbvtAabbMm& a,
|
||||
const btDbvtAabbMm& b, const btTransform& xform)
|
||||
const btDbvtAabbMm& b, const btTransform& xform, btScalar distanceThreshold)
|
||||
{
|
||||
btVector3 newmin,newmax;
|
||||
btTransformAabb(b.Mins(),b.Maxs(),0.f,xform,newmin,newmax);
|
||||
newmin -= btVector3(distanceThreshold, distanceThreshold, distanceThreshold);
|
||||
newmax += btVector3(distanceThreshold, distanceThreshold, distanceThreshold);
|
||||
btDbvtAabbMm newb = btDbvtAabbMm::FromMM(newmin,newmax);
|
||||
return Intersect(a,newb);
|
||||
}
|
||||
|
|
@ -230,7 +243,7 @@ static DBVT_INLINE bool MyIntersect( const btDbvtAabbMm& a,
|
|||
static inline void MycollideTT( const btDbvtNode* root0,
|
||||
const btDbvtNode* root1,
|
||||
const btTransform& xform,
|
||||
btCompoundCompoundLeafCallback* callback)
|
||||
btCompoundCompoundLeafCallback* callback, btScalar distanceThreshold)
|
||||
{
|
||||
|
||||
if(root0&&root1)
|
||||
|
|
@ -242,7 +255,7 @@ static inline void MycollideTT( const btDbvtNode* root0,
|
|||
stkStack[0]=btDbvt::sStkNN(root0,root1);
|
||||
do {
|
||||
btDbvt::sStkNN p=stkStack[--depth];
|
||||
if(MyIntersect(p.a->volume,p.b->volume,xform))
|
||||
if(MyIntersect(p.a->volume,p.b->volume,xform, distanceThreshold))
|
||||
{
|
||||
if(depth>treshold)
|
||||
{
|
||||
|
|
@ -292,12 +305,21 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb
|
|||
const btCompoundShape* compoundShape0 = static_cast<const btCompoundShape*>(col0ObjWrap->getCollisionShape());
|
||||
const btCompoundShape* compoundShape1 = static_cast<const btCompoundShape*>(col1ObjWrap->getCollisionShape());
|
||||
|
||||
const btDbvt* tree0 = compoundShape0->getDynamicAabbTree();
|
||||
const btDbvt* tree1 = compoundShape1->getDynamicAabbTree();
|
||||
if (!tree0 || !tree1)
|
||||
{
|
||||
return btCompoundCollisionAlgorithm::processCollision(body0Wrap,body1Wrap,dispatchInfo,resultOut);
|
||||
}
|
||||
///btCompoundShape might have changed:
|
||||
////make sure the internal child collision algorithm caches are still valid
|
||||
if ((compoundShape0->getUpdateRevision() != m_compoundShapeRevision0) || (compoundShape1->getUpdateRevision() != m_compoundShapeRevision1))
|
||||
{
|
||||
///clear all
|
||||
removeChildAlgorithms();
|
||||
m_compoundShapeRevision0 = compoundShape0->getUpdateRevision();
|
||||
m_compoundShapeRevision1 = compoundShape1->getUpdateRevision();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -329,14 +351,13 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb
|
|||
}
|
||||
|
||||
|
||||
const btDbvt* tree0 = compoundShape0->getDynamicAabbTree();
|
||||
const btDbvt* tree1 = compoundShape1->getDynamicAabbTree();
|
||||
|
||||
|
||||
btCompoundCompoundLeafCallback callback(col0ObjWrap,col1ObjWrap,this->m_dispatcher,dispatchInfo,resultOut,this->m_childCollisionAlgorithmCache,m_sharedManifold);
|
||||
|
||||
|
||||
const btTransform xform=col0ObjWrap->getWorldTransform().inverse()*col1ObjWrap->getWorldTransform();
|
||||
MycollideTT(tree0->m_root,tree1->m_root,xform,&callback);
|
||||
MycollideTT(tree0->m_root,tree1->m_root,xform,&callback, resultOut->m_closestPointDistanceThreshold);
|
||||
|
||||
//printf("#compound-compound child/leaf overlap =%d \r",callback.m_numOverlapPairs);
|
||||
|
||||
|
|
@ -376,7 +397,9 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb
|
|||
newChildWorldTrans0 = orgTrans0*childTrans0 ;
|
||||
childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0);
|
||||
}
|
||||
|
||||
btVector3 thresholdVec(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold);
|
||||
aabbMin0 -= thresholdVec;
|
||||
aabbMax0 += thresholdVec;
|
||||
{
|
||||
btTransform orgInterpolationTrans1;
|
||||
const btCollisionShape* childShape1 = 0;
|
||||
|
|
@ -391,7 +414,8 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb
|
|||
childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1);
|
||||
}
|
||||
|
||||
|
||||
aabbMin1 -= thresholdVec;
|
||||
aabbMax1 += thresholdVec;
|
||||
|
||||
if (!TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ subject to the following restrictions:
|
|||
#ifndef BT_COMPOUND_COMPOUND_COLLISION_ALGORITHM_H
|
||||
#define BT_COMPOUND_COMPOUND_COLLISION_ALGORITHM_H
|
||||
|
||||
#include "btCompoundCollisionAlgorithm.h"
|
||||
|
||||
#include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btDispatcher.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
|
||||
|
|
@ -35,15 +37,12 @@ typedef bool (*btShapePairCallback)(const btCollisionShape* pShape0, const btCol
|
|||
extern btShapePairCallback gCompoundCompoundChildShapePairCallback;
|
||||
|
||||
/// btCompoundCompoundCollisionAlgorithm supports collision between two btCompoundCollisionShape shapes
|
||||
class btCompoundCompoundCollisionAlgorithm : public btActivatingCollisionAlgorithm
|
||||
class btCompoundCompoundCollisionAlgorithm : public btCompoundCollisionAlgorithm
|
||||
{
|
||||
|
||||
class btHashedSimplePairCache* m_childCollisionAlgorithmCache;
|
||||
btSimplePairArray m_removePairs;
|
||||
|
||||
class btPersistentManifold* m_sharedManifold;
|
||||
bool m_ownsManifold;
|
||||
|
||||
|
||||
int m_compoundShapeRevision0;//to keep track of changes, so that childAlgorithm array can be updated
|
||||
int m_compoundShapeRevision1;
|
||||
|
|
|
|||
|
|
@ -47,8 +47,6 @@ subject to the following restrictions:
|
|||
|
||||
btConvex2dConvex2dAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
|
||||
{
|
||||
m_numPerturbationIterations = 0;
|
||||
m_minimumPointsPerturbationThreshold = 3;
|
||||
m_simplexSolver = simplexSolver;
|
||||
m_pdSolver = pdSolver;
|
||||
}
|
||||
|
|
@ -57,15 +55,13 @@ btConvex2dConvex2dAlgorithm::CreateFunc::~CreateFunc()
|
|||
{
|
||||
}
|
||||
|
||||
btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
|
||||
btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int /* numPerturbationIterations */, int /* minimumPointsPerturbationThreshold */)
|
||||
: btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap),
|
||||
m_simplexSolver(simplexSolver),
|
||||
m_pdSolver(pdSolver),
|
||||
m_ownManifold (false),
|
||||
m_manifoldPtr(mf),
|
||||
m_lowLevelOfDetail(false),
|
||||
m_numPerturbationIterations(numPerturbationIterations),
|
||||
m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold)
|
||||
m_lowLevelOfDetail(false)
|
||||
{
|
||||
(void)body0Wrap;
|
||||
(void)body1Wrap;
|
||||
|
|
|
|||
|
|
@ -40,9 +40,6 @@ class btConvex2dConvex2dAlgorithm : public btActivatingCollisionAlgorithm
|
|||
btPersistentManifold* m_manifoldPtr;
|
||||
bool m_lowLevelOfDetail;
|
||||
|
||||
int m_numPerturbationIterations;
|
||||
int m_minimumPointsPerturbationThreshold;
|
||||
|
||||
public:
|
||||
|
||||
btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ subject to the following restrictions:
|
|||
|
||||
|
||||
#include "btConvexConcaveCollisionAlgorithm.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
||||
#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
|
||||
#include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h"
|
||||
|
|
@ -79,6 +80,7 @@ void btConvexTriangleCallback::clearCache()
|
|||
void btConvexTriangleCallback::processTriangle(btVector3* triangle,int
|
||||
partId, int triangleIndex)
|
||||
{
|
||||
BT_PROFILE("btConvexTriangleCallback::processTriangle");
|
||||
|
||||
if (!TestTriangleAgainstAabb2(triangle, m_aabbMin, m_aabbMax))
|
||||
{
|
||||
|
|
@ -88,20 +90,19 @@ partId, int triangleIndex)
|
|||
//just for debugging purposes
|
||||
//printf("triangle %d",m_triangleCount++);
|
||||
|
||||
const btCollisionObject* ob = const_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
|
||||
|
||||
|
||||
btCollisionAlgorithmConstructionInfo ci;
|
||||
ci.m_dispatcher1 = m_dispatcher;
|
||||
|
||||
//const btCollisionObject* ob = static_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
///debug drawing of the overlapping triangles
|
||||
if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe ))
|
||||
{
|
||||
const btCollisionObject* ob = const_cast<btCollisionObject*>(m_triBodyWrap->getCollisionObject());
|
||||
btVector3 color(1,1,0);
|
||||
btTransform& tr = ob->getWorldTransform();
|
||||
m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color);
|
||||
|
|
@ -117,8 +118,16 @@ partId, int triangleIndex)
|
|||
|
||||
|
||||
btCollisionObjectWrapper triObWrap(m_triBodyWrap,&tm,m_triBodyWrap->getCollisionObject(),m_triBodyWrap->getWorldTransform(),partId,triangleIndex);//correct transform?
|
||||
btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap,&triObWrap,m_manifoldPtr);
|
||||
|
||||
btCollisionAlgorithm* colAlgo = 0;
|
||||
|
||||
if (m_resultOut->m_closestPointDistanceThreshold > 0)
|
||||
{
|
||||
colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap, &triObWrap, 0, BT_CLOSEST_POINT_ALGORITHMS);
|
||||
}
|
||||
else
|
||||
{
|
||||
colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap, &triObWrap, m_manifoldPtr, BT_CONTACT_POINT_ALGORITHMS);
|
||||
}
|
||||
const btCollisionObjectWrapper* tmpWrap = 0;
|
||||
|
||||
if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject())
|
||||
|
|
@ -169,7 +178,8 @@ void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTr
|
|||
const btCollisionShape* convexShape = static_cast<const btCollisionShape*>(m_convexBodyWrap->getCollisionShape());
|
||||
//CollisionShape* triangleShape = static_cast<btCollisionShape*>(triBody->m_collisionShape);
|
||||
convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax);
|
||||
btScalar extraMargin = collisionMarginTriangle;
|
||||
btScalar extraMargin = collisionMarginTriangle+ resultOut->m_closestPointDistanceThreshold;
|
||||
|
||||
btVector3 extra(extraMargin,extraMargin,extraMargin);
|
||||
|
||||
m_aabbMax += extra;
|
||||
|
|
@ -185,7 +195,7 @@ void btConvexConcaveCollisionAlgorithm::clearCache()
|
|||
|
||||
void btConvexConcaveCollisionAlgorithm::processCollision (const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut)
|
||||
{
|
||||
|
||||
BT_PROFILE("btConvexConcaveCollisionAlgorithm::processCollision");
|
||||
|
||||
const btCollisionObjectWrapper* convexBodyWrap = m_isSwapped ? body1Wrap : body0Wrap;
|
||||
const btCollisionObjectWrapper* triBodyWrap = m_isSwapped ? body0Wrap : body1Wrap;
|
||||
|
|
@ -266,6 +276,7 @@ btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObj
|
|||
|
||||
virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex)
|
||||
{
|
||||
BT_PROFILE("processTriangle");
|
||||
(void)partId;
|
||||
(void)triangleIndex;
|
||||
//do a swept sphere for now
|
||||
|
|
|
|||
|
|
@ -26,14 +26,16 @@ class btDispatcher;
|
|||
#include "btCollisionCreateFunc.h"
|
||||
|
||||
///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called.
|
||||
class btConvexTriangleCallback : public btTriangleCallback
|
||||
ATTRIBUTE_ALIGNED16(class) btConvexTriangleCallback : public btTriangleCallback
|
||||
{
|
||||
const btCollisionObjectWrapper* m_convexBodyWrap;
|
||||
const btCollisionObjectWrapper* m_triBodyWrap;
|
||||
|
||||
btVector3 m_aabbMin;
|
||||
btVector3 m_aabbMax ;
|
||||
|
||||
const btCollisionObjectWrapper* m_convexBodyWrap;
|
||||
const btCollisionObjectWrapper* m_triBodyWrap;
|
||||
|
||||
|
||||
|
||||
btManifoldResult* m_resultOut;
|
||||
btDispatcher* m_dispatcher;
|
||||
|
|
@ -41,6 +43,8 @@ class btConvexTriangleCallback : public btTriangleCallback
|
|||
btScalar m_collisionMarginTriangle;
|
||||
|
||||
public:
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
int m_triangleCount;
|
||||
|
||||
btPersistentManifold* m_manifoldPtr;
|
||||
|
|
@ -75,17 +79,19 @@ int m_triangleCount;
|
|||
|
||||
|
||||
/// btConvexConcaveCollisionAlgorithm supports collision between convex shapes and (concave) trianges meshes.
|
||||
class btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm
|
||||
ATTRIBUTE_ALIGNED16(class) btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm
|
||||
{
|
||||
|
||||
bool m_isSwapped;
|
||||
|
||||
btConvexTriangleCallback m_btConvexTriangleCallback;
|
||||
|
||||
bool m_isSwapped;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped);
|
||||
|
||||
virtual ~btConvexConcaveCollisionAlgorithm();
|
||||
|
|
|
|||
|
|
@ -179,11 +179,10 @@ static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance(
|
|||
|
||||
|
||||
|
||||
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver)
|
||||
btConvexConvexAlgorithm::CreateFunc::CreateFunc(btConvexPenetrationDepthSolver* pdSolver)
|
||||
{
|
||||
m_numPerturbationIterations = 0;
|
||||
m_minimumPointsPerturbationThreshold = 3;
|
||||
m_simplexSolver = simplexSolver;
|
||||
m_pdSolver = pdSolver;
|
||||
}
|
||||
|
||||
|
|
@ -191,9 +190,8 @@ btConvexConvexAlgorithm::CreateFunc::~CreateFunc()
|
|||
{
|
||||
}
|
||||
|
||||
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
|
||||
btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold)
|
||||
: btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap),
|
||||
m_simplexSolver(simplexSolver),
|
||||
m_pdSolver(pdSolver),
|
||||
m_ownManifold (false),
|
||||
m_manifoldPtr(mf),
|
||||
|
|
@ -349,8 +347,8 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
|
|||
|
||||
|
||||
btGjkPairDetector::ClosestPointInput input;
|
||||
|
||||
btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver);
|
||||
btVoronoiSimplexSolver simplexSolver;
|
||||
btGjkPairDetector gjkPairDetector( min0, min1, &simplexSolver, m_pdSolver );
|
||||
//TODO: if (dispatchInfo.m_useContinuous)
|
||||
gjkPairDetector.setMinkowskiA(min0);
|
||||
gjkPairDetector.setMinkowskiB(min1);
|
||||
|
|
@ -367,7 +365,7 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
|
|||
// input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold();
|
||||
//} else
|
||||
//{
|
||||
input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold();
|
||||
input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold()+resultOut->m_closestPointDistanceThreshold;
|
||||
// }
|
||||
|
||||
input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared;
|
||||
|
|
@ -503,9 +501,11 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
|
|||
|
||||
// printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ());
|
||||
|
||||
worldVertsB1.resize(0);
|
||||
btPolyhedralContactClipping::clipHullAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(),
|
||||
body0Wrap->getWorldTransform(),
|
||||
body1Wrap->getWorldTransform(), minDist-threshold, threshold, *resultOut);
|
||||
body1Wrap->getWorldTransform(), minDist-threshold, threshold, worldVertsB1,worldVertsB2,
|
||||
*resultOut);
|
||||
|
||||
}
|
||||
if (m_ownManifold)
|
||||
|
|
@ -568,8 +568,9 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper*
|
|||
|
||||
if (foundSepAxis)
|
||||
{
|
||||
worldVertsB2.resize(0);
|
||||
btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(),
|
||||
body0Wrap->getWorldTransform(), vertices, minDist-threshold, maxDist, *resultOut);
|
||||
body0Wrap->getWorldTransform(), vertices, worldVertsB2,minDist-threshold, maxDist, *resultOut);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ subject to the following restrictions:
|
|||
#include "btCollisionCreateFunc.h"
|
||||
#include "btCollisionDispatcher.h"
|
||||
#include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil
|
||||
#include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h"
|
||||
|
||||
class btConvexPenetrationDepthSolver;
|
||||
|
||||
|
|
@ -42,9 +43,10 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm
|
|||
#ifdef USE_SEPDISTANCE_UTIL2
|
||||
btConvexSeparatingDistanceUtil m_sepDistance;
|
||||
#endif
|
||||
btSimplexSolverInterface* m_simplexSolver;
|
||||
btConvexPenetrationDepthSolver* m_pdSolver;
|
||||
|
||||
btVertexArray worldVertsB1;
|
||||
btVertexArray worldVertsB2;
|
||||
|
||||
bool m_ownManifold;
|
||||
btPersistentManifold* m_manifoldPtr;
|
||||
|
|
@ -59,7 +61,7 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm
|
|||
|
||||
public:
|
||||
|
||||
btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold);
|
||||
btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold);
|
||||
|
||||
virtual ~btConvexConvexAlgorithm();
|
||||
|
||||
|
|
@ -87,18 +89,17 @@ public:
|
|||
{
|
||||
|
||||
btConvexPenetrationDepthSolver* m_pdSolver;
|
||||
btSimplexSolverInterface* m_simplexSolver;
|
||||
int m_numPerturbationIterations;
|
||||
int m_minimumPointsPerturbationThreshold;
|
||||
|
||||
CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver);
|
||||
CreateFunc(btConvexPenetrationDepthSolver* pdSolver);
|
||||
|
||||
virtual ~CreateFunc();
|
||||
|
||||
virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap)
|
||||
{
|
||||
void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm));
|
||||
return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold);
|
||||
return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,9 +44,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
|
|||
//btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool)
|
||||
{
|
||||
|
||||
void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16);
|
||||
m_simplexSolver = new (mem)btVoronoiSimplexSolver();
|
||||
|
||||
void* mem = NULL;
|
||||
if (constructionInfo.m_useEpaPenetrationAlgorithm)
|
||||
{
|
||||
mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16);
|
||||
|
|
@ -59,7 +57,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
|
|||
|
||||
//default CreationFunctions, filling the m_doubleDispatch table
|
||||
mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16);
|
||||
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver);
|
||||
m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_pdSolver);
|
||||
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
|
||||
m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc;
|
||||
mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16);
|
||||
|
|
@ -105,12 +103,12 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
|
|||
int maxSize = sizeof(btConvexConvexAlgorithm);
|
||||
int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm);
|
||||
int maxSize3 = sizeof(btCompoundCollisionAlgorithm);
|
||||
int sl = sizeof(btConvexSeparatingDistanceUtil);
|
||||
sl = sizeof(btGjkPairDetector);
|
||||
int maxSize4 = sizeof(btCompoundCompoundCollisionAlgorithm);
|
||||
|
||||
int collisionAlgorithmMaxElementSize = btMax(maxSize,constructionInfo.m_customCollisionAlgorithmMaxElementSize);
|
||||
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2);
|
||||
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3);
|
||||
|
||||
collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize4);
|
||||
|
||||
if (constructionInfo.m_persistentManifoldPool)
|
||||
{
|
||||
|
|
@ -123,6 +121,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault
|
|||
m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize);
|
||||
}
|
||||
|
||||
collisionAlgorithmMaxElementSize = (collisionAlgorithmMaxElementSize+16)&0xffffffffffff0;
|
||||
if (constructionInfo.m_collisionAlgorithmPool)
|
||||
{
|
||||
m_ownsCollisionAlgorithmPool = false;
|
||||
|
|
@ -192,9 +191,6 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration()
|
|||
m_planeConvexCF->~btCollisionAlgorithmCreateFunc();
|
||||
btAlignedFree( m_planeConvexCF);
|
||||
|
||||
m_simplexSolver->~btVoronoiSimplexSolver();
|
||||
btAlignedFree(m_simplexSolver);
|
||||
|
||||
m_pdSolver->~btConvexPenetrationDepthSolver();
|
||||
|
||||
btAlignedFree(m_pdSolver);
|
||||
|
|
@ -202,6 +198,86 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration()
|
|||
|
||||
}
|
||||
|
||||
btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1)
|
||||
{
|
||||
|
||||
|
||||
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE))
|
||||
{
|
||||
return m_sphereSphereCF;
|
||||
}
|
||||
#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM
|
||||
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE))
|
||||
{
|
||||
return m_sphereBoxCF;
|
||||
}
|
||||
|
||||
if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE))
|
||||
{
|
||||
return m_boxSphereCF;
|
||||
}
|
||||
#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM
|
||||
|
||||
|
||||
if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == TRIANGLE_SHAPE_PROXYTYPE))
|
||||
{
|
||||
return m_sphereTriangleCF;
|
||||
}
|
||||
|
||||
if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE))
|
||||
{
|
||||
return m_triangleSphereCF;
|
||||
}
|
||||
|
||||
if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE))
|
||||
{
|
||||
return m_convexPlaneCF;
|
||||
}
|
||||
|
||||
if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE))
|
||||
{
|
||||
return m_planeConvexCF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1))
|
||||
{
|
||||
return m_convexConvexCreateFunc;
|
||||
}
|
||||
|
||||
if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1))
|
||||
{
|
||||
return m_convexConcaveCreateFunc;
|
||||
}
|
||||
|
||||
if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0))
|
||||
{
|
||||
return m_swappedConvexConcaveCreateFunc;
|
||||
}
|
||||
|
||||
|
||||
if (btBroadphaseProxy::isCompound(proxyType0) && btBroadphaseProxy::isCompound(proxyType1))
|
||||
{
|
||||
return m_compoundCompoundCreateFunc;
|
||||
}
|
||||
|
||||
if (btBroadphaseProxy::isCompound(proxyType0))
|
||||
{
|
||||
return m_compoundCreateFunc;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (btBroadphaseProxy::isCompound(proxyType1))
|
||||
{
|
||||
return m_swappedCompoundCreateFunc;
|
||||
}
|
||||
}
|
||||
|
||||
//failed to find an algorithm
|
||||
return m_emptyCreateFunc;
|
||||
|
||||
}
|
||||
|
||||
btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,8 +60,7 @@ protected:
|
|||
btPoolAllocator* m_collisionAlgorithmPool;
|
||||
bool m_ownsCollisionAlgorithmPool;
|
||||
|
||||
//default simplex/penetration depth solvers
|
||||
btVoronoiSimplexSolver* m_simplexSolver;
|
||||
//default penetration depth solver
|
||||
btConvexPenetrationDepthSolver* m_pdSolver;
|
||||
|
||||
//default CreationFunctions, filling the m_doubleDispatch table
|
||||
|
|
@ -102,14 +101,10 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual btVoronoiSimplexSolver* getSimplexSolver()
|
||||
{
|
||||
return m_simplexSolver;
|
||||
}
|
||||
|
||||
|
||||
virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1);
|
||||
|
||||
virtual btCollisionAlgorithmCreateFunc* getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1);
|
||||
|
||||
///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm.
|
||||
///By default, this feature is disabled for best performance.
|
||||
///@param numPerturbationIterations controls the number of collision queries. Set it to zero to disable the feature.
|
||||
|
|
|
|||
|
|
@ -28,9 +28,7 @@ int gFindSimplePairs =0;
|
|||
|
||||
|
||||
|
||||
btHashedSimplePairCache::btHashedSimplePairCache():
|
||||
m_blockedForChanges(false)
|
||||
{
|
||||
btHashedSimplePairCache::btHashedSimplePairCache() {
|
||||
int initialAllocatedSize= 2;
|
||||
m_overlappingPairArray.reserve(initialAllocatedSize);
|
||||
growTables();
|
||||
|
|
|
|||
|
|
@ -55,9 +55,7 @@ extern int gFindSimplePairs;
|
|||
class btHashedSimplePairCache
|
||||
{
|
||||
btSimplePairArray m_overlappingPairArray;
|
||||
|
||||
bool m_blockedForChanges;
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ struct btConnectivityProcessor : public btTriangleCallback
|
|||
btScalar len2 = calculatedEdge.length2();
|
||||
|
||||
btScalar correctedAngle(0);
|
||||
btVector3 calculatedNormalB = normalA;
|
||||
//btVector3 calculatedNormalB = normalA;
|
||||
bool isConvex = false;
|
||||
|
||||
if (len2<m_triangleInfoMap->m_planarEpsilon)
|
||||
|
|
@ -213,10 +213,6 @@ struct btConnectivityProcessor : public btTriangleCallback
|
|||
isConvex = (dotA<0.);
|
||||
|
||||
correctedAngle = isConvex ? ang4 : -ang4;
|
||||
btQuaternion orn2(calculatedEdge,-correctedAngle);
|
||||
calculatedNormalB = btMatrix3x3(orn2)*normalA;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,9 @@ ContactAddedCallback gContactAddedCallback=0;
|
|||
|
||||
|
||||
|
||||
///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback;
|
||||
inline btScalar calculateCombinedRollingFriction(const btCollisionObject* body0,const btCollisionObject* body1)
|
||||
btScalar btManifoldResult::calculateCombinedRollingFriction(const btCollisionObject* body0,const btCollisionObject* body1)
|
||||
{
|
||||
btScalar friction = body0->getRollingFriction() * body1->getRollingFriction();
|
||||
btScalar friction = body0->getRollingFriction() * body1->getFriction() + body1->getRollingFriction() * body0->getFriction();
|
||||
|
||||
const btScalar MAX_FRICTION = btScalar(10.);
|
||||
if (friction < -MAX_FRICTION)
|
||||
|
|
@ -38,6 +37,17 @@ inline btScalar calculateCombinedRollingFriction(const btCollisionObject* body0,
|
|||
|
||||
}
|
||||
|
||||
btScalar btManifoldResult::calculateCombinedSpinningFriction(const btCollisionObject* body0,const btCollisionObject* body1)
|
||||
{
|
||||
btScalar friction = body0->getSpinningFriction() * body1->getFriction() + body1->getSpinningFriction() * body0->getFriction();
|
||||
|
||||
const btScalar MAX_FRICTION = btScalar(10.);
|
||||
if (friction < -MAX_FRICTION)
|
||||
friction = -MAX_FRICTION;
|
||||
if (friction > MAX_FRICTION)
|
||||
friction = MAX_FRICTION;
|
||||
return friction;
|
||||
}
|
||||
|
||||
///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback;
|
||||
btScalar btManifoldResult::calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1)
|
||||
|
|
@ -58,6 +68,22 @@ btScalar btManifoldResult::calculateCombinedRestitution(const btCollisionObject*
|
|||
return body0->getRestitution() * body1->getRestitution();
|
||||
}
|
||||
|
||||
btScalar btManifoldResult::calculateCombinedContactDamping(const btCollisionObject* body0,const btCollisionObject* body1)
|
||||
{
|
||||
return body0->getContactDamping() + body1->getContactDamping();
|
||||
}
|
||||
|
||||
btScalar btManifoldResult::calculateCombinedContactStiffness(const btCollisionObject* body0,const btCollisionObject* body1)
|
||||
{
|
||||
|
||||
btScalar s0 = body0->getContactStiffness();
|
||||
btScalar s1 = body1->getContactStiffness();
|
||||
|
||||
btScalar tmp0 = btScalar(1)/s0;
|
||||
btScalar tmp1 = btScalar(1)/s1;
|
||||
btScalar combinedStiffness = btScalar(1) / (tmp0+tmp1);
|
||||
return combinedStiffness;
|
||||
}
|
||||
|
||||
|
||||
btManifoldResult::btManifoldResult(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap)
|
||||
|
|
@ -70,6 +96,7 @@ btManifoldResult::btManifoldResult(const btCollisionObjectWrapper* body0Wrap,con
|
|||
m_index0(-1),
|
||||
m_index1(-1)
|
||||
#endif //DEBUG_PART_INDEX
|
||||
, m_closestPointDistanceThreshold(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +136,16 @@ void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const b
|
|||
newPt.m_combinedFriction = calculateCombinedFriction(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject());
|
||||
newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject());
|
||||
newPt.m_combinedRollingFriction = calculateCombinedRollingFriction(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject());
|
||||
newPt.m_combinedSpinningFriction = calculateCombinedSpinningFriction(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject());
|
||||
|
||||
if ( (m_body0Wrap->getCollisionObject()->getCollisionFlags()& btCollisionObject::CF_HAS_CONTACT_STIFFNESS_DAMPING) ||
|
||||
(m_body1Wrap->getCollisionObject()->getCollisionFlags()& btCollisionObject::CF_HAS_CONTACT_STIFFNESS_DAMPING))
|
||||
{
|
||||
newPt.m_combinedContactDamping1 = calculateCombinedContactDamping(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject());
|
||||
newPt.m_combinedContactStiffness1 = calculateCombinedContactStiffness(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject());
|
||||
newPt.m_contactPointFlags |= BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING;
|
||||
}
|
||||
|
||||
btPlaneSpace1(newPt.m_normalWorldOnB,newPt.m_lateralFrictionDir1,newPt.m_lateralFrictionDir2);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -49,17 +49,19 @@ protected:
|
|||
int m_index0;
|
||||
int m_index1;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
btManifoldResult()
|
||||
#ifdef DEBUG_PART_INDEX
|
||||
:
|
||||
#ifdef DEBUG_PART_INDEX
|
||||
|
||||
m_partId0(-1),
|
||||
m_partId1(-1),
|
||||
m_index0(-1),
|
||||
m_index1(-1)
|
||||
#endif //DEBUG_PART_INDEX
|
||||
m_closestPointDistanceThreshold(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -142,9 +144,15 @@ public:
|
|||
return m_body1Wrap->getCollisionObject();
|
||||
}
|
||||
|
||||
btScalar m_closestPointDistanceThreshold;
|
||||
|
||||
/// in the future we can let the user override the methods to combine restitution and friction
|
||||
static btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
static btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
static btScalar calculateCombinedRollingFriction(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
static btScalar calculateCombinedSpinningFriction(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
static btScalar calculateCombinedContactDamping(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
static btScalar calculateCombinedContactStiffness(const btCollisionObject* body0,const btCollisionObject* body1);
|
||||
};
|
||||
|
||||
#endif //BT_MANIFOLD_RESULT_H
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ subject to the following restrictions:
|
|||
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.
|
||||
*/
|
||||
#define CLEAR_MANIFOLD 1
|
||||
|
||||
#include "btSphereSphereCollisionAlgorithm.h"
|
||||
#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
|
||||
|
|
@ -62,7 +63,7 @@ void btSphereSphereCollisionAlgorithm::processCollision (const btCollisionObject
|
|||
#endif
|
||||
|
||||
///iff distance positive, don't generate a new contact
|
||||
if ( len > (radius0+radius1))
|
||||
if ( len > (radius0+radius1+resultOut->m_closestPointDistanceThreshold))
|
||||
{
|
||||
#ifndef CLEAR_MANIFOLD
|
||||
resultOut->refreshContactPoints();
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ void btSphereTriangleCollisionAlgorithm::processCollision (const btCollisionObje
|
|||
|
||||
/// report a contact. internally this will be kept persistent, and contact reduction is done
|
||||
resultOut->setPersistentManifold(m_manifoldPtr);
|
||||
SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold());
|
||||
SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold);
|
||||
|
||||
btDiscreteCollisionDetectorInterface::ClosestPointInput input;
|
||||
input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);///@todo: tighter bounds
|
||||
|
|
|
|||
|
|
@ -245,16 +245,18 @@ void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,co
|
|||
btStridingMeshInterface* m_meshInterface;
|
||||
btTriangleCallback* m_callback;
|
||||
btVector3 m_triangle[3];
|
||||
|
||||
int m_numOverlap;
|
||||
|
||||
MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface)
|
||||
:m_meshInterface(meshInterface),
|
||||
m_callback(callback)
|
||||
m_callback(callback),
|
||||
m_numOverlap(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void processNode(int nodeSubPart, int nodeTriangleIndex)
|
||||
{
|
||||
m_numOverlap++;
|
||||
const unsigned char *vertexbase;
|
||||
int numverts;
|
||||
PHY_ScalarType type;
|
||||
|
|
@ -321,8 +323,7 @@ void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,co
|
|||
MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface);
|
||||
|
||||
m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax);
|
||||
|
||||
|
||||
|
||||
#endif//DISABLE_BVH
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,11 @@ ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape
|
|||
|
||||
bool m_useQuantizedAabbCompression;
|
||||
bool m_ownsBvh;
|
||||
#ifdef __clang__
|
||||
bool m_pad[11] __attribute__((unused));////need padding due to alignment
|
||||
#else
|
||||
bool m_pad[11];////need padding due to alignment
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ public:
|
|||
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
||||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const;
|
||||
|
||||
SIMD_FORCE_INLINE void deSerializeFloat(struct btCapsuleShapeData* dataBuffer);
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -181,4 +182,13 @@ SIMD_FORCE_INLINE const char* btCapsuleShape::serialize(void* dataBuffer, btSeri
|
|||
return "btCapsuleShapeData";
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE void btCapsuleShape::deSerializeFloat(btCapsuleShapeData* dataBuffer)
|
||||
{
|
||||
m_implicitShapeDimensions.deSerializeFloat(dataBuffer->m_convexInternalShapeData.m_implicitShapeDimensions);
|
||||
m_collisionMargin = dataBuffer->m_convexInternalShapeData.m_collisionMargin;
|
||||
m_localScaling.deSerializeFloat(dataBuffer->m_convexInternalShapeData.m_localScaling);
|
||||
//it is best to already pre-allocate the matching btCapsuleShape*(X/Z) version to match m_upAxis
|
||||
m_upAxis = dataBuffer->m_upAxis;
|
||||
}
|
||||
|
||||
#endif //BT_CAPSULE_SHAPE_H
|
||||
|
|
|
|||
|
|
@ -29,12 +29,13 @@ ATTRIBUTE_ALIGNED16(class) btCollisionShape
|
|||
protected:
|
||||
int m_shapeType;
|
||||
void* m_userPointer;
|
||||
int m_userIndex;
|
||||
|
||||
public:
|
||||
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0)
|
||||
btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0), m_userIndex(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ public:
|
|||
|
||||
virtual void getBoundingSphere(btVector3& center,btScalar& radius) const;
|
||||
|
||||
///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations.
|
||||
///getAngularMotionDisc returns the maximum radius needed for Conservative Advancement to handle time-of-impact with rotations.
|
||||
virtual btScalar getAngularMotionDisc() const;
|
||||
|
||||
virtual btScalar getContactBreakingThreshold(btScalar defaultContactThresholdFactor) const;
|
||||
|
|
@ -130,6 +131,16 @@ public:
|
|||
{
|
||||
return m_userPointer;
|
||||
}
|
||||
void setUserIndex(int index)
|
||||
{
|
||||
m_userIndex = index;
|
||||
}
|
||||
|
||||
int getUserIndex() const
|
||||
{
|
||||
return m_userIndex;
|
||||
}
|
||||
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ subject to the following restrictions:
|
|||
#include "BulletCollision/BroadphaseCollision/btDbvt.h"
|
||||
#include "LinearMath/btSerializer.h"
|
||||
|
||||
btCompoundShape::btCompoundShape(bool enableDynamicAabbTree)
|
||||
btCompoundShape::btCompoundShape(bool enableDynamicAabbTree, const int initialChildCapacity)
|
||||
: m_localAabbMin(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)),
|
||||
m_localAabbMax(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)),
|
||||
m_dynamicAabbTree(0),
|
||||
|
|
@ -34,6 +34,8 @@ m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.))
|
|||
m_dynamicAabbTree = new(mem) btDbvt();
|
||||
btAssert(mem==m_dynamicAabbTree);
|
||||
}
|
||||
|
||||
m_children.reserve(initialChildCapacity);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -77,8 +79,8 @@ void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisio
|
|||
if (m_dynamicAabbTree)
|
||||
{
|
||||
const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax);
|
||||
int index = m_children.size();
|
||||
child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index);
|
||||
size_t index = m_children.size();
|
||||
child.m_node = m_dynamicAabbTree->insert(bounds,reinterpret_cast<void*>(index) );
|
||||
}
|
||||
|
||||
m_children.push_back(child);
|
||||
|
|
@ -312,7 +314,8 @@ void btCompoundShape::createAabbTreeFromChildren()
|
|||
child.m_childShape->getAabb(child.m_transform,localAabbMin,localAabbMax);
|
||||
|
||||
const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax);
|
||||
child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index);
|
||||
size_t index2 = index;
|
||||
child.m_node = m_dynamicAabbTree->insert(bounds, reinterpret_cast<void*>(index2) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ SIMD_FORCE_INLINE bool operator==(const btCompoundShapeChild& c1, const btCompou
|
|||
/// Currently, removal of child shapes is only supported when disabling the aabb tree (pass 'false' in the constructor of btCompoundShape)
|
||||
ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape
|
||||
{
|
||||
protected:
|
||||
btAlignedObjectArray<btCompoundShapeChild> m_children;
|
||||
btVector3 m_localAabbMin;
|
||||
btVector3 m_localAabbMax;
|
||||
|
|
@ -64,13 +65,12 @@ ATTRIBUTE_ALIGNED16(class) btCompoundShape : public btCollisionShape
|
|||
|
||||
btScalar m_collisionMargin;
|
||||
|
||||
protected:
|
||||
btVector3 m_localScaling;
|
||||
|
||||
public:
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btCompoundShape(bool enableDynamicAabbTree = true);
|
||||
explicit btCompoundShape(bool enableDynamicAabbTree = true, const int initialChildCapacity = 0);
|
||||
|
||||
virtual ~btCompoundShape();
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,15 @@ public:
|
|||
btScalar getRadius() const { return m_radius;}
|
||||
btScalar getHeight() const { return m_height;}
|
||||
|
||||
void setRadius(const btScalar radius)
|
||||
{
|
||||
m_radius = radius;
|
||||
}
|
||||
void setHeight(const btScalar height)
|
||||
{
|
||||
m_height = height;
|
||||
}
|
||||
|
||||
|
||||
virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ subject to the following restrictions:
|
|||
|
||||
#include "LinearMath/btQuaternion.h"
|
||||
#include "LinearMath/btSerializer.h"
|
||||
#include "btConvexPolyhedron.h"
|
||||
#include "LinearMath/btConvexHullComputer.h"
|
||||
|
||||
btConvexHullShape ::btConvexHullShape (const btScalar* points,int numPoints,int stride) : btPolyhedralConvexAabbCachingShape ()
|
||||
{
|
||||
|
|
@ -121,10 +123,17 @@ btVector3 btConvexHullShape::localGetSupportingVertex(const btVector3& vec)const
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void btConvexHullShape::optimizeConvexHull()
|
||||
{
|
||||
btConvexHullComputer conv;
|
||||
conv.compute(&m_unscaledPoints[0].getX(), sizeof(btVector3),m_unscaledPoints.size(),0.f,0.f);
|
||||
int numVerts = conv.vertices.size();
|
||||
m_unscaledPoints.resize(0);
|
||||
for (int i=0;i<numVerts;i++)
|
||||
{
|
||||
m_unscaledPoints.push_back(conv.vertices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,9 +55,8 @@ public:
|
|||
return getUnscaledPoints();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void optimizeConvexHull();
|
||||
|
||||
SIMD_FORCE_INLINE btVector3 getScaledPoint(int i) const
|
||||
{
|
||||
return m_unscaledPoints[i] * m_localScaling;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ subject to the following restrictions:
|
|||
#include "btConvexPolyhedron.h"
|
||||
#include "LinearMath/btHashMap.h"
|
||||
|
||||
|
||||
btConvexPolyhedron::btConvexPolyhedron()
|
||||
{
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ btConvexPolyhedron::~btConvexPolyhedron()
|
|||
|
||||
inline bool IsAlmostZero(const btVector3& v)
|
||||
{
|
||||
if(fabsf(v.x())>1e-6 || fabsf(v.y())>1e-6 || fabsf(v.z())>1e-6) return false;
|
||||
if(btFabs(v.x())>1e-6 || btFabs(v.y())>1e-6 || btFabs(v.z())>1e-6) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ btConvexShape::~btConvexShape()
|
|||
}
|
||||
|
||||
|
||||
void btConvexShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const
|
||||
void btConvexShape::project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max, btVector3& witnesPtMin,btVector3& witnesPtMax) const
|
||||
{
|
||||
btVector3 localAxis = dir*trans.getBasis();
|
||||
btVector3 vtx1 = trans(localGetSupportingVertex(localAxis));
|
||||
|
|
@ -56,12 +56,16 @@ void btConvexShape::project(const btTransform& trans, const btVector3& dir, btSc
|
|||
|
||||
min = vtx1.dot(dir);
|
||||
max = vtx2.dot(dir);
|
||||
|
||||
witnesPtMax = vtx2;
|
||||
witnesPtMin = vtx1;
|
||||
|
||||
if(min>max)
|
||||
{
|
||||
btScalar tmp = min;
|
||||
min = max;
|
||||
max = tmp;
|
||||
witnesPtMax = vtx1;
|
||||
witnesPtMin = vtx2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ public:
|
|||
btScalar getMarginNonVirtual () const;
|
||||
void getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const;
|
||||
|
||||
virtual void project(const btTransform& trans, const btVector3& dir, btScalar& min, btScalar& max) const;
|
||||
|
||||
virtual void project(const btTransform& trans, const btVector3& dir, btScalar& minProj, btScalar& maxProj, btVector3& witnesPtMin,btVector3& witnesPtMax) const;
|
||||
|
||||
|
||||
//notice that the vectors should be unit length
|
||||
|
|
|
|||
|
|
@ -59,15 +59,13 @@ PHY_ScalarType hdt, bool flipQuadEdges
|
|||
)
|
||||
{
|
||||
// validation
|
||||
btAssert(heightStickWidth > 1 && "bad width");
|
||||
btAssert(heightStickLength > 1 && "bad length");
|
||||
btAssert(heightfieldData && "null heightfield data");
|
||||
btAssert(heightStickWidth > 1);// && "bad width");
|
||||
btAssert(heightStickLength > 1);// && "bad length");
|
||||
btAssert(heightfieldData);// && "null heightfield data");
|
||||
// btAssert(heightScale) -- do we care? Trust caller here
|
||||
btAssert(minHeight <= maxHeight && "bad min/max height");
|
||||
btAssert(upAxis >= 0 && upAxis < 3 &&
|
||||
"bad upAxis--should be in range [0,2]");
|
||||
btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT &&
|
||||
"Bad height data type enum");
|
||||
btAssert(minHeight <= maxHeight);// && "bad min/max height");
|
||||
btAssert(upAxis >= 0 && upAxis < 3);// && "bad upAxis--should be in range [0,2]");
|
||||
btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT);// && "Bad height data type enum");
|
||||
|
||||
// initialize member variables
|
||||
m_shapeType = TERRAIN_SHAPE_PROXYTYPE;
|
||||
|
|
@ -110,7 +108,7 @@ PHY_ScalarType hdt, bool flipQuadEdges
|
|||
default:
|
||||
{
|
||||
//need to get valid m_upAxis
|
||||
btAssert(0 && "Bad m_upAxis");
|
||||
btAssert(0);// && "Bad m_upAxis");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -365,14 +363,15 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback
|
|||
{
|
||||
//first triangle
|
||||
getVertex(x,j,vertices[0]);
|
||||
getVertex(x+1,j,vertices[1]);
|
||||
getVertex(x+1,j+1,vertices[2]);
|
||||
getVertex(x, j + 1, vertices[1]);
|
||||
getVertex(x + 1, j + 1, vertices[2]);
|
||||
callback->processTriangle(vertices,x,j);
|
||||
//second triangle
|
||||
// getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman
|
||||
getVertex(x+1,j+1,vertices[1]);
|
||||
getVertex(x,j+1,vertices[2]);
|
||||
callback->processTriangle(vertices,x,j);
|
||||
getVertex(x + 1, j, vertices[2]);
|
||||
callback->processTriangle(vertices, x, j);
|
||||
|
||||
} else
|
||||
{
|
||||
//first triangle
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ btMultiSphereShape::btMultiSphereShape (const btVector3* positions,const btScala
|
|||
int inner_count = MIN( numSpheres - k, 128 );
|
||||
for( long i = 0; i < inner_count; i++ )
|
||||
{
|
||||
temp[i] = (*pos) +vec*m_localScaling*(*rad) - vec * getMargin();
|
||||
temp[i] = (*pos)*m_localScaling +vec*m_localScaling*(*rad) - vec * getMargin();
|
||||
pos++;
|
||||
rad++;
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ btMultiSphereShape::btMultiSphereShape (const btVector3* positions,const btScala
|
|||
int inner_count = MIN( numSpheres - k, 128 );
|
||||
for( long i = 0; i < inner_count; i++ )
|
||||
{
|
||||
temp[i] = (*pos) +vec*m_localScaling*(*rad) - vec * getMargin();
|
||||
temp[i] = (*pos)*m_localScaling +vec*m_localScaling*(*rad) - vec * getMargin();
|
||||
pos++;
|
||||
rad++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ subject to the following restrictions:
|
|||
ATTRIBUTE_ALIGNED16(class) btMultimaterialTriangleMeshShape : public btBvhTriangleMeshShape
|
||||
{
|
||||
btAlignedObjectArray <btMaterial*> m_materialList;
|
||||
int ** m_triangleMaterials;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ subject to the following restrictions:
|
|||
btStaticPlaneShape::btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant)
|
||||
: btConcaveShape (), m_planeNormal(planeNormal.normalized()),
|
||||
m_planeConstant(planeConstant),
|
||||
m_localScaling(btScalar(0.),btScalar(0.),btScalar(0.))
|
||||
m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.))
|
||||
{
|
||||
m_shapeType = STATIC_PLANE_PROXYTYPE;
|
||||
// btAssert( btFuzzyZero(m_planeNormal.length() - btScalar(1.)) );
|
||||
|
|
|
|||
|
|
@ -75,6 +75,13 @@ void btTriangleMesh::addIndex(int index)
|
|||
}
|
||||
}
|
||||
|
||||
void btTriangleMesh::addTriangleIndices(int index1, int index2, int index3 )
|
||||
{
|
||||
m_indexedMeshes[0].m_numTriangles++;
|
||||
addIndex( index1 );
|
||||
addIndex( index2 );
|
||||
addIndex( index3 );
|
||||
}
|
||||
|
||||
int btTriangleMesh::findOrAddVertex(const btVector3& vertex, bool removeDuplicateVertices)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -52,7 +52,10 @@ class btTriangleMesh : public btTriangleIndexVertexArray
|
|||
///By default addTriangle won't search for duplicate vertices, because the search is very slow for large triangle meshes.
|
||||
///In general it is better to directly use btTriangleIndexVertexArray instead.
|
||||
void addTriangle(const btVector3& vertex0,const btVector3& vertex1,const btVector3& vertex2, bool removeDuplicateVertices=false);
|
||||
|
||||
|
||||
///Add a triangle using its indices. Make sure the indices are pointing within the vertices array, so add the vertices first (and to be sure, avoid removal of duplicate vertices)
|
||||
void addTriangleIndices(int index1, int index2, int index3 );
|
||||
|
||||
int getNumTriangles() const;
|
||||
|
||||
virtual void preallocateVertices(int numverts);
|
||||
|
|
|
|||
|
|
@ -1,746 +0,0 @@
|
|||
# Doxyfile 1.2.4
|
||||
|
||||
# This file describes the settings to be used by doxygen for a project
|
||||
#
|
||||
# All text after a hash (#) is considered a comment and will be ignored
|
||||
# The format is:
|
||||
# TAG = value [value, ...]
|
||||
# For lists items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (" ")
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# General configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
|
||||
# by quotes) that should identify the project.
|
||||
PROJECT_NAME = "Bullet Continuous Collision Detection Library"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
|
||||
# This could be handy for archiving the generated documentation or
|
||||
# if some version control system is used.
|
||||
|
||||
PROJECT_NUMBER =
|
||||
|
||||
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# base path where the generated documentation will be put.
|
||||
# If a relative path is entered, it will be relative to the location
|
||||
# where doxygen was started. If left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY =
|
||||
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# The default language is English, other supported languages are:
|
||||
# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese,
|
||||
# Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian,
|
||||
# Polish, Portuguese and Slovene.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
|
||||
# documentation are documented, even if no documentation was available.
|
||||
# Private class members and static file members will be hidden unless
|
||||
# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
|
||||
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_PRIVATE = YES
|
||||
|
||||
# If the EXTRACT_STATIC tag is set to YES all static members of a file
|
||||
# will be included in the documentation.
|
||||
|
||||
EXTRACT_STATIC = YES
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
|
||||
# undocumented members of documented classes, files or namespaces.
|
||||
# If set to NO (the default) these members will be included in the
|
||||
# various overviews, but no documentation section is generated.
|
||||
# This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
|
||||
# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
|
||||
# undocumented classes that are normally visible in the class hierarchy.
|
||||
# If set to NO (the default) these class will be included in the various
|
||||
# overviews. This option has no effect if EXTRACT_ALL is enabled.
|
||||
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
|
||||
# include brief member descriptions after the members that are listed in
|
||||
# the file and class documentation (similar to JavaDoc).
|
||||
# Set to NO to disable this.
|
||||
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
|
||||
# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
|
||||
# the brief description of a member or function before the detailed description.
|
||||
# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
|
||||
# brief descriptions will be completely suppressed.
|
||||
|
||||
REPEAT_BRIEF = YES
|
||||
|
||||
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
|
||||
# Doxygen will generate a detailed section even if there is only a brief
|
||||
# description.
|
||||
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
|
||||
# path before files name in the file list and in the header files. If set
|
||||
# to NO the shortest path that makes the file name unique will be used.
|
||||
|
||||
FULL_PATH_NAMES = NO
|
||||
|
||||
# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
|
||||
# can be used to strip a user defined part of the path. Stripping is
|
||||
# only done if one of the specified strings matches the left-hand part of
|
||||
# the path. It is allowed to use relative paths in the argument list.
|
||||
|
||||
STRIP_FROM_PATH =
|
||||
|
||||
# The INTERNAL_DOCS tag determines if documentation
|
||||
# that is typed after a \internal command is included. If the tag is set
|
||||
# to NO (the default) then the documentation will be excluded.
|
||||
# Set it to YES to include the internal documentation.
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
|
||||
# generate a class diagram (in Html and LaTeX) for classes with base or
|
||||
# super classes. Setting the tag to NO turns the diagrams off.
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# If the SOURCE_BROWSER tag is set to YES then a list of source files will
|
||||
# be generated. Documented entities will be cross-referenced with these sources.
|
||||
|
||||
SOURCE_BROWSER = YES
|
||||
|
||||
# Setting the INLINE_SOURCES tag to YES will include the body
|
||||
# of functions and classes directly in the documentation.
|
||||
|
||||
INLINE_SOURCES = NO
|
||||
|
||||
# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
|
||||
# doxygen to hide any special comment blocks from generated source code
|
||||
# fragments. Normal C and C++ comments will always remain visible.
|
||||
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
|
||||
# file names in lower case letters. If set to YES upper case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# users are adviced to set this option to NO.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
|
||||
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
|
||||
# will show members with their full class and namespace scopes in the
|
||||
# documentation. If set to YES the scope will be hidden.
|
||||
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
|
||||
# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
|
||||
# will generate a verbatim copy of the header file for each class for
|
||||
# which an include is specified. Set to NO to disable this.
|
||||
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
|
||||
# will put list of the files that are included by a file in the documentation
|
||||
# of that file.
|
||||
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
|
||||
# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
|
||||
# will interpret the first line (until the first dot) of a JavaDoc-style
|
||||
# comment as the brief description. If set to NO, the JavaDoc
|
||||
# comments will behave just like the Qt-style comments (thus requiring an
|
||||
# explict @brief command for a brief description.
|
||||
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
|
||||
# member inherits the documentation from any documented member that it
|
||||
# reimplements.
|
||||
|
||||
INHERIT_DOCS = YES
|
||||
|
||||
# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
|
||||
# is inserted in the documentation for inline members.
|
||||
|
||||
INLINE_INFO = YES
|
||||
|
||||
# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
|
||||
# will sort the (detailed) documentation of file and class members
|
||||
# alphabetically by member name. If set to NO the members will appear in
|
||||
# declaration order.
|
||||
|
||||
SORT_MEMBER_DOCS = YES
|
||||
|
||||
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
|
||||
# tag is set to YES, then doxygen will reuse the documentation of the first
|
||||
# member in the group (if any) for the other members of the group. By default
|
||||
# all members of a group must be documented explicitly.
|
||||
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
|
||||
# The TAB_SIZE tag can be used to set the number of spaces in a tab.
|
||||
# Doxygen uses this value to replace tabs by spaces in code fragments.
|
||||
|
||||
TAB_SIZE = 8
|
||||
|
||||
# The ENABLE_SECTIONS tag can be used to enable conditional
|
||||
# documentation sections, marked by \if sectionname ... \endif.
|
||||
|
||||
ENABLED_SECTIONS =
|
||||
|
||||
# The GENERATE_TODOLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the todo list. This list is created by putting \todo
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TODOLIST = YES
|
||||
|
||||
# The GENERATE_TESTLIST tag can be used to enable (YES) or
|
||||
# disable (NO) the test list. This list is created by putting \test
|
||||
# commands in the documentation.
|
||||
|
||||
GENERATE_TESTLIST = YES
|
||||
|
||||
# This tag can be used to specify a number of aliases that acts
|
||||
# as commands in the documentation. An alias has the form "name=value".
|
||||
# For example adding "sideeffect=\par Side Effects:\n" will allow you to
|
||||
# put the command \sideeffect (or @sideeffect) in the documentation, which
|
||||
# will result in a user defined paragraph with heading "Side Effects:".
|
||||
# You can put \n's in the value part of an alias to insert newlines.
|
||||
|
||||
ALIASES =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The QUIET tag can be used to turn on/off the messages that are generated
|
||||
# by doxygen. Possible values are YES and NO. If left blank NO is used.
|
||||
|
||||
QUIET = NO
|
||||
|
||||
# The WARNINGS tag can be used to turn on/off the warning messages that are
|
||||
# generated by doxygen. Possible values are YES and NO. If left blank
|
||||
# NO is used.
|
||||
|
||||
WARNINGS = YES
|
||||
|
||||
# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
|
||||
# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
|
||||
# automatically be disabled.
|
||||
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
|
||||
# The WARN_FORMAT tag determines the format of the warning messages that
|
||||
# doxygen can produce. The string should contain the $file, $line, and $text
|
||||
# tags, which will be replaced by the file and line number from which the
|
||||
# warning originated and the warning text.
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning
|
||||
# and error messages should be written. If left blank the output is written
|
||||
# to stderr.
|
||||
|
||||
WARN_LOGFILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The INPUT tag can be used to specify the files and/or directories that contain
|
||||
# documented source files. You may enter file names like "myfile.cpp" or
|
||||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = .
|
||||
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
FILE_PATTERNS = *.h *.cpp *.c
|
||||
|
||||
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
|
||||
# should be searched for input files as well. Possible values are YES and NO.
|
||||
# If left blank NO is used.
|
||||
|
||||
RECURSIVE = YES
|
||||
|
||||
# The EXCLUDE tag can be used to specify files and/or directories that should
|
||||
# excluded from the INPUT source files. This way you can easily exclude a
|
||||
# subdirectory from a directory tree whose root is specified with the INPUT tag.
|
||||
|
||||
EXCLUDE =
|
||||
|
||||
# If the value of the INPUT tag contains directories, you can use the
|
||||
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
|
||||
# certain files from those directories.
|
||||
|
||||
EXCLUDE_PATTERNS =
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH =
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
# and *.h) to filter out the source-files in the directories. If left
|
||||
# blank all files are included.
|
||||
|
||||
EXAMPLE_PATTERNS =
|
||||
|
||||
# The IMAGE_PATH tag can be used to specify one or more files or
|
||||
# directories that contain image that are included in the documentation (see
|
||||
# the \image command).
|
||||
|
||||
IMAGE_PATH =
|
||||
|
||||
# The INPUT_FILTER tag can be used to specify a program that doxygen should
|
||||
# invoke to filter for each input file. Doxygen will invoke the filter program
|
||||
# by executing (via popen()) the command <filter> <input-file>, where <filter>
|
||||
# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
|
||||
# input file. Doxygen will then use the output that the filter program writes
|
||||
# to standard output.
|
||||
|
||||
INPUT_FILTER =
|
||||
|
||||
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
|
||||
# INPUT_FILTER) will be used to filter the input files when producing source
|
||||
# files to browse.
|
||||
|
||||
FILTER_SOURCE_FILES = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
|
||||
# of all compounds will be generated. Enable this if the project
|
||||
# contains a lot of classes, structs, unions or interfaces.
|
||||
|
||||
ALPHABETICAL_INDEX = NO
|
||||
|
||||
# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
|
||||
# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
|
||||
# in which this list will be split (can be a number in the range [1..20])
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all
|
||||
# classes will be put under the same header in the alphabetical index.
|
||||
# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
|
||||
# should be ignored while generating the index headers.
|
||||
|
||||
IGNORE_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
|
||||
# generate HTML output.
|
||||
|
||||
GENERATE_HTML = YES
|
||||
|
||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `html' will be used as the default path.
|
||||
|
||||
HTML_OUTPUT = html
|
||||
|
||||
# The HTML_HEADER tag can be used to specify a personal HTML header for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard header.
|
||||
|
||||
HTML_HEADER =
|
||||
|
||||
# The HTML_FOOTER tag can be used to specify a personal HTML footer for
|
||||
# each generated HTML page. If it is left blank doxygen will generate a
|
||||
# standard footer.
|
||||
|
||||
HTML_FOOTER =
|
||||
|
||||
# The HTML_STYLESHEET tag can be used to specify a user defined cascading
|
||||
# style sheet that is used by each HTML page. It can be used to
|
||||
# fine-tune the look of the HTML output. If the tag is left blank doxygen
|
||||
# will generate a default style sheet
|
||||
|
||||
HTML_STYLESHEET =
|
||||
|
||||
# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
|
||||
# files or namespaces will be aligned in HTML using tables. If set to
|
||||
# NO a bullet list will be used.
|
||||
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
|
||||
# If the GENERATE_HTMLHELP tag is set to YES, additional index files
|
||||
# will be generated that can be used as input for tools like the
|
||||
# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
|
||||
# of the generated HTML documentation.
|
||||
|
||||
GENERATE_HTMLHELP = NO
|
||||
|
||||
# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
|
||||
# top of each HTML page. The value NO (the default) enables the index and
|
||||
# the value YES disables it.
|
||||
|
||||
DISABLE_INDEX = NO
|
||||
|
||||
# This tag can be used to set the number of enum values (range [1..20])
|
||||
# that doxygen will group on one line in the generated HTML documentation.
|
||||
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
|
||||
# If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be
|
||||
# generated containing a tree-like index structure (just like the one that
|
||||
# is generated for HTML Help). For this to work a browser that supports
|
||||
# JavaScript and frames is required (for instance Netscape 4.0+
|
||||
# or Internet explorer 4.0+).
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
|
||||
# used to set the initial width (in pixels) of the frame in which the tree
|
||||
# is shown.
|
||||
|
||||
TREEVIEW_WIDTH = 250
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
|
||||
# generate Latex output.
|
||||
|
||||
GENERATE_LATEX = NO
|
||||
|
||||
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `latex' will be used as the default path.
|
||||
|
||||
LATEX_OUTPUT = latex
|
||||
|
||||
# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
|
||||
# LaTeX documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_LATEX = NO
|
||||
|
||||
# The PAPER_TYPE tag can be used to set the paper type that is used
|
||||
# by the printer. Possible values are: a4, a4wide, letter, legal and
|
||||
# executive. If left blank a4wide will be used.
|
||||
|
||||
PAPER_TYPE = a4wide
|
||||
|
||||
# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
|
||||
# packages that should be included in the LaTeX output.
|
||||
|
||||
EXTRA_PACKAGES =
|
||||
|
||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
|
||||
# the generated latex document. The header should contain everything until
|
||||
# the first chapter. If it is left blank doxygen will generate a
|
||||
# standard header. Notice: only use this tag if you know what you are doing!
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
|
||||
# is prepared for conversion to pdf (using ps2pdf). The pdf file will
|
||||
# contain links (just like the HTML output) instead of page references
|
||||
# This makes the output suitable for online browsing using a pdf viewer.
|
||||
|
||||
PDF_HYPERLINKS = NO
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
|
||||
# plain latex in the generated Makefile. Set this option to YES to get a
|
||||
# higher quality PDF documentation.
|
||||
|
||||
USE_PDFLATEX = NO
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep
|
||||
# running if errors occur, instead of asking the user for help.
|
||||
# This option is also used when generating formulas in HTML.
|
||||
|
||||
LATEX_BATCHMODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
|
||||
# The RTF output is optimised for Word 97 and may not look very pretty with
|
||||
# other RTF readers or editors.
|
||||
|
||||
GENERATE_RTF = NO
|
||||
|
||||
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `rtf' will be used as the default path.
|
||||
|
||||
RTF_OUTPUT = rtf
|
||||
|
||||
# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
|
||||
# RTF documents. This may be useful for small projects and may help to
|
||||
# save some trees in general.
|
||||
|
||||
COMPACT_RTF = NO
|
||||
|
||||
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
|
||||
# will contain hyperlink fields. The RTF file will
|
||||
# contain links (just like the HTML output) instead of page references.
|
||||
# This makes the output suitable for online browsing using a WORD or other.
|
||||
# programs which support those fields.
|
||||
# Note: wordpad (write) and others do not support links.
|
||||
|
||||
RTF_HYPERLINKS = NO
|
||||
|
||||
# Load stylesheet definitions from file. Syntax is similar to doxygen's
|
||||
# config file, i.e. a series of assigments. You only have to provide
|
||||
# replacements, missing definitions are set to their default value.
|
||||
|
||||
RTF_STYLESHEET_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
|
||||
# generate man pages
|
||||
|
||||
GENERATE_MAN = NO
|
||||
|
||||
# The MAN_OUTPUT tag is used to specify where the man pages will be put.
|
||||
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
|
||||
# put in front of it. If left blank `man' will be used as the default path.
|
||||
|
||||
MAN_OUTPUT = man
|
||||
|
||||
# The MAN_EXTENSION tag determines the extension that is added to
|
||||
# the generated man pages (default is the subroutine's section .3)
|
||||
|
||||
MAN_EXTENSION = .3
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_XML tag is set to YES Doxygen will
|
||||
# generate an XML file that captures the structure of
|
||||
# the code including all documentation. Warning: This feature
|
||||
# is still experimental and very incomplete.
|
||||
|
||||
GENERATE_XML = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
|
||||
# evaluate all C-preprocessor directives found in the sources and include
|
||||
# files.
|
||||
|
||||
ENABLE_PREPROCESSING = YES
|
||||
|
||||
# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
|
||||
# names in the source code. If set to NO (the default) only conditional
|
||||
# compilation will be performed. Macro expansion can be done in a controlled
|
||||
# way by setting EXPAND_ONLY_PREDEF to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
|
||||
# then the macro expansion is limited to the macros specified with the
|
||||
# PREDEFINED and EXPAND_AS_PREDEFINED tags.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
|
||||
# in the INCLUDE_PATH (see below) will be search if a #include is found.
|
||||
|
||||
SEARCH_INCLUDES = YES
|
||||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by
|
||||
# the preprocessor.
|
||||
|
||||
INCLUDE_PATH = ../../generic/extern
|
||||
|
||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||
# directories. If left blank, the patterns specified with FILE_PATTERNS will
|
||||
# be used.
|
||||
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
|
||||
# The PREDEFINED tag can be used to specify one or more macro names that
|
||||
# are defined before the preprocessor is started (similar to the -D option of
|
||||
# gcc). The argument of the tag is a list of macros of the form: name
|
||||
# or name=definition (no spaces). If the definition and the = are
|
||||
# omitted =1 is assumed.
|
||||
|
||||
PREDEFINED =
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then
|
||||
# this tag can be used to specify a list of macro names that should be expanded.
|
||||
# The macro definition that is found in the sources will be used.
|
||||
# Use the PREDEFINED tag if you want to use a different macro definition.
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The TAGFILES tag can be used to specify one or more tagfiles.
|
||||
|
||||
TAGFILES =
|
||||
|
||||
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
|
||||
# a tag file that is based on the input files it reads.
|
||||
|
||||
GENERATE_TAGFILE =
|
||||
|
||||
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
|
||||
# in the class index. If set to NO only the inherited external classes
|
||||
# will be listed.
|
||||
|
||||
ALLEXTERNALS = NO
|
||||
|
||||
# The PERL_PATH should be the absolute path and name of the perl script
|
||||
# interpreter (i.e. the result of `which perl').
|
||||
|
||||
PERL_PATH = /usr/bin/perl
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz, a graph visualization
|
||||
# toolkit from AT&T and Lucent Bell Labs. The other options in this section
|
||||
# have no effect if this option is set to NO (the default)
|
||||
|
||||
HAVE_DOT = YES
|
||||
|
||||
# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect inheritance relations. Setting this tag to YES will force the
|
||||
# the CLASS_DIAGRAMS tag to NO.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
|
||||
# will generate a graph for each documented class showing the direct and
|
||||
# indirect implementation dependencies (inheritance, containment, and
|
||||
# class references variables) of the class with other documented classes.
|
||||
|
||||
COLLABORATION_GRAPH = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to
|
||||
# YES then doxygen will generate a graph for each documented file showing
|
||||
# the direct and indirect include dependencies of the file with other
|
||||
# documented files.
|
||||
|
||||
INCLUDE_GRAPH = YES
|
||||
|
||||
# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to
|
||||
# YES then doxygen will generate a graph for each documented header file showing
|
||||
# the documented files that directly or indirectly include this file
|
||||
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
|
||||
# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
|
||||
# will graphical hierarchy of all classes instead of a textual one.
|
||||
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
# The tag DOT_PATH can be used to specify the path where the dot tool can be
|
||||
# found. If left blank, it is assumed the dot tool can be found on the path.
|
||||
|
||||
DOT_PATH =
|
||||
|
||||
# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
|
||||
# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
|
||||
# (in pixels) of the graphs generated by dot. If a graph becomes larger than
|
||||
# this value, doxygen will try to truncate the graph, so that it fits within
|
||||
# the specified constraint. Beware that most browsers cannot cope with very
|
||||
# large images.
|
||||
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
|
||||
# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
|
||||
# generate a legend page explaining the meaning of the various boxes and
|
||||
# arrows in the dot generated graphs.
|
||||
|
||||
GENERATE_LEGEND = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# The SEARCHENGINE tag specifies whether or not a search engine should be
|
||||
# used. If set to NO the values of all tags below this one will be ignored.
|
||||
|
||||
SEARCHENGINE = NO
|
||||
|
||||
# The CGI_NAME tag should be the name of the CGI script that
|
||||
# starts the search engine (doxysearch) with the correct parameters.
|
||||
# A script with this name will be generated by doxygen.
|
||||
|
||||
CGI_NAME = search.cgi
|
||||
|
||||
# The CGI_URL tag should be the absolute URL to the directory where the
|
||||
# cgi binaries are located. See the documentation of your http daemon for
|
||||
# details.
|
||||
|
||||
CGI_URL =
|
||||
|
||||
# The DOC_URL tag should be the absolute URL to the directory where the
|
||||
# documentation is located. If left blank the absolute path to the
|
||||
# documentation, with file:// prepended to it, will be used.
|
||||
|
||||
DOC_URL =
|
||||
|
||||
# The DOC_ABSPATH tag should be the absolute path to the directory where the
|
||||
# documentation is located. If left blank the directory on the local machine
|
||||
# will be used.
|
||||
|
||||
DOC_ABSPATH =
|
||||
|
||||
# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
|
||||
# is installed.
|
||||
|
||||
BIN_ABSPATH = c:\program files\doxygen\bin
|
||||
|
||||
# The EXT_DOC_PATHS tag can be used to specify one or more paths to
|
||||
# documentation generated for other projects. This allows doxysearch to search
|
||||
# the documentation for these projects as well.
|
||||
|
||||
EXT_DOC_PATHS =
|
||||
|
|
@ -122,7 +122,7 @@ protected:
|
|||
checkManifold(body0Wrap,body1Wrap);
|
||||
|
||||
btCollisionAlgorithm * convex_algorithm = m_dispatcher->findAlgorithm(
|
||||
body0Wrap,body1Wrap,getLastManifold());
|
||||
body0Wrap,body1Wrap,getLastManifold(), BT_CONTACT_POINT_ALGORITHMS);
|
||||
return convex_algorithm ;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,59 @@ subject to the following restrictions:
|
|||
#include "btGImpactMassUtil.h"
|
||||
|
||||
|
||||
btGImpactMeshShapePart::btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part )
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
// (The setting of BT_THREADSAFE may differ between various cpp files, so it is best to
|
||||
// avoid using it in h files)
|
||||
m_primitive_manager.m_meshInterface = meshInterface;
|
||||
m_primitive_manager.m_part = part;
|
||||
m_box_set.setPrimitiveManager( &m_primitive_manager );
|
||||
#if BT_THREADSAFE
|
||||
// If threadsafe is requested, this object uses a different lock/unlock
|
||||
// model with the btStridingMeshInterface -- lock once when the object is constructed
|
||||
// and unlock once in the destructor.
|
||||
// The other way of locking and unlocking for each collision check in the narrowphase
|
||||
// is not threadsafe. Note these are not thread-locks, they are calls to the meshInterface's
|
||||
// getLockedReadOnlyVertexIndexBase virtual function, which by default just returns a couple of
|
||||
// pointers. In theory a client could override the lock function to do all sorts of
|
||||
// things like reading data from GPU memory, or decompressing data on the fly, but such things
|
||||
// do not seem all that likely or useful, given the performance cost.
|
||||
m_primitive_manager.lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
btGImpactMeshShapePart::~btGImpactMeshShapePart()
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
#if BT_THREADSAFE
|
||||
m_primitive_manager.unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void btGImpactMeshShapePart::lockChildShapes() const
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
#if ! BT_THREADSAFE
|
||||
// called in the narrowphase -- not threadsafe!
|
||||
void * dummy = (void*) ( m_box_set.getPrimitiveManager() );
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>( dummy );
|
||||
dummymanager->lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
void btGImpactMeshShapePart::unlockChildShapes() const
|
||||
{
|
||||
// moved from .h to .cpp because of conditional compilation
|
||||
#if ! BT_THREADSAFE
|
||||
// called in the narrowphase -- not threadsafe!
|
||||
void * dummy = (void*) ( m_box_set.getPrimitiveManager() );
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>( dummy );
|
||||
dummymanager->unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define CALC_EXACT_INERTIA 1
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -722,17 +722,8 @@ public:
|
|||
m_box_set.setPrimitiveManager(&m_primitive_manager);
|
||||
}
|
||||
|
||||
|
||||
btGImpactMeshShapePart(btStridingMeshInterface * meshInterface, int part)
|
||||
{
|
||||
m_primitive_manager.m_meshInterface = meshInterface;
|
||||
m_primitive_manager.m_part = part;
|
||||
m_box_set.setPrimitiveManager(&m_primitive_manager);
|
||||
}
|
||||
|
||||
virtual ~btGImpactMeshShapePart()
|
||||
{
|
||||
}
|
||||
btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part );
|
||||
virtual ~btGImpactMeshShapePart();
|
||||
|
||||
//! if true, then its children must get transforms.
|
||||
virtual bool childrenHasTransform() const
|
||||
|
|
@ -742,19 +733,8 @@ public:
|
|||
|
||||
|
||||
//! call when reading child shapes
|
||||
virtual void lockChildShapes() const
|
||||
{
|
||||
void * dummy = (void*)(m_box_set.getPrimitiveManager());
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>(dummy);
|
||||
dummymanager->lock();
|
||||
}
|
||||
|
||||
virtual void unlockChildShapes() const
|
||||
{
|
||||
void * dummy = (void*)(m_box_set.getPrimitiveManager());
|
||||
TrimeshPrimitiveManager * dummymanager = static_cast<TrimeshPrimitiveManager *>(dummy);
|
||||
dummymanager->unlock();
|
||||
}
|
||||
virtual void lockChildShapes() const;
|
||||
virtual void unlockChildShapes() const;
|
||||
|
||||
//! Gets the number of children
|
||||
virtual int getNumChildShapes() const
|
||||
|
|
|
|||
|
|
@ -404,12 +404,12 @@ SIMD_FORCE_INLINE void SEGMENT_COLLISION(
|
|||
CLASS_POINT & vPointA,
|
||||
CLASS_POINT & vPointB)
|
||||
{
|
||||
CLASS_POINT _AD,_BD,_N;
|
||||
CLASS_POINT _AD,_BD,n;
|
||||
vec4f _M;//plane
|
||||
VEC_DIFF(_AD,vA2,vA1);
|
||||
VEC_DIFF(_BD,vB2,vB1);
|
||||
VEC_CROSS(_N,_AD,_BD);
|
||||
GREAL _tp = VEC_DOT(_N,_N);
|
||||
VEC_CROSS(n,_AD,_BD);
|
||||
GREAL _tp = VEC_DOT(n,n);
|
||||
if(_tp<G_EPSILON)//ARE PARALELE
|
||||
{
|
||||
//project B over A
|
||||
|
|
@ -424,10 +424,10 @@ SIMD_FORCE_INLINE void SEGMENT_COLLISION(
|
|||
_M[2] = VEC_DOT(vA1,_AD);
|
||||
_M[3] = VEC_DOT(vA2,_AD);
|
||||
//mid points
|
||||
_N[0] = (_M[0]+_M[1])*0.5f;
|
||||
_N[1] = (_M[2]+_M[3])*0.5f;
|
||||
n[0] = (_M[0]+_M[1])*0.5f;
|
||||
n[1] = (_M[2]+_M[3])*0.5f;
|
||||
|
||||
if(_N[0]<_N[1])
|
||||
if(n[0]<n[1])
|
||||
{
|
||||
if(_M[1]<_M[2])
|
||||
{
|
||||
|
|
@ -467,7 +467,7 @@ SIMD_FORCE_INLINE void SEGMENT_COLLISION(
|
|||
}
|
||||
|
||||
|
||||
VEC_CROSS(_M,_N,_BD);
|
||||
VEC_CROSS(_M,n,_BD);
|
||||
_M[3] = VEC_DOT(_M,vB1);
|
||||
|
||||
LINE_PLANE_COLLISION(_M,_AD,vA1,vPointA,_tp,btScalar(0), btScalar(1));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2014 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.
|
||||
*/
|
||||
|
||||
#ifndef BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H
|
||||
#define BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H
|
||||
|
||||
#include "LinearMath/btTransform.h" // Note that btVector3 might be double precision...
|
||||
#include "btGjkEpa3.h"
|
||||
#include "btGjkCollisionDescription.h"
|
||||
#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename btConvexTemplate>
|
||||
bool btGjkEpaCalcPenDepth(const btConvexTemplate& a, const btConvexTemplate& b,
|
||||
const btGjkCollisionDescription& colDesc,
|
||||
btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB)
|
||||
{
|
||||
(void)v;
|
||||
|
||||
// const btScalar radialmargin(btScalar(0.));
|
||||
|
||||
btVector3 guessVector(b.getWorldTransform().getOrigin()-a.getWorldTransform().getOrigin());//?? why not use the GJK input?
|
||||
|
||||
btGjkEpaSolver3::sResults results;
|
||||
|
||||
|
||||
if(btGjkEpaSolver3_Penetration(a,b,guessVector,results))
|
||||
|
||||
{
|
||||
// debugDraw->drawLine(results.witnesses[1],results.witnesses[1]+results.normal,btVector3(255,0,0));
|
||||
//resultOut->addContactPoint(results.normal,results.witnesses[1],-results.depth);
|
||||
wWitnessOnA = results.witnesses[0];
|
||||
wWitnessOnB = results.witnesses[1];
|
||||
v = results.normal;
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
if(btGjkEpaSolver3_Distance(a,b,guessVector,results))
|
||||
{
|
||||
wWitnessOnA = results.witnesses[0];
|
||||
wWitnessOnB = results.witnesses[1];
|
||||
v = results.normal;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename btConvexTemplate, typename btGjkDistanceTemplate>
|
||||
int btComputeGjkEpaPenetration(const btConvexTemplate& a, const btConvexTemplate& b, const btGjkCollisionDescription& colDesc, btVoronoiSimplexSolver& simplexSolver, btGjkDistanceTemplate* distInfo)
|
||||
{
|
||||
|
||||
bool m_catchDegeneracies = true;
|
||||
btScalar m_cachedSeparatingDistance = 0.f;
|
||||
|
||||
btScalar distance=btScalar(0.);
|
||||
btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
|
||||
|
||||
btVector3 pointOnA,pointOnB;
|
||||
btTransform localTransA = a.getWorldTransform();
|
||||
btTransform localTransB = b.getWorldTransform();
|
||||
|
||||
btScalar marginA = a.getMargin();
|
||||
btScalar marginB = b.getMargin();
|
||||
|
||||
int m_curIter = 0;
|
||||
int gGjkMaxIter = colDesc.m_maxGjkIterations;//this is to catch invalid input, perhaps check for #NaN?
|
||||
btVector3 m_cachedSeparatingAxis = colDesc.m_firstDir;
|
||||
|
||||
bool isValid = false;
|
||||
bool checkSimplex = false;
|
||||
bool checkPenetration = true;
|
||||
int m_degenerateSimplex = 0;
|
||||
|
||||
int m_lastUsedMethod = -1;
|
||||
|
||||
{
|
||||
btScalar squaredDistance = BT_LARGE_FLOAT;
|
||||
btScalar delta = btScalar(0.);
|
||||
|
||||
btScalar margin = marginA + marginB;
|
||||
|
||||
|
||||
|
||||
simplexSolver.reset();
|
||||
|
||||
for ( ; ; )
|
||||
//while (true)
|
||||
{
|
||||
|
||||
btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* localTransA.getBasis();
|
||||
btVector3 seperatingAxisInB = m_cachedSeparatingAxis* localTransB.getBasis();
|
||||
|
||||
btVector3 pInA = a.getLocalSupportWithoutMargin(seperatingAxisInA);
|
||||
btVector3 qInB = b.getLocalSupportWithoutMargin(seperatingAxisInB);
|
||||
|
||||
btVector3 pWorld = localTransA(pInA);
|
||||
btVector3 qWorld = localTransB(qInB);
|
||||
|
||||
|
||||
|
||||
btVector3 w = pWorld - qWorld;
|
||||
delta = m_cachedSeparatingAxis.dot(w);
|
||||
|
||||
// potential exit, they don't overlap
|
||||
if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * colDesc.m_maximumDistanceSquared))
|
||||
{
|
||||
m_degenerateSimplex = 10;
|
||||
checkSimplex=true;
|
||||
//checkPenetration = false;
|
||||
break;
|
||||
}
|
||||
|
||||
//exit 0: the new point is already in the simplex, or we didn't come any closer
|
||||
if (simplexSolver.inSimplex(w))
|
||||
{
|
||||
m_degenerateSimplex = 1;
|
||||
checkSimplex = true;
|
||||
break;
|
||||
}
|
||||
// are we getting any closer ?
|
||||
btScalar f0 = squaredDistance - delta;
|
||||
btScalar f1 = squaredDistance * colDesc.m_gjkRelError2;
|
||||
|
||||
if (f0 <= f1)
|
||||
{
|
||||
if (f0 <= btScalar(0.))
|
||||
{
|
||||
m_degenerateSimplex = 2;
|
||||
} else
|
||||
{
|
||||
m_degenerateSimplex = 11;
|
||||
}
|
||||
checkSimplex = true;
|
||||
break;
|
||||
}
|
||||
|
||||
//add current vertex to simplex
|
||||
simplexSolver.addVertex(w, pWorld, qWorld);
|
||||
btVector3 newCachedSeparatingAxis;
|
||||
|
||||
//calculate the closest point to the origin (update vector v)
|
||||
if (!simplexSolver.closest(newCachedSeparatingAxis))
|
||||
{
|
||||
m_degenerateSimplex = 3;
|
||||
checkSimplex = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(newCachedSeparatingAxis.length2()<colDesc.m_gjkRelError2)
|
||||
{
|
||||
m_cachedSeparatingAxis = newCachedSeparatingAxis;
|
||||
m_degenerateSimplex = 6;
|
||||
checkSimplex = true;
|
||||
break;
|
||||
}
|
||||
|
||||
btScalar previousSquaredDistance = squaredDistance;
|
||||
squaredDistance = newCachedSeparatingAxis.length2();
|
||||
#if 0
|
||||
///warning: this termination condition leads to some problems in 2d test case see Bullet/Demos/Box2dDemo
|
||||
if (squaredDistance>previousSquaredDistance)
|
||||
{
|
||||
m_degenerateSimplex = 7;
|
||||
squaredDistance = previousSquaredDistance;
|
||||
checkSimplex = false;
|
||||
break;
|
||||
}
|
||||
#endif //
|
||||
|
||||
|
||||
//redundant m_simplexSolver->compute_points(pointOnA, pointOnB);
|
||||
|
||||
//are we getting any closer ?
|
||||
if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance)
|
||||
{
|
||||
// m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
|
||||
checkSimplex = true;
|
||||
m_degenerateSimplex = 12;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
m_cachedSeparatingAxis = newCachedSeparatingAxis;
|
||||
|
||||
//degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
|
||||
if (m_curIter++ > gGjkMaxIter)
|
||||
{
|
||||
#if defined(DEBUG) || defined (_DEBUG)
|
||||
|
||||
printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
|
||||
printf("sepAxis=(%f,%f,%f), squaredDistance = %f\n",
|
||||
m_cachedSeparatingAxis.getX(),
|
||||
m_cachedSeparatingAxis.getY(),
|
||||
m_cachedSeparatingAxis.getZ(),
|
||||
squaredDistance);
|
||||
#endif
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool check = (!simplexSolver.fullSimplex());
|
||||
//bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex());
|
||||
|
||||
if (!check)
|
||||
{
|
||||
//do we need this backup_closest here ?
|
||||
// m_simplexSolver->backup_closest(m_cachedSeparatingAxis);
|
||||
m_degenerateSimplex = 13;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkSimplex)
|
||||
{
|
||||
simplexSolver.compute_points(pointOnA, pointOnB);
|
||||
normalInB = m_cachedSeparatingAxis;
|
||||
|
||||
btScalar lenSqr =m_cachedSeparatingAxis.length2();
|
||||
|
||||
//valid normal
|
||||
if (lenSqr < 0.0001)
|
||||
{
|
||||
m_degenerateSimplex = 5;
|
||||
}
|
||||
if (lenSqr > SIMD_EPSILON*SIMD_EPSILON)
|
||||
{
|
||||
btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
|
||||
normalInB *= rlen; //normalize
|
||||
|
||||
btScalar s = btSqrt(squaredDistance);
|
||||
|
||||
btAssert(s > btScalar(0.0));
|
||||
pointOnA -= m_cachedSeparatingAxis * (marginA / s);
|
||||
pointOnB += m_cachedSeparatingAxis * (marginB / s);
|
||||
distance = ((btScalar(1.)/rlen) - margin);
|
||||
isValid = true;
|
||||
|
||||
m_lastUsedMethod = 1;
|
||||
} else
|
||||
{
|
||||
m_lastUsedMethod = 2;
|
||||
}
|
||||
}
|
||||
|
||||
bool catchDegeneratePenetrationCase =
|
||||
(m_catchDegeneracies && m_degenerateSimplex && ((distance+margin) < 0.01));
|
||||
|
||||
//if (checkPenetration && !isValid)
|
||||
if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
|
||||
{
|
||||
//penetration case
|
||||
|
||||
//if there is no way to handle penetrations, bail out
|
||||
|
||||
// Penetration depth case.
|
||||
btVector3 tmpPointOnA,tmpPointOnB;
|
||||
|
||||
m_cachedSeparatingAxis.setZero();
|
||||
|
||||
bool isValid2 = btGjkEpaCalcPenDepth(a,b,
|
||||
colDesc,
|
||||
m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB);
|
||||
|
||||
if (isValid2)
|
||||
{
|
||||
btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA;
|
||||
btScalar lenSqr = tmpNormalInB.length2();
|
||||
if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON))
|
||||
{
|
||||
tmpNormalInB = m_cachedSeparatingAxis;
|
||||
lenSqr = m_cachedSeparatingAxis.length2();
|
||||
}
|
||||
|
||||
if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON))
|
||||
{
|
||||
tmpNormalInB /= btSqrt(lenSqr);
|
||||
btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
|
||||
//only replace valid penetrations when the result is deeper (check)
|
||||
if (!isValid || (distance2 < distance))
|
||||
{
|
||||
distance = distance2;
|
||||
pointOnA = tmpPointOnA;
|
||||
pointOnB = tmpPointOnB;
|
||||
normalInB = tmpNormalInB;
|
||||
|
||||
isValid = true;
|
||||
m_lastUsedMethod = 3;
|
||||
} else
|
||||
{
|
||||
m_lastUsedMethod = 8;
|
||||
}
|
||||
} else
|
||||
{
|
||||
m_lastUsedMethod = 9;
|
||||
}
|
||||
} else
|
||||
|
||||
{
|
||||
///this is another degenerate case, where the initial GJK calculation reports a degenerate case
|
||||
///EPA reports no penetration, and the second GJK (using the supporting vector without margin)
|
||||
///reports a valid positive distance. Use the results of the second GJK instead of failing.
|
||||
///thanks to Jacob.Langford for the reproduction case
|
||||
///http://code.google.com/p/bullet/issues/detail?id=250
|
||||
|
||||
|
||||
if (m_cachedSeparatingAxis.length2() > btScalar(0.))
|
||||
{
|
||||
btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin;
|
||||
//only replace valid distances when the distance is less
|
||||
if (!isValid || (distance2 < distance))
|
||||
{
|
||||
distance = distance2;
|
||||
pointOnA = tmpPointOnA;
|
||||
pointOnB = tmpPointOnB;
|
||||
pointOnA -= m_cachedSeparatingAxis * marginA ;
|
||||
pointOnB += m_cachedSeparatingAxis * marginB ;
|
||||
normalInB = m_cachedSeparatingAxis;
|
||||
normalInB.normalize();
|
||||
|
||||
isValid = true;
|
||||
m_lastUsedMethod = 6;
|
||||
} else
|
||||
{
|
||||
m_lastUsedMethod = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (isValid && ((distance < 0) || (distance*distance < colDesc.m_maximumDistanceSquared)))
|
||||
{
|
||||
|
||||
m_cachedSeparatingAxis = normalInB;
|
||||
m_cachedSeparatingDistance = distance;
|
||||
distInfo->m_distance = distance;
|
||||
distInfo->m_normalBtoA = normalInB;
|
||||
distInfo->m_pointOnB = pointOnB;
|
||||
distInfo->m_pointOnA = pointOnB+normalInB*distance;
|
||||
return 0;
|
||||
}
|
||||
return -m_lastUsedMethod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2010 Erwin Coumans http://bulletphysics.org
|
||||
Copyright (c) 2003-2014 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.
|
||||
|
|
@ -14,24 +14,28 @@ subject to the following restrictions:
|
|||
*/
|
||||
|
||||
|
||||
#ifndef BT_PPU_ADDRESS_SPACE_H
|
||||
#define BT_PPU_ADDRESS_SPACE_H
|
||||
#ifndef GJK_COLLISION_DESCRIPTION_H
|
||||
#define GJK_COLLISION_DESCRIPTION_H
|
||||
|
||||
#include "LinearMath/btVector3.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
//stop those casting warnings until we have a better solution for ppu_address_t / void* / uint64 conversions
|
||||
#pragma warning (disable: 4311)
|
||||
#pragma warning (disable: 4312)
|
||||
#endif //_WIN32
|
||||
struct btGjkCollisionDescription
|
||||
{
|
||||
btVector3 m_firstDir;
|
||||
int m_maxGjkIterations;
|
||||
btScalar m_maximumDistanceSquared;
|
||||
btScalar m_gjkRelError2;
|
||||
btGjkCollisionDescription()
|
||||
:m_firstDir(0,1,0),
|
||||
m_maxGjkIterations(1000),
|
||||
m_maximumDistanceSquared(1e30f),
|
||||
m_gjkRelError2(1.0e-6)
|
||||
{
|
||||
}
|
||||
virtual ~btGjkCollisionDescription()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#if defined(_WIN64)
|
||||
typedef unsigned __int64 ppu_address_t;
|
||||
#elif defined(__LP64__) || defined(__x86_64__)
|
||||
typedef uint64_t ppu_address_t;
|
||||
#else
|
||||
typedef uint32_t ppu_address_t;
|
||||
#endif //defined(_WIN64)
|
||||
|
||||
#endif //BT_PPU_ADDRESS_SPACE_H
|
||||
#endif //GJK_COLLISION_DESCRIPTION_H
|
||||
|
||||
|
|
@ -41,21 +41,38 @@ namespace gjkepa2_impl
|
|||
|
||||
/* GJK */
|
||||
#define GJK_MAX_ITERATIONS 128
|
||||
#define GJK_ACCURARY ((btScalar)0.0001)
|
||||
#define GJK_MIN_DISTANCE ((btScalar)0.0001)
|
||||
#define GJK_DUPLICATED_EPS ((btScalar)0.0001)
|
||||
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
#define GJK_ACCURACY ((btScalar)1e-12)
|
||||
#define GJK_MIN_DISTANCE ((btScalar)1e-12)
|
||||
#define GJK_DUPLICATED_EPS ((btScalar)1e-12)
|
||||
#else
|
||||
#define GJK_ACCURACY ((btScalar)0.0001)
|
||||
#define GJK_MIN_DISTANCE ((btScalar)0.0001)
|
||||
#define GJK_DUPLICATED_EPS ((btScalar)0.0001)
|
||||
#endif //BT_USE_DOUBLE_PRECISION
|
||||
|
||||
|
||||
#define GJK_SIMPLEX2_EPS ((btScalar)0.0)
|
||||
#define GJK_SIMPLEX3_EPS ((btScalar)0.0)
|
||||
#define GJK_SIMPLEX4_EPS ((btScalar)0.0)
|
||||
|
||||
/* EPA */
|
||||
#define EPA_MAX_VERTICES 64
|
||||
#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
|
||||
#define EPA_MAX_VERTICES 128
|
||||
#define EPA_MAX_ITERATIONS 255
|
||||
#define EPA_ACCURACY ((btScalar)0.0001)
|
||||
#define EPA_FALLBACK (10*EPA_ACCURACY)
|
||||
#define EPA_PLANE_EPS ((btScalar)0.00001)
|
||||
#define EPA_INSIDE_EPS ((btScalar)0.01)
|
||||
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
#define EPA_ACCURACY ((btScalar)1e-12)
|
||||
#define EPA_PLANE_EPS ((btScalar)1e-14)
|
||||
#define EPA_INSIDE_EPS ((btScalar)1e-9)
|
||||
#else
|
||||
#define EPA_ACCURACY ((btScalar)0.0001)
|
||||
#define EPA_PLANE_EPS ((btScalar)0.00001)
|
||||
#define EPA_INSIDE_EPS ((btScalar)0.01)
|
||||
#endif
|
||||
|
||||
#define EPA_FALLBACK (10*EPA_ACCURACY)
|
||||
#define EPA_MAX_FACES (EPA_MAX_VERTICES*2)
|
||||
|
||||
|
||||
// Shorthands
|
||||
|
|
@ -242,7 +259,7 @@ namespace gjkepa2_impl
|
|||
/* Check for termination */
|
||||
const btScalar omega=btDot(m_ray,w)/rl;
|
||||
alpha=btMax(omega,alpha);
|
||||
if(((rl-alpha)-(GJK_ACCURARY*rl))<=0)
|
||||
if(((rl-alpha)-(GJK_ACCURACY*rl))<=0)
|
||||
{/* Return old simplex */
|
||||
removevertice(m_simplices[m_current]);
|
||||
break;
|
||||
|
|
@ -1015,7 +1032,7 @@ bool btGjkEpaSolver2::SignedDistance(const btConvexShape* shape0,
|
|||
/* Symbols cleanup */
|
||||
|
||||
#undef GJK_MAX_ITERATIONS
|
||||
#undef GJK_ACCURARY
|
||||
#undef GJK_ACCURACY
|
||||
#undef GJK_MIN_DISTANCE
|
||||
#undef GJK_DUPLICATED_EPS
|
||||
#undef GJK_SIMPLEX2_EPS
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -26,12 +26,17 @@ subject to the following restrictions:
|
|||
#ifdef __SPU__
|
||||
#include <spu_printf.h>
|
||||
#define printf spu_printf
|
||||
//#define DEBUG_SPU_COLLISION_DETECTION 1
|
||||
#endif //__SPU__
|
||||
#endif
|
||||
|
||||
//must be above the machine epsilon
|
||||
#define REL_ERROR2 btScalar(1.0e-6)
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
#define REL_ERROR2 btScalar(1.0e-12)
|
||||
btScalar gGjkEpaPenetrationTolerance = 1e-7;
|
||||
#else
|
||||
#define REL_ERROR2 btScalar(1.0e-6)
|
||||
btScalar gGjkEpaPenetrationTolerance = 0.001;
|
||||
#endif
|
||||
|
||||
//temp globals, to improve GJK/EPA/penetration calculations
|
||||
int gNumDeepPenetrationChecks = 0;
|
||||
|
|
@ -81,17 +86,18 @@ void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result&
|
|||
#ifdef __SPU__
|
||||
void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
|
||||
#else
|
||||
void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw)
|
||||
void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input, Result& output, class btIDebugDraw* debugDraw)
|
||||
#endif
|
||||
{
|
||||
m_cachedSeparatingDistance = 0.f;
|
||||
|
||||
btScalar distance=btScalar(0.);
|
||||
btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.));
|
||||
|
||||
btVector3 pointOnA,pointOnB;
|
||||
btTransform localTransA = input.m_transformA;
|
||||
btTransform localTransB = input.m_transformB;
|
||||
btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
|
||||
btVector3 positionOffset=(localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5);
|
||||
localTransA.getOrigin() -= positionOffset;
|
||||
localTransB.getOrigin() -= positionOffset;
|
||||
|
||||
|
|
@ -102,17 +108,11 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
|
||||
gNumGjkChecks++;
|
||||
|
||||
#ifdef DEBUG_SPU_COLLISION_DETECTION
|
||||
spu_printf("inside gjk\n");
|
||||
#endif
|
||||
//for CCD we don't use margins
|
||||
if (m_ignoreMargin)
|
||||
{
|
||||
marginA = btScalar(0.);
|
||||
marginB = btScalar(0.);
|
||||
#ifdef DEBUG_SPU_COLLISION_DETECTION
|
||||
spu_printf("ignoring margin\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
m_curIter = 0;
|
||||
|
|
@ -143,37 +143,13 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis();
|
||||
btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis();
|
||||
|
||||
#if 1
|
||||
|
||||
btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
|
||||
btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
|
||||
|
||||
// btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA);
|
||||
// btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB);
|
||||
|
||||
#else
|
||||
#ifdef __SPU__
|
||||
btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
|
||||
btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
|
||||
#else
|
||||
btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
|
||||
btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
|
||||
#ifdef TEST_NON_VIRTUAL
|
||||
btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA);
|
||||
btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB);
|
||||
btAssert((pInAv-pInA).length() < 0.0001);
|
||||
btAssert((qInBv-qInB).length() < 0.0001);
|
||||
#endif //
|
||||
#endif //__SPU__
|
||||
#endif
|
||||
|
||||
|
||||
btVector3 pWorld = localTransA(pInA);
|
||||
btVector3 qWorld = localTransB(qInB);
|
||||
|
||||
#ifdef DEBUG_SPU_COLLISION_DETECTION
|
||||
spu_printf("got local supporting vertices\n");
|
||||
#endif
|
||||
|
||||
if (check2d)
|
||||
{
|
||||
|
|
@ -217,14 +193,8 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SPU_COLLISION_DETECTION
|
||||
spu_printf("addVertex 1\n");
|
||||
#endif
|
||||
//add current vertex to simplex
|
||||
m_simplexSolver->addVertex(w, pWorld, qWorld);
|
||||
#ifdef DEBUG_SPU_COLLISION_DETECTION
|
||||
spu_printf("addVertex 2\n");
|
||||
#endif
|
||||
btVector3 newCachedSeparatingAxis;
|
||||
|
||||
//calculate the closest point to the origin (update vector v)
|
||||
|
|
@ -274,7 +244,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
//degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject
|
||||
if (m_curIter++ > gGjkMaxIter)
|
||||
{
|
||||
#if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION)
|
||||
#if defined(DEBUG) || defined (_DEBUG)
|
||||
|
||||
printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter);
|
||||
printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n",
|
||||
|
|
@ -307,10 +277,11 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
{
|
||||
m_simplexSolver->compute_points(pointOnA, pointOnB);
|
||||
normalInB = m_cachedSeparatingAxis;
|
||||
|
||||
btScalar lenSqr =m_cachedSeparatingAxis.length2();
|
||||
|
||||
//valid normal
|
||||
if (lenSqr < 0.0001)
|
||||
if (lenSqr < REL_ERROR2)
|
||||
{
|
||||
m_degenerateSimplex = 5;
|
||||
}
|
||||
|
|
@ -318,6 +289,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
{
|
||||
btScalar rlen = btScalar(1.) / btSqrt(lenSqr );
|
||||
normalInB *= rlen; //normalize
|
||||
|
||||
btScalar s = btSqrt(squaredDistance);
|
||||
|
||||
btAssert(s > btScalar(0.0));
|
||||
|
|
@ -334,7 +306,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
}
|
||||
|
||||
bool catchDegeneratePenetrationCase =
|
||||
(m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01));
|
||||
(m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < gGjkEpaPenetrationTolerance));
|
||||
|
||||
//if (checkPenetration && !isValid)
|
||||
if (checkPenetration && (!isValid || catchDegeneratePenetrationCase ))
|
||||
|
|
@ -373,6 +345,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
{
|
||||
tmpNormalInB /= btSqrt(lenSqr);
|
||||
btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length();
|
||||
m_lastUsedMethod = 3;
|
||||
//only replace valid penetrations when the result is deeper (check)
|
||||
if (!isValid || (distance2 < distance))
|
||||
{
|
||||
|
|
@ -380,8 +353,9 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
pointOnA = tmpPointOnA;
|
||||
pointOnB = tmpPointOnB;
|
||||
normalInB = tmpNormalInB;
|
||||
|
||||
isValid = true;
|
||||
m_lastUsedMethod = 3;
|
||||
|
||||
} else
|
||||
{
|
||||
m_lastUsedMethod = 8;
|
||||
|
|
@ -413,6 +387,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
pointOnB += m_cachedSeparatingAxis * marginB ;
|
||||
normalInB = m_cachedSeparatingAxis;
|
||||
normalInB.normalize();
|
||||
|
||||
isValid = true;
|
||||
m_lastUsedMethod = 6;
|
||||
} else
|
||||
|
|
@ -431,39 +406,51 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu
|
|||
|
||||
if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared)))
|
||||
{
|
||||
#if 0
|
||||
///some debugging
|
||||
// if (check2d)
|
||||
{
|
||||
printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]);
|
||||
printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_fixContactNormalDirection)
|
||||
{
|
||||
///@workaround for sticky convex collisions
|
||||
//in some degenerate cases (usually when the use uses very small margins)
|
||||
//the contact normal is pointing the wrong direction
|
||||
//so fix it now (until we can deal with all degenerate cases in GJK and EPA)
|
||||
//contact normals need to point from B to A in all cases, so we can simply check if the contact normal really points from B to A
|
||||
//We like to use a dot product of the normal against the difference of the centroids,
|
||||
//once the centroid is available in the API
|
||||
//until then we use the center of the aabb to approximate the centroid
|
||||
btVector3 aabbMin,aabbMax;
|
||||
m_minkowskiA->getAabb(localTransA,aabbMin,aabbMax);
|
||||
btVector3 posA = (aabbMax+aabbMin)*btScalar(0.5);
|
||||
|
||||
m_minkowskiB->getAabb(localTransB,aabbMin,aabbMax);
|
||||
btVector3 posB = (aabbMin+aabbMax)*btScalar(0.5);
|
||||
|
||||
btVector3 diff = posA-posB;
|
||||
if (diff.dot(normalInB) < 0.f)
|
||||
normalInB *= -1.f;
|
||||
}
|
||||
m_cachedSeparatingAxis = normalInB;
|
||||
m_cachedSeparatingDistance = distance;
|
||||
|
||||
{
|
||||
///todo: need to track down this EPA penetration solver degeneracy
|
||||
///the penetration solver reports penetration but the contact normal
|
||||
///connecting the contact points is pointing in the opposite direction
|
||||
///until then, detect the issue and revert the normal
|
||||
|
||||
btScalar d1=0;
|
||||
{
|
||||
btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis();
|
||||
btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis();
|
||||
|
||||
|
||||
btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
|
||||
btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
|
||||
|
||||
btVector3 pWorld = localTransA(pInA);
|
||||
btVector3 qWorld = localTransB(qInB);
|
||||
btVector3 w = pWorld - qWorld;
|
||||
d1 = (-normalInB).dot(w);
|
||||
}
|
||||
btScalar d0 = 0.f;
|
||||
{
|
||||
btVector3 seperatingAxisInA = (-normalInB)* input.m_transformA.getBasis();
|
||||
btVector3 seperatingAxisInB = normalInB* input.m_transformB.getBasis();
|
||||
|
||||
|
||||
btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA);
|
||||
btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);
|
||||
|
||||
btVector3 pWorld = localTransA(pInA);
|
||||
btVector3 qWorld = localTransB(qInB);
|
||||
btVector3 w = pWorld - qWorld;
|
||||
d0 = normalInB.dot(w);
|
||||
}
|
||||
if (d1>d0)
|
||||
{
|
||||
m_lastUsedMethod = 10;
|
||||
normalInB*=-1;
|
||||
}
|
||||
|
||||
}
|
||||
output.addContactPoint(
|
||||
normalInB,
|
||||
pointOnB+positionOffset,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,13 @@ typedef sce::PhysicsEffects::PfxConstraintRow btConstraintRow;
|
|||
typedef btConstraintRow PfxConstraintRow;
|
||||
#endif //PFX_USE_FREE_VECTORMATH
|
||||
|
||||
|
||||
enum btContactPointFlags
|
||||
{
|
||||
BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED=1,
|
||||
BT_CONTACT_FLAG_HAS_CONTACT_CFM=2,
|
||||
BT_CONTACT_FLAG_HAS_CONTACT_ERP=4,
|
||||
BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING = 8,
|
||||
};
|
||||
|
||||
/// ManifoldContactPoint collects and maintains persistent contactpoints.
|
||||
/// used to improve stability and performance of rigidbody dynamics response.
|
||||
|
|
@ -44,14 +50,15 @@ class btManifoldPoint
|
|||
public:
|
||||
btManifoldPoint()
|
||||
:m_userPersistentData(0),
|
||||
m_lateralFrictionInitialized(false),
|
||||
m_appliedImpulse(0.f),
|
||||
m_contactPointFlags(0),
|
||||
m_appliedImpulse(0.f),
|
||||
m_appliedImpulseLateral1(0.f),
|
||||
m_appliedImpulseLateral2(0.f),
|
||||
m_contactMotion1(0.f),
|
||||
m_contactMotion2(0.f),
|
||||
m_contactCFM1(0.f),
|
||||
m_contactCFM2(0.f),
|
||||
m_contactCFM(0.f),
|
||||
m_contactERP(0.f),
|
||||
m_frictionCFM(0.f),
|
||||
m_lifeTime(0)
|
||||
{
|
||||
}
|
||||
|
|
@ -65,16 +72,18 @@ class btManifoldPoint
|
|||
m_distance1( distance ),
|
||||
m_combinedFriction(btScalar(0.)),
|
||||
m_combinedRollingFriction(btScalar(0.)),
|
||||
m_combinedRestitution(btScalar(0.)),
|
||||
m_combinedSpinningFriction(btScalar(0.)),
|
||||
m_combinedRestitution(btScalar(0.)),
|
||||
m_userPersistentData(0),
|
||||
m_lateralFrictionInitialized(false),
|
||||
m_appliedImpulse(0.f),
|
||||
m_contactPointFlags(0),
|
||||
m_appliedImpulse(0.f),
|
||||
m_appliedImpulseLateral1(0.f),
|
||||
m_appliedImpulseLateral2(0.f),
|
||||
m_contactMotion1(0.f),
|
||||
m_contactMotion2(0.f),
|
||||
m_contactCFM1(0.f),
|
||||
m_contactCFM2(0.f),
|
||||
m_contactCFM(0.f),
|
||||
m_contactERP(0.f),
|
||||
m_frictionCFM(0.f),
|
||||
m_lifeTime(0)
|
||||
{
|
||||
|
||||
|
|
@ -91,8 +100,9 @@ class btManifoldPoint
|
|||
|
||||
btScalar m_distance1;
|
||||
btScalar m_combinedFriction;
|
||||
btScalar m_combinedRollingFriction;
|
||||
btScalar m_combinedRestitution;
|
||||
btScalar m_combinedRollingFriction;//torsional friction orthogonal to contact normal, useful to make spheres stop rolling forever
|
||||
btScalar m_combinedSpinningFriction;//torsional friction around contact normal, useful for grasping objects
|
||||
btScalar m_combinedRestitution;
|
||||
|
||||
//BP mod, store contact triangles.
|
||||
int m_partId0;
|
||||
|
|
@ -101,15 +111,28 @@ class btManifoldPoint
|
|||
int m_index1;
|
||||
|
||||
mutable void* m_userPersistentData;
|
||||
bool m_lateralFrictionInitialized;
|
||||
|
||||
//bool m_lateralFrictionInitialized;
|
||||
int m_contactPointFlags;
|
||||
|
||||
btScalar m_appliedImpulse;
|
||||
btScalar m_appliedImpulseLateral1;
|
||||
btScalar m_appliedImpulseLateral2;
|
||||
btScalar m_contactMotion1;
|
||||
btScalar m_contactMotion2;
|
||||
btScalar m_contactCFM1;
|
||||
btScalar m_contactCFM2;
|
||||
|
||||
union
|
||||
{
|
||||
btScalar m_contactCFM;
|
||||
btScalar m_combinedContactStiffness1;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
btScalar m_contactERP;
|
||||
btScalar m_combinedContactDamping1;
|
||||
};
|
||||
|
||||
btScalar m_frictionCFM;
|
||||
|
||||
int m_lifeTime;//lifetime of the contactpoint in frames
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,908 @@
|
|||
|
||||
/***
|
||||
* ---------------------------------
|
||||
* Copyright (c)2012 Daniel Fiser <danfis@danfis.cz>
|
||||
*
|
||||
* This file was ported from mpr.c file, part of libccd.
|
||||
* The Minkoski Portal Refinement implementation was ported
|
||||
* to OpenCL by Erwin Coumans for the Bullet 3 Physics library.
|
||||
* The original MPR idea and implementation is by Gary Snethen
|
||||
* in XenoCollide, see http://github.com/erwincoumans/xenocollide
|
||||
*
|
||||
* Distributed under the OSI-approved BSD License (the "License");
|
||||
* see <http://www.opensource.org/licenses/bsd-license.php>.
|
||||
* This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the License for more information.
|
||||
*/
|
||||
|
||||
///2014 Oct, Erwin Coumans, Use templates to avoid void* casts
|
||||
|
||||
#ifndef BT_MPR_PENETRATION_H
|
||||
#define BT_MPR_PENETRATION_H
|
||||
|
||||
#define BT_DEBUG_MPR1
|
||||
|
||||
#include "LinearMath/btTransform.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
|
||||
//#define MPR_AVERAGE_CONTACT_POSITIONS
|
||||
|
||||
|
||||
struct btMprCollisionDescription
|
||||
{
|
||||
btVector3 m_firstDir;
|
||||
int m_maxGjkIterations;
|
||||
btScalar m_maximumDistanceSquared;
|
||||
btScalar m_gjkRelError2;
|
||||
|
||||
btMprCollisionDescription()
|
||||
: m_firstDir(0,1,0),
|
||||
m_maxGjkIterations(1000),
|
||||
m_maximumDistanceSquared(1e30f),
|
||||
m_gjkRelError2(1.0e-6)
|
||||
{
|
||||
}
|
||||
virtual ~btMprCollisionDescription()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct btMprDistanceInfo
|
||||
{
|
||||
btVector3 m_pointOnA;
|
||||
btVector3 m_pointOnB;
|
||||
btVector3 m_normalBtoA;
|
||||
btScalar m_distance;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define BT_MPR_SQRT sqrtf
|
||||
#else
|
||||
#define BT_MPR_SQRT sqrt
|
||||
#endif
|
||||
#define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define BT_MPR_FABS fabs
|
||||
|
||||
#define BT_MPR_TOLERANCE 1E-6f
|
||||
#define BT_MPR_MAX_ITERATIONS 1000
|
||||
|
||||
struct _btMprSupport_t
|
||||
{
|
||||
btVector3 v; //!< Support point in minkowski sum
|
||||
btVector3 v1; //!< Support point in obj1
|
||||
btVector3 v2; //!< Support point in obj2
|
||||
};
|
||||
typedef struct _btMprSupport_t btMprSupport_t;
|
||||
|
||||
struct _btMprSimplex_t
|
||||
{
|
||||
btMprSupport_t ps[4];
|
||||
int last; //!< index of last added point
|
||||
};
|
||||
typedef struct _btMprSimplex_t btMprSimplex_t;
|
||||
|
||||
inline btMprSupport_t* btMprSimplexPointW(btMprSimplex_t *s, int idx)
|
||||
{
|
||||
return &s->ps[idx];
|
||||
}
|
||||
|
||||
inline void btMprSimplexSetSize(btMprSimplex_t *s, int size)
|
||||
{
|
||||
s->last = size - 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MPR
|
||||
inline void btPrintPortalVertex(_btMprSimplex_t* portal, int index)
|
||||
{
|
||||
printf("portal[%d].v = %f,%f,%f, v1=%f,%f,%f, v2=%f,%f,%f\n", index, portal->ps[index].v.x(),portal->ps[index].v.y(),portal->ps[index].v.z(),
|
||||
portal->ps[index].v1.x(),portal->ps[index].v1.y(),portal->ps[index].v1.z(),
|
||||
portal->ps[index].v2.x(),portal->ps[index].v2.y(),portal->ps[index].v2.z());
|
||||
}
|
||||
#endif //DEBUG_MPR
|
||||
|
||||
|
||||
|
||||
|
||||
inline int btMprSimplexSize(const btMprSimplex_t *s)
|
||||
{
|
||||
return s->last + 1;
|
||||
}
|
||||
|
||||
|
||||
inline const btMprSupport_t* btMprSimplexPoint(const btMprSimplex_t* s, int idx)
|
||||
{
|
||||
// here is no check on boundaries
|
||||
return &s->ps[idx];
|
||||
}
|
||||
|
||||
inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s)
|
||||
{
|
||||
*d = *s;
|
||||
}
|
||||
|
||||
inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a)
|
||||
{
|
||||
btMprSupportCopy(s->ps + pos, a);
|
||||
}
|
||||
|
||||
|
||||
inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2)
|
||||
{
|
||||
btMprSupport_t supp;
|
||||
|
||||
btMprSupportCopy(&supp, &s->ps[pos1]);
|
||||
btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]);
|
||||
btMprSupportCopy(&s->ps[pos2], &supp);
|
||||
}
|
||||
|
||||
|
||||
inline int btMprIsZero(float val)
|
||||
{
|
||||
return BT_MPR_FABS(val) < FLT_EPSILON;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline int btMprEq(float _a, float _b)
|
||||
{
|
||||
float ab;
|
||||
float a, b;
|
||||
|
||||
ab = BT_MPR_FABS(_a - _b);
|
||||
if (BT_MPR_FABS(ab) < FLT_EPSILON)
|
||||
return 1;
|
||||
|
||||
a = BT_MPR_FABS(_a);
|
||||
b = BT_MPR_FABS(_b);
|
||||
if (b > a){
|
||||
return ab < FLT_EPSILON * b;
|
||||
}else{
|
||||
return ab < FLT_EPSILON * a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline int btMprVec3Eq(const btVector3* a, const btVector3 *b)
|
||||
{
|
||||
return btMprEq((*a).x(), (*b).x())
|
||||
&& btMprEq((*a).y(), (*b).y())
|
||||
&& btMprEq((*a).z(), (*b).z());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename btConvexTemplate>
|
||||
inline void btFindOrigin(const btConvexTemplate& a, const btConvexTemplate& b, const btMprCollisionDescription& colDesc,btMprSupport_t *center)
|
||||
{
|
||||
|
||||
center->v1 = a.getObjectCenterInWorld();
|
||||
center->v2 = b.getObjectCenterInWorld();
|
||||
center->v = center->v1 - center->v2;
|
||||
}
|
||||
|
||||
inline void btMprVec3Set(btVector3 *v, float x, float y, float z)
|
||||
{
|
||||
v->setValue(x,y,z);
|
||||
}
|
||||
|
||||
inline void btMprVec3Add(btVector3 *v, const btVector3 *w)
|
||||
{
|
||||
*v += *w;
|
||||
}
|
||||
|
||||
inline void btMprVec3Copy(btVector3 *v, const btVector3 *w)
|
||||
{
|
||||
*v = *w;
|
||||
}
|
||||
|
||||
inline void btMprVec3Scale(btVector3 *d, float k)
|
||||
{
|
||||
*d *= k;
|
||||
}
|
||||
|
||||
inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b)
|
||||
{
|
||||
float dot;
|
||||
|
||||
dot = btDot(*a,*b);
|
||||
return dot;
|
||||
}
|
||||
|
||||
|
||||
inline float btMprVec3Len2(const btVector3 *v)
|
||||
{
|
||||
return btMprVec3Dot(v, v);
|
||||
}
|
||||
|
||||
inline void btMprVec3Normalize(btVector3 *d)
|
||||
{
|
||||
float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d));
|
||||
btMprVec3Scale(d, k);
|
||||
}
|
||||
|
||||
inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b)
|
||||
{
|
||||
*d = btCross(*a,*b);
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w)
|
||||
{
|
||||
*d = *v - *w;
|
||||
}
|
||||
|
||||
inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir)
|
||||
{
|
||||
btVector3 v2v1, v3v1;
|
||||
|
||||
btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v,
|
||||
&btMprSimplexPoint(portal, 1)->v);
|
||||
btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v,
|
||||
&btMprSimplexPoint(portal, 1)->v);
|
||||
btMprVec3Cross(dir, &v2v1, &v3v1);
|
||||
btMprVec3Normalize(dir);
|
||||
}
|
||||
|
||||
|
||||
inline int portalEncapsulesOrigin(const btMprSimplex_t *portal,
|
||||
const btVector3 *dir)
|
||||
{
|
||||
float dot;
|
||||
dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v);
|
||||
return btMprIsZero(dot) || dot > 0.f;
|
||||
}
|
||||
|
||||
inline int portalReachTolerance(const btMprSimplex_t *portal,
|
||||
const btMprSupport_t *v4,
|
||||
const btVector3 *dir)
|
||||
{
|
||||
float dv1, dv2, dv3, dv4;
|
||||
float dot1, dot2, dot3;
|
||||
|
||||
// find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}
|
||||
|
||||
dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir);
|
||||
dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir);
|
||||
dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir);
|
||||
dv4 = btMprVec3Dot(&v4->v, dir);
|
||||
|
||||
dot1 = dv4 - dv1;
|
||||
dot2 = dv4 - dv2;
|
||||
dot3 = dv4 - dv3;
|
||||
|
||||
dot1 = BT_MPR_FMIN(dot1, dot2);
|
||||
dot1 = BT_MPR_FMIN(dot1, dot3);
|
||||
|
||||
return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE;
|
||||
}
|
||||
|
||||
inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal,
|
||||
const btMprSupport_t *v4,
|
||||
const btVector3 *dir)
|
||||
{
|
||||
float dot;
|
||||
dot = btMprVec3Dot(&v4->v, dir);
|
||||
return btMprIsZero(dot) || dot > 0.f;
|
||||
}
|
||||
|
||||
inline void btExpandPortal(btMprSimplex_t *portal,
|
||||
const btMprSupport_t *v4)
|
||||
{
|
||||
float dot;
|
||||
btVector3 v4v0;
|
||||
|
||||
btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v);
|
||||
dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0);
|
||||
if (dot > 0.f){
|
||||
dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0);
|
||||
if (dot > 0.f){
|
||||
btMprSimplexSet(portal, 1, v4);
|
||||
}else{
|
||||
btMprSimplexSet(portal, 3, v4);
|
||||
}
|
||||
}else{
|
||||
dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0);
|
||||
if (dot > 0.f){
|
||||
btMprSimplexSet(portal, 2, v4);
|
||||
}else{
|
||||
btMprSimplexSet(portal, 1, v4);
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename btConvexTemplate>
|
||||
inline void btMprSupport(const btConvexTemplate& a, const btConvexTemplate& b,
|
||||
const btMprCollisionDescription& colDesc,
|
||||
const btVector3& dir, btMprSupport_t *supp)
|
||||
{
|
||||
btVector3 seperatingAxisInA = dir* a.getWorldTransform().getBasis();
|
||||
btVector3 seperatingAxisInB = -dir* b.getWorldTransform().getBasis();
|
||||
|
||||
btVector3 pInA = a.getLocalSupportWithMargin(seperatingAxisInA);
|
||||
btVector3 qInB = b.getLocalSupportWithMargin(seperatingAxisInB);
|
||||
|
||||
supp->v1 = a.getWorldTransform()(pInA);
|
||||
supp->v2 = b.getWorldTransform()(qInB);
|
||||
supp->v = supp->v1 - supp->v2;
|
||||
}
|
||||
|
||||
|
||||
template <typename btConvexTemplate>
|
||||
static int btDiscoverPortal(const btConvexTemplate& a, const btConvexTemplate& b,
|
||||
const btMprCollisionDescription& colDesc,
|
||||
btMprSimplex_t *portal)
|
||||
{
|
||||
btVector3 dir, va, vb;
|
||||
float dot;
|
||||
int cont;
|
||||
|
||||
|
||||
|
||||
// vertex 0 is center of portal
|
||||
btFindOrigin(a,b,colDesc, btMprSimplexPointW(portal, 0));
|
||||
|
||||
|
||||
// vertex 0 is center of portal
|
||||
btMprSimplexSetSize(portal, 1);
|
||||
|
||||
|
||||
|
||||
btVector3 zero = btVector3(0,0,0);
|
||||
btVector3* org = &zero;
|
||||
|
||||
if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org)){
|
||||
// Portal's center lies on origin (0,0,0) => we know that objects
|
||||
// intersect but we would need to know penetration info.
|
||||
// So move center little bit...
|
||||
btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f);
|
||||
btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va);
|
||||
}
|
||||
|
||||
|
||||
// vertex 1 = support in direction of origin
|
||||
btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v);
|
||||
btMprVec3Scale(&dir, -1.f);
|
||||
btMprVec3Normalize(&dir);
|
||||
|
||||
|
||||
btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 1));
|
||||
|
||||
btMprSimplexSetSize(portal, 2);
|
||||
|
||||
// test if origin isn't outside of v1
|
||||
dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir);
|
||||
|
||||
|
||||
if (btMprIsZero(dot) || dot < 0.f)
|
||||
return -1;
|
||||
|
||||
|
||||
// vertex 2
|
||||
btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v,
|
||||
&btMprSimplexPoint(portal, 1)->v);
|
||||
if (btMprIsZero(btMprVec3Len2(&dir))){
|
||||
if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org)){
|
||||
// origin lies on v1
|
||||
return 1;
|
||||
}else{
|
||||
// origin lies on v0-v1 segment
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
btMprVec3Normalize(&dir);
|
||||
btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 2));
|
||||
|
||||
|
||||
|
||||
dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir);
|
||||
if (btMprIsZero(dot) || dot < 0.f)
|
||||
return -1;
|
||||
|
||||
btMprSimplexSetSize(portal, 3);
|
||||
|
||||
// vertex 3 direction
|
||||
btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
|
||||
&btMprSimplexPoint(portal, 0)->v);
|
||||
btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
|
||||
&btMprSimplexPoint(portal, 0)->v);
|
||||
btMprVec3Cross(&dir, &va, &vb);
|
||||
btMprVec3Normalize(&dir);
|
||||
|
||||
// it is better to form portal faces to be oriented "outside" origin
|
||||
dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v);
|
||||
if (dot > 0.f){
|
||||
btMprSimplexSwap(portal, 1, 2);
|
||||
btMprVec3Scale(&dir, -1.f);
|
||||
}
|
||||
|
||||
while (btMprSimplexSize(portal) < 4){
|
||||
btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 3));
|
||||
|
||||
dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir);
|
||||
if (btMprIsZero(dot) || dot < 0.f)
|
||||
return -1;
|
||||
|
||||
cont = 0;
|
||||
|
||||
// test if origin is outside (v1, v0, v3) - set v2 as v3 and
|
||||
// continue
|
||||
btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v,
|
||||
&btMprSimplexPoint(portal, 3)->v);
|
||||
dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
|
||||
if (dot < 0.f && !btMprIsZero(dot)){
|
||||
btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3));
|
||||
cont = 1;
|
||||
}
|
||||
|
||||
if (!cont){
|
||||
// test if origin is outside (v3, v0, v2) - set v1 as v3 and
|
||||
// continue
|
||||
btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v,
|
||||
&btMprSimplexPoint(portal, 2)->v);
|
||||
dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v);
|
||||
if (dot < 0.f && !btMprIsZero(dot)){
|
||||
btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3));
|
||||
cont = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (cont){
|
||||
btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v,
|
||||
&btMprSimplexPoint(portal, 0)->v);
|
||||
btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v,
|
||||
&btMprSimplexPoint(portal, 0)->v);
|
||||
btMprVec3Cross(&dir, &va, &vb);
|
||||
btMprVec3Normalize(&dir);
|
||||
}else{
|
||||
btMprSimplexSetSize(portal, 4);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename btConvexTemplate>
|
||||
static int btRefinePortal(const btConvexTemplate& a, const btConvexTemplate& b,const btMprCollisionDescription& colDesc,
|
||||
btMprSimplex_t *portal)
|
||||
{
|
||||
btVector3 dir;
|
||||
btMprSupport_t v4;
|
||||
|
||||
for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
|
||||
//while (1)
|
||||
{
|
||||
// compute direction outside the portal (from v0 throught v1,v2,v3
|
||||
// face)
|
||||
btPortalDir(portal, &dir);
|
||||
|
||||
// test if origin is inside the portal
|
||||
if (portalEncapsulesOrigin(portal, &dir))
|
||||
return 0;
|
||||
|
||||
// get next support point
|
||||
|
||||
btMprSupport(a,b,colDesc, dir, &v4);
|
||||
|
||||
|
||||
// test if v4 can expand portal to contain origin and if portal
|
||||
// expanding doesn't reach given tolerance
|
||||
if (!portalCanEncapsuleOrigin(portal, &v4, &dir)
|
||||
|| portalReachTolerance(portal, &v4, &dir))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// v1-v2-v3 triangle must be rearranged to face outside Minkowski
|
||||
// difference (direction from v0).
|
||||
btExpandPortal(portal, &v4);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void btFindPos(const btMprSimplex_t *portal, btVector3 *pos)
|
||||
{
|
||||
|
||||
btVector3 zero = btVector3(0,0,0);
|
||||
btVector3* origin = &zero;
|
||||
|
||||
btVector3 dir;
|
||||
size_t i;
|
||||
float b[4], sum, inv;
|
||||
btVector3 vec, p1, p2;
|
||||
|
||||
btPortalDir(portal, &dir);
|
||||
|
||||
// use barycentric coordinates of tetrahedron to find origin
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
|
||||
&btMprSimplexPoint(portal, 2)->v);
|
||||
b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
|
||||
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
|
||||
&btMprSimplexPoint(portal, 2)->v);
|
||||
b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
|
||||
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v,
|
||||
&btMprSimplexPoint(portal, 1)->v);
|
||||
b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v);
|
||||
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
|
||||
&btMprSimplexPoint(portal, 1)->v);
|
||||
b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v);
|
||||
|
||||
sum = b[0] + b[1] + b[2] + b[3];
|
||||
|
||||
if (btMprIsZero(sum) || sum < 0.f){
|
||||
b[0] = 0.f;
|
||||
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v,
|
||||
&btMprSimplexPoint(portal, 3)->v);
|
||||
b[1] = btMprVec3Dot(&vec, &dir);
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v,
|
||||
&btMprSimplexPoint(portal, 1)->v);
|
||||
b[2] = btMprVec3Dot(&vec, &dir);
|
||||
btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v,
|
||||
&btMprSimplexPoint(portal, 2)->v);
|
||||
b[3] = btMprVec3Dot(&vec, &dir);
|
||||
|
||||
sum = b[1] + b[2] + b[3];
|
||||
}
|
||||
|
||||
inv = 1.f / sum;
|
||||
|
||||
btMprVec3Copy(&p1, origin);
|
||||
btMprVec3Copy(&p2, origin);
|
||||
for (i = 0; i < 4; i++){
|
||||
btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1);
|
||||
btMprVec3Scale(&vec, b[i]);
|
||||
btMprVec3Add(&p1, &vec);
|
||||
|
||||
btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2);
|
||||
btMprVec3Scale(&vec, b[i]);
|
||||
btMprVec3Add(&p2, &vec);
|
||||
}
|
||||
btMprVec3Scale(&p1, inv);
|
||||
btMprVec3Scale(&p2, inv);
|
||||
#ifdef MPR_AVERAGE_CONTACT_POSITIONS
|
||||
btMprVec3Copy(pos, &p1);
|
||||
btMprVec3Add(pos, &p2);
|
||||
btMprVec3Scale(pos, 0.5);
|
||||
#else
|
||||
btMprVec3Copy(pos, &p2);
|
||||
#endif//MPR_AVERAGE_CONTACT_POSITIONS
|
||||
}
|
||||
|
||||
inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b)
|
||||
{
|
||||
btVector3 ab;
|
||||
btMprVec3Sub2(&ab, a, b);
|
||||
return btMprVec3Len2(&ab);
|
||||
}
|
||||
|
||||
inline float _btMprVec3PointSegmentDist2(const btVector3 *P,
|
||||
const btVector3 *x0,
|
||||
const btVector3 *b,
|
||||
btVector3 *witness)
|
||||
{
|
||||
// The computation comes from solving equation of segment:
|
||||
// S(t) = x0 + t.d
|
||||
// where - x0 is initial point of segment
|
||||
// - d is direction of segment from x0 (|d| > 0)
|
||||
// - t belongs to <0, 1> interval
|
||||
//
|
||||
// Than, distance from a segment to some point P can be expressed:
|
||||
// D(t) = |x0 + t.d - P|^2
|
||||
// which is distance from any point on segment. Minimization
|
||||
// of this function brings distance from P to segment.
|
||||
// Minimization of D(t) leads to simple quadratic equation that's
|
||||
// solving is straightforward.
|
||||
//
|
||||
// Bonus of this method is witness point for free.
|
||||
|
||||
float dist, t;
|
||||
btVector3 d, a;
|
||||
|
||||
// direction of segment
|
||||
btMprVec3Sub2(&d, b, x0);
|
||||
|
||||
// precompute vector from P to x0
|
||||
btMprVec3Sub2(&a, x0, P);
|
||||
|
||||
t = -1.f * btMprVec3Dot(&a, &d);
|
||||
t /= btMprVec3Len2(&d);
|
||||
|
||||
if (t < 0.f || btMprIsZero(t)){
|
||||
dist = btMprVec3Dist2(x0, P);
|
||||
if (witness)
|
||||
btMprVec3Copy(witness, x0);
|
||||
}else if (t > 1.f || btMprEq(t, 1.f)){
|
||||
dist = btMprVec3Dist2(b, P);
|
||||
if (witness)
|
||||
btMprVec3Copy(witness, b);
|
||||
}else{
|
||||
if (witness){
|
||||
btMprVec3Copy(witness, &d);
|
||||
btMprVec3Scale(witness, t);
|
||||
btMprVec3Add(witness, x0);
|
||||
dist = btMprVec3Dist2(witness, P);
|
||||
}else{
|
||||
// recycling variables
|
||||
btMprVec3Scale(&d, t);
|
||||
btMprVec3Add(&d, &a);
|
||||
dist = btMprVec3Len2(&d);
|
||||
}
|
||||
}
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline float btMprVec3PointTriDist2(const btVector3 *P,
|
||||
const btVector3 *x0, const btVector3 *B,
|
||||
const btVector3 *C,
|
||||
btVector3 *witness)
|
||||
{
|
||||
// Computation comes from analytic expression for triangle (x0, B, C)
|
||||
// T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and
|
||||
// Then equation for distance is:
|
||||
// D(s, t) = | T(s, t) - P |^2
|
||||
// This leads to minimization of quadratic function of two variables.
|
||||
// The solution from is taken only if s is between 0 and 1, t is
|
||||
// between 0 and 1 and t + s < 1, otherwise distance from segment is
|
||||
// computed.
|
||||
|
||||
btVector3 d1, d2, a;
|
||||
float u, v, w, p, q, r;
|
||||
float s, t, dist, dist2;
|
||||
btVector3 witness2;
|
||||
|
||||
btMprVec3Sub2(&d1, B, x0);
|
||||
btMprVec3Sub2(&d2, C, x0);
|
||||
btMprVec3Sub2(&a, x0, P);
|
||||
|
||||
u = btMprVec3Dot(&a, &a);
|
||||
v = btMprVec3Dot(&d1, &d1);
|
||||
w = btMprVec3Dot(&d2, &d2);
|
||||
p = btMprVec3Dot(&a, &d1);
|
||||
q = btMprVec3Dot(&a, &d2);
|
||||
r = btMprVec3Dot(&d1, &d2);
|
||||
|
||||
btScalar div = (w * v - r * r);
|
||||
if (btMprIsZero(div))
|
||||
{
|
||||
s=-1;
|
||||
} else
|
||||
{
|
||||
s = (q * r - w * p) / div;
|
||||
t = (-s * r - q) / w;
|
||||
}
|
||||
|
||||
if ((btMprIsZero(s) || s > 0.f)
|
||||
&& (btMprEq(s, 1.f) || s < 1.f)
|
||||
&& (btMprIsZero(t) || t > 0.f)
|
||||
&& (btMprEq(t, 1.f) || t < 1.f)
|
||||
&& (btMprEq(t + s, 1.f) || t + s < 1.f)){
|
||||
|
||||
if (witness){
|
||||
btMprVec3Scale(&d1, s);
|
||||
btMprVec3Scale(&d2, t);
|
||||
btMprVec3Copy(witness, x0);
|
||||
btMprVec3Add(witness, &d1);
|
||||
btMprVec3Add(witness, &d2);
|
||||
|
||||
dist = btMprVec3Dist2(witness, P);
|
||||
}else{
|
||||
dist = s * s * v;
|
||||
dist += t * t * w;
|
||||
dist += 2.f * s * t * r;
|
||||
dist += 2.f * s * p;
|
||||
dist += 2.f * t * q;
|
||||
dist += u;
|
||||
}
|
||||
}else{
|
||||
dist = _btMprVec3PointSegmentDist2(P, x0, B, witness);
|
||||
|
||||
dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2);
|
||||
if (dist2 < dist){
|
||||
dist = dist2;
|
||||
if (witness)
|
||||
btMprVec3Copy(witness, &witness2);
|
||||
}
|
||||
|
||||
dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2);
|
||||
if (dist2 < dist){
|
||||
dist = dist2;
|
||||
if (witness)
|
||||
btMprVec3Copy(witness, &witness2);
|
||||
}
|
||||
}
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename btConvexTemplate>
|
||||
static void btFindPenetr(const btConvexTemplate& a, const btConvexTemplate& b,
|
||||
const btMprCollisionDescription& colDesc,
|
||||
btMprSimplex_t *portal,
|
||||
float *depth, btVector3 *pdir, btVector3 *pos)
|
||||
{
|
||||
btVector3 dir;
|
||||
btMprSupport_t v4;
|
||||
unsigned long iterations;
|
||||
|
||||
btVector3 zero = btVector3(0,0,0);
|
||||
btVector3* origin = &zero;
|
||||
|
||||
|
||||
iterations = 1UL;
|
||||
for (int i=0;i<BT_MPR_MAX_ITERATIONS;i++)
|
||||
//while (1)
|
||||
{
|
||||
// compute portal direction and obtain next support point
|
||||
btPortalDir(portal, &dir);
|
||||
|
||||
btMprSupport(a,b,colDesc, dir, &v4);
|
||||
|
||||
|
||||
// reached tolerance -> find penetration info
|
||||
if (portalReachTolerance(portal, &v4, &dir)
|
||||
|| iterations ==BT_MPR_MAX_ITERATIONS)
|
||||
{
|
||||
*depth = btMprVec3PointTriDist2(origin,&btMprSimplexPoint(portal, 1)->v,&btMprSimplexPoint(portal, 2)->v,&btMprSimplexPoint(portal, 3)->v,pdir);
|
||||
*depth = BT_MPR_SQRT(*depth);
|
||||
|
||||
if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z()))
|
||||
{
|
||||
|
||||
*pdir = dir;
|
||||
}
|
||||
btMprVec3Normalize(pdir);
|
||||
|
||||
// barycentric coordinates:
|
||||
btFindPos(portal, pos);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
btExpandPortal(portal, &v4);
|
||||
|
||||
iterations++;
|
||||
}
|
||||
}
|
||||
|
||||
static void btFindPenetrTouch(btMprSimplex_t *portal,float *depth, btVector3 *dir, btVector3 *pos)
|
||||
{
|
||||
// Touching contact on portal's v1 - so depth is zero and direction
|
||||
// is unimportant and pos can be guessed
|
||||
*depth = 0.f;
|
||||
btVector3 zero = btVector3(0,0,0);
|
||||
btVector3* origin = &zero;
|
||||
|
||||
|
||||
btMprVec3Copy(dir, origin);
|
||||
#ifdef MPR_AVERAGE_CONTACT_POSITIONS
|
||||
btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
|
||||
btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
|
||||
btMprVec3Scale(pos, 0.5);
|
||||
#else
|
||||
btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void btFindPenetrSegment(btMprSimplex_t *portal,
|
||||
float *depth, btVector3 *dir, btVector3 *pos)
|
||||
{
|
||||
|
||||
// Origin lies on v0-v1 segment.
|
||||
// Depth is distance to v1, direction also and position must be
|
||||
// computed
|
||||
#ifdef MPR_AVERAGE_CONTACT_POSITIONS
|
||||
btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1);
|
||||
btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2);
|
||||
btMprVec3Scale(pos, 0.5f);
|
||||
#else
|
||||
btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2);
|
||||
#endif//MPR_AVERAGE_CONTACT_POSITIONS
|
||||
|
||||
btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v);
|
||||
*depth = BT_MPR_SQRT(btMprVec3Len2(dir));
|
||||
btMprVec3Normalize(dir);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename btConvexTemplate>
|
||||
inline int btMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b,
|
||||
const btMprCollisionDescription& colDesc,
|
||||
float *depthOut, btVector3* dirOut, btVector3* posOut)
|
||||
{
|
||||
|
||||
btMprSimplex_t portal;
|
||||
|
||||
|
||||
// Phase 1: Portal discovery
|
||||
int result = btDiscoverPortal(a,b,colDesc, &portal);
|
||||
|
||||
|
||||
//sepAxis[pairIndex] = *pdir;//or -dir?
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// Phase 2: Portal refinement
|
||||
|
||||
result = btRefinePortal(a,b,colDesc, &portal);
|
||||
if (result < 0)
|
||||
return -1;
|
||||
|
||||
// Phase 3. Penetration info
|
||||
btFindPenetr(a,b,colDesc, &portal, depthOut, dirOut, posOut);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// Touching contact on portal's v1.
|
||||
btFindPenetrTouch(&portal, depthOut, dirOut, posOut);
|
||||
result=0;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
|
||||
btFindPenetrSegment( &portal, depthOut, dirOut, posOut);
|
||||
result=0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
//if (res < 0)
|
||||
//{
|
||||
// Origin isn't inside portal - no collision.
|
||||
result = -1;
|
||||
//}
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
template<typename btConvexTemplate, typename btMprDistanceTemplate>
|
||||
inline int btComputeMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, const
|
||||
btMprCollisionDescription& colDesc, btMprDistanceTemplate* distInfo)
|
||||
{
|
||||
btVector3 dir,pos;
|
||||
float depth;
|
||||
|
||||
int res = btMprPenetration(a,b,colDesc,&depth, &dir, &pos);
|
||||
if (res==0)
|
||||
{
|
||||
distInfo->m_distance = -depth;
|
||||
distInfo->m_pointOnB = pos;
|
||||
distInfo->m_normalBtoA = -dir;
|
||||
distInfo->m_pointOnA = pos-distInfo->m_distance*dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //BT_MPR_PENETRATION_H
|
||||
|
|
@ -163,7 +163,7 @@ public:
|
|||
//get rid of duplicated userPersistentData pointer
|
||||
m_pointCache[lastUsedIndex].m_userPersistentData = 0;
|
||||
m_pointCache[lastUsedIndex].m_appliedImpulse = 0.f;
|
||||
m_pointCache[lastUsedIndex].m_lateralFrictionInitialized = false;
|
||||
m_pointCache[lastUsedIndex].m_contactPointFlags = 0;
|
||||
m_pointCache[lastUsedIndex].m_appliedImpulseLateral1 = 0.f;
|
||||
m_pointCache[lastUsedIndex].m_appliedImpulseLateral2 = 0.f;
|
||||
m_pointCache[lastUsedIndex].m_lifeTime = 0;
|
||||
|
|
@ -190,16 +190,11 @@ public:
|
|||
void* cache = m_pointCache[insertIndex].m_userPersistentData;
|
||||
|
||||
m_pointCache[insertIndex] = newPoint;
|
||||
|
||||
m_pointCache[insertIndex].m_userPersistentData = cache;
|
||||
m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse;
|
||||
m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
|
||||
m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
|
||||
|
||||
m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse;
|
||||
m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1;
|
||||
m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2;
|
||||
|
||||
|
||||
m_pointCache[insertIndex].m_lifeTime = lifeTime;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static int gActualSATPairTests=0;
|
|||
|
||||
inline bool IsAlmostZero(const btVector3& v)
|
||||
{
|
||||
if(fabsf(v.x())>1e-6 || fabsf(v.y())>1e-6 || fabsf(v.z())>1e-6) return false;
|
||||
if(btFabs(v.x())>1e-6 || btFabs(v.y())>1e-6 || btFabs(v.z())>1e-6) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ bool btPolyhedralContactClipping::findSeparatingAxis( const btConvexPolyhedron&
|
|||
int edgeB=-1;
|
||||
btVector3 worldEdgeA;
|
||||
btVector3 worldEdgeB;
|
||||
btVector3 witnessPointA,witnessPointB;
|
||||
btVector3 witnessPointA(0,0,0),witnessPointB(0,0,0);
|
||||
|
||||
|
||||
int curEdgeEdge = 0;
|
||||
|
|
@ -411,9 +411,9 @@ bool btPolyhedralContactClipping::findSeparatingAxis( const btConvexPolyhedron&
|
|||
return true;
|
||||
}
|
||||
|
||||
void btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut)
|
||||
void btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1,btVertexArray& worldVertsB2, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut)
|
||||
{
|
||||
btVertexArray worldVertsB2;
|
||||
worldVertsB2.resize(0);
|
||||
btVertexArray* pVtxIn = &worldVertsB1;
|
||||
btVertexArray* pVtxOut = &worldVertsB2;
|
||||
pVtxOut->reserve(pVtxIn->size());
|
||||
|
|
@ -527,7 +527,7 @@ void btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatin
|
|||
|
||||
|
||||
|
||||
void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut)
|
||||
void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btVertexArray& worldVertsB1,btVertexArray& worldVertsB2,btDiscreteCollisionDetectorInterface::Result& resultOut)
|
||||
{
|
||||
|
||||
btVector3 separatingNormal = separatingNormal1.normalized();
|
||||
|
|
@ -552,7 +552,7 @@ void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatin
|
|||
}
|
||||
}
|
||||
}
|
||||
btVertexArray worldVertsB1;
|
||||
worldVertsB1.resize(0);
|
||||
{
|
||||
const btFace& polyB = hullB.m_faces[closestFaceB];
|
||||
const int numVertices = polyB.m_indices.size();
|
||||
|
|
@ -565,6 +565,6 @@ void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatin
|
|||
|
||||
|
||||
if (closestFaceB>=0)
|
||||
clipFaceAgainstHull(separatingNormal, hullA, transA,worldVertsB1, minDist, maxDist,resultOut);
|
||||
clipFaceAgainstHull(separatingNormal, hullA, transA,worldVertsB1, worldVertsB2,minDist, maxDist,resultOut);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,8 +32,11 @@ typedef btAlignedObjectArray<btVector3> btVertexArray;
|
|||
// Clips a face to the back of a plane
|
||||
struct btPolyhedralContactClipping
|
||||
{
|
||||
static void clipHullAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist, btDiscreteCollisionDetectorInterface::Result& resultOut);
|
||||
static void clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut);
|
||||
|
||||
static void clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btVertexArray& worldVertsB1,btVertexArray& worldVertsB2,btDiscreteCollisionDetectorInterface::Result& resultOut);
|
||||
|
||||
static void clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1,btVertexArray& worldVertsB2, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut);
|
||||
|
||||
|
||||
static bool findSeparatingAxis( const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, btVector3& sep, btDiscreteCollisionDetectorInterface::Result& resultOut);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,10 +32,12 @@ public:
|
|||
//@BP Mod - allow backface filtering and unflipped normals
|
||||
enum EFlags
|
||||
{
|
||||
kF_None = 0,
|
||||
kF_None = 0,
|
||||
kF_FilterBackfaces = 1 << 0,
|
||||
kF_KeepUnflippedNormal = 1 << 1, // Prevents returned face normal getting flipped when a ray hits a back-facing triangle
|
||||
kF_UseSubSimplexConvexCastRaytest = 1 << 2, // Uses an approximate but faster ray versus convex intersection algorithm
|
||||
///SubSimplexConvexCastRaytest is the default, even if kF_None is set.
|
||||
kF_UseSubSimplexConvexCastRaytest = 1 << 2, // Uses an approximate but faster ray versus convex intersection algorithm
|
||||
kF_UseGjkConvexCastRaytest = 1 << 3,
|
||||
kF_Terminator = 0xFFFFFFFF
|
||||
};
|
||||
unsigned int m_flags;
|
||||
|
|
|
|||
|
|
@ -65,10 +65,10 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
|
|||
|
||||
btVector3 n;
|
||||
n.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
|
||||
bool hasResult = false;
|
||||
|
||||
btVector3 c;
|
||||
|
||||
btScalar lastLambda = lambda;
|
||||
|
||||
|
||||
|
||||
btScalar dist2 = v.length2();
|
||||
|
|
@ -109,9 +109,9 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
|
|||
//m_simplexSolver->reset();
|
||||
//check next line
|
||||
w = supVertexA-supVertexB;
|
||||
lastLambda = lambda;
|
||||
|
||||
n = v;
|
||||
hasResult = true;
|
||||
|
||||
}
|
||||
}
|
||||
///Just like regular GJK only add the vertex if it isn't already (close) to current vertex, it would lead to divisions by zero and NaN etc.
|
||||
|
|
@ -121,7 +121,7 @@ bool btSubsimplexConvexCast::calcTimeOfImpact(
|
|||
if (m_simplexSolver->closest(v))
|
||||
{
|
||||
dist2 = v.length2();
|
||||
hasResult = true;
|
||||
|
||||
//todo: check this normal for validity
|
||||
//n=v;
|
||||
//printf("V=%f , %f, %f\n",v[0],v[1],v[2]);
|
||||
|
|
|
|||
|
|
@ -294,7 +294,10 @@ bool btVoronoiSimplexSolver::inSimplex(const btVector3& w)
|
|||
#else
|
||||
if (m_simplexVectorW[i] == w)
|
||||
#endif
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check in case lastW is already removed
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@ subject to the following restrictions:
|
|||
|
||||
///disable next define, or use defaultCollisionConfiguration->getSimplexSolver()->setEqualVertexThreshold(0.f) to disable/configure
|
||||
#define BT_USE_EQUAL_VERTEX_THRESHOLD
|
||||
#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f
|
||||
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 1e-12f
|
||||
#else
|
||||
#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f
|
||||
#endif//BT_USE_DOUBLE_PRECISION
|
||||
|
||||
struct btUsageBitfield{
|
||||
btUsageBitfield()
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
project "BulletCollision"
|
||||
|
||||
|
||||
kind "StaticLib"
|
||||
targetdir "../../lib"
|
||||
includedirs {
|
||||
"..",
|
||||
}
|
||||
files {
|
||||
"**.cpp",
|
||||
"**.h"
|
||||
}
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"BroadphaseCollision/*.cpp",
|
||||
"BroadphaseCollision/*.h",
|
||||
"CollisionDispatch/*.cpp",
|
||||
"CollisionDispatch/*.h",
|
||||
"CollisionShapes/*.cpp",
|
||||
"CollisionShapes/*.h",
|
||||
"Gimpact/*.cpp",
|
||||
"Gimpact/*.h",
|
||||
"NarrowPhaseCollision/*.cpp",
|
||||
"NarrowPhaseCollision/*.h",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,18 +10,22 @@ SET(BulletDynamics_SRCS
|
|||
ConstraintSolver/btGearConstraint.cpp
|
||||
ConstraintSolver/btGeneric6DofConstraint.cpp
|
||||
ConstraintSolver/btGeneric6DofSpringConstraint.cpp
|
||||
ConstraintSolver/btGeneric6DofSpring2Constraint.cpp
|
||||
ConstraintSolver/btHinge2Constraint.cpp
|
||||
ConstraintSolver/btHingeConstraint.cpp
|
||||
ConstraintSolver/btPoint2PointConstraint.cpp
|
||||
ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
|
||||
ConstraintSolver/btNNCGConstraintSolver.cpp
|
||||
ConstraintSolver/btSliderConstraint.cpp
|
||||
ConstraintSolver/btSolve2LinearConstraint.cpp
|
||||
ConstraintSolver/btTypedConstraint.cpp
|
||||
ConstraintSolver/btUniversalConstraint.cpp
|
||||
Dynamics/btDiscreteDynamicsWorld.cpp
|
||||
Dynamics/btDiscreteDynamicsWorldMt.cpp
|
||||
Dynamics/btSimulationIslandManagerMt.cpp
|
||||
Dynamics/btRigidBody.cpp
|
||||
Dynamics/btSimpleDynamicsWorld.cpp
|
||||
Dynamics/Bullet-C-API.cpp
|
||||
# Dynamics/Bullet-C-API.cpp
|
||||
Vehicle/btRaycastVehicle.cpp
|
||||
Vehicle/btWheelInfo.cpp
|
||||
Featherstone/btMultiBody.cpp
|
||||
|
|
@ -30,9 +34,12 @@ SET(BulletDynamics_SRCS
|
|||
Featherstone/btMultiBodyJointLimitConstraint.cpp
|
||||
Featherstone/btMultiBodyConstraint.cpp
|
||||
Featherstone/btMultiBodyPoint2Point.cpp
|
||||
Featherstone/btMultiBodyFixedConstraint.cpp
|
||||
Featherstone/btMultiBodySliderConstraint.cpp
|
||||
Featherstone/btMultiBodyJointMotor.cpp
|
||||
MLCPSolvers/btDantzigLCP.cpp
|
||||
MLCPSolvers/btMLCPSolver.cpp
|
||||
MLCPSolvers/btLemkeAlgorithm.cpp
|
||||
)
|
||||
|
||||
SET(Root_HDRS
|
||||
|
|
@ -48,11 +55,13 @@ SET(ConstraintSolver_HDRS
|
|||
ConstraintSolver/btGearConstraint.h
|
||||
ConstraintSolver/btGeneric6DofConstraint.h
|
||||
ConstraintSolver/btGeneric6DofSpringConstraint.h
|
||||
ConstraintSolver/btGeneric6DofSpring2Constraint.h
|
||||
ConstraintSolver/btHinge2Constraint.h
|
||||
ConstraintSolver/btHingeConstraint.h
|
||||
ConstraintSolver/btJacobianEntry.h
|
||||
ConstraintSolver/btPoint2PointConstraint.h
|
||||
ConstraintSolver/btSequentialImpulseConstraintSolver.h
|
||||
ConstraintSolver/btNNCGConstraintSolver.h
|
||||
ConstraintSolver/btSliderConstraint.h
|
||||
ConstraintSolver/btSolve2LinearConstraint.h
|
||||
ConstraintSolver/btSolverBody.h
|
||||
|
|
@ -63,6 +72,8 @@ SET(ConstraintSolver_HDRS
|
|||
SET(Dynamics_HDRS
|
||||
Dynamics/btActionInterface.h
|
||||
Dynamics/btDiscreteDynamicsWorld.h
|
||||
Dynamics/btDiscreteDynamicsWorldMt.h
|
||||
Dynamics/btSimulationIslandManagerMt.h
|
||||
Dynamics/btDynamicsWorld.h
|
||||
Dynamics/btSimpleDynamicsWorld.h
|
||||
Dynamics/btRigidBody.h
|
||||
|
|
@ -84,6 +95,8 @@ SET(Featherstone_HDRS
|
|||
Featherstone/btMultiBodyJointLimitConstraint.h
|
||||
Featherstone/btMultiBodyConstraint.h
|
||||
Featherstone/btMultiBodyPoint2Point.h
|
||||
Featherstone/btMultiBodyFixedConstraint.h
|
||||
Featherstone/btMultiBodySliderConstraint.h
|
||||
Featherstone/btMultiBodyJointMotor.h
|
||||
)
|
||||
|
||||
|
|
@ -93,7 +106,9 @@ SET(MLCPSolvers_HDRS
|
|||
MLCPSolvers/btMLCPSolver.h
|
||||
MLCPSolvers/btMLCPSolverInterface.h
|
||||
MLCPSolvers/btPATHSolver.h
|
||||
MLCPSolvers/btSolveProjectedGaussSeidel.h
|
||||
MLCPSolvers/btSolveProjectedGaussSeidel.h
|
||||
MLCPSolvers/btLemkeSolver.h
|
||||
MLCPSolvers/btLemkeAlgorithm.h
|
||||
)
|
||||
|
||||
SET(Character_HDRS
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public:
|
|||
virtual void preStep ( btCollisionWorld* collisionWorld) = 0;
|
||||
virtual void playerStep (btCollisionWorld* collisionWorld, btScalar dt) = 0;
|
||||
virtual bool canJump () const = 0;
|
||||
virtual void jump () = 0;
|
||||
virtual void jump(const btVector3& dir = btVector3()) = 0;
|
||||
|
||||
virtual bool onGround () const = 0;
|
||||
virtual void setUpInterpolate (bool value) = 0;
|
||||
|
|
|
|||
|
|
@ -29,9 +29,10 @@ subject to the following restrictions:
|
|||
static btVector3
|
||||
getNormalizedVector(const btVector3& v)
|
||||
{
|
||||
btVector3 n = v.normalized();
|
||||
if (n.length() < SIMD_EPSILON) {
|
||||
n.setValue(0, 0, 0);
|
||||
btVector3 n(0, 0, 0);
|
||||
|
||||
if (v.length() > SIMD_EPSILON) {
|
||||
n = v.normalized();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
|
@ -131,30 +132,37 @@ btVector3 btKinematicCharacterController::perpindicularComponent (const btVector
|
|||
return direction - parallelComponent(direction, normal);
|
||||
}
|
||||
|
||||
btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis)
|
||||
btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up)
|
||||
{
|
||||
m_upAxis = upAxis;
|
||||
m_addedMargin = 0.02;
|
||||
m_walkDirection.setValue(0,0,0);
|
||||
m_useGhostObjectSweepTest = true;
|
||||
m_ghostObject = ghostObject;
|
||||
m_stepHeight = stepHeight;
|
||||
m_up.setValue(0.0f, 0.0f, 1.0f);
|
||||
m_jumpAxis.setValue(0.0f, 0.0f, 1.0f);
|
||||
setUp(up);
|
||||
setStepHeight(stepHeight);
|
||||
m_addedMargin = 0.02;
|
||||
m_walkDirection.setValue(0.0,0.0,0.0);
|
||||
m_AngVel.setValue(0.0, 0.0, 0.0);
|
||||
m_useGhostObjectSweepTest = true;
|
||||
m_turnAngle = btScalar(0.0);
|
||||
m_convexShape=convexShape;
|
||||
m_useWalkDirection = true; // use walk direction by default, legacy behavior
|
||||
m_velocityTimeInterval = 0.0;
|
||||
m_verticalVelocity = 0.0;
|
||||
m_verticalOffset = 0.0;
|
||||
m_gravity = 9.8 * 3 ; // 3G acceleration.
|
||||
m_gravity = 9.8 * 3.0 ; // 3G acceleration.
|
||||
m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s.
|
||||
m_jumpSpeed = 10.0; // ?
|
||||
m_SetjumpSpeed = m_jumpSpeed;
|
||||
m_wasOnGround = false;
|
||||
m_wasJumping = false;
|
||||
m_interpolateUp = true;
|
||||
setMaxSlope(btRadians(45.0));
|
||||
m_currentStepOffset = 0;
|
||||
m_currentStepOffset = 0.0;
|
||||
m_maxPenetrationDepth = 0.2;
|
||||
full_drop = false;
|
||||
bounce_fix = false;
|
||||
m_linearDamping = btScalar(0.0);
|
||||
m_angularDamping = btScalar(0.0);
|
||||
}
|
||||
|
||||
btKinematicCharacterController::~btKinematicCharacterController ()
|
||||
|
|
@ -189,7 +197,7 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld*
|
|||
|
||||
m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||
|
||||
btScalar maxPen = btScalar(0.0);
|
||||
// btScalar maxPen = btScalar(0.0);
|
||||
for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
|
||||
{
|
||||
m_manifoldArray.resize(0);
|
||||
|
|
@ -197,10 +205,13 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld*
|
|||
btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i];
|
||||
|
||||
btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject);
|
||||
btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
|
||||
btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject);
|
||||
|
||||
if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse()))
|
||||
continue;
|
||||
|
||||
if (!needsCollision(obj0, obj1))
|
||||
continue;
|
||||
|
||||
if (collisionPair->m_algorithm)
|
||||
collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray);
|
||||
|
|
@ -216,14 +227,15 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld*
|
|||
|
||||
btScalar dist = pt.getDistance();
|
||||
|
||||
if (dist < 0.0)
|
||||
if (dist < -m_maxPenetrationDepth)
|
||||
{
|
||||
if (dist < maxPen)
|
||||
{
|
||||
maxPen = dist;
|
||||
m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
|
||||
// TODO: cause problems on slopes, not sure if it is needed
|
||||
//if (dist < maxPen)
|
||||
//{
|
||||
// maxPen = dist;
|
||||
// m_touchingNormal = pt.m_normalWorldOnB * directionSign;//??
|
||||
|
||||
}
|
||||
//}
|
||||
m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2);
|
||||
penetration = true;
|
||||
} else {
|
||||
|
|
@ -243,18 +255,28 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld*
|
|||
|
||||
void btKinematicCharacterController::stepUp ( btCollisionWorld* world)
|
||||
{
|
||||
btScalar stepHeight = 0.0f;
|
||||
if (m_verticalVelocity < 0.0)
|
||||
stepHeight = m_stepHeight;
|
||||
|
||||
// phase 1: up
|
||||
btTransform start, end;
|
||||
m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f));
|
||||
|
||||
start.setIdentity ();
|
||||
end.setIdentity ();
|
||||
|
||||
/* FIXME: Handle penetration properly */
|
||||
start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin));
|
||||
start.setOrigin(m_currentPosition);
|
||||
|
||||
m_targetPosition = m_currentPosition + m_up * (stepHeight) + m_jumpAxis * ((m_verticalOffset > 0.f ? m_verticalOffset : 0.f));
|
||||
m_currentPosition = m_targetPosition;
|
||||
|
||||
end.setOrigin (m_targetPosition);
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071));
|
||||
start.setRotation(m_currentOrientation);
|
||||
end.setRotation(m_targetOrientation);
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, -m_up, m_maxSlopeCosine);
|
||||
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
|
|
@ -264,29 +286,61 @@ void btKinematicCharacterController::stepUp ( btCollisionWorld* world)
|
|||
}
|
||||
else
|
||||
{
|
||||
world->convexSweepTest (m_convexShape, start, end, callback);
|
||||
world->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration);
|
||||
}
|
||||
|
||||
if (callback.hasHit())
|
||||
|
||||
if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))
|
||||
{
|
||||
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
||||
if(callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0)
|
||||
if (callback.m_hitNormalWorld.dot(m_up) > 0.0)
|
||||
{
|
||||
// we moved up only a fraction of the step height
|
||||
m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction;
|
||||
m_currentStepOffset = stepHeight * callback.m_closestHitFraction;
|
||||
if (m_interpolateUp == true)
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
|
||||
else
|
||||
m_currentPosition = m_targetPosition;
|
||||
}
|
||||
m_verticalVelocity = 0.0;
|
||||
m_verticalOffset = 0.0;
|
||||
|
||||
btTransform& xform = m_ghostObject->getWorldTransform();
|
||||
xform.setOrigin(m_currentPosition);
|
||||
m_ghostObject->setWorldTransform(xform);
|
||||
|
||||
// fix penetration if we hit a ceiling for example
|
||||
int numPenetrationLoops = 0;
|
||||
m_touchingContact = false;
|
||||
while (recoverFromPenetration(world))
|
||||
{
|
||||
numPenetrationLoops++;
|
||||
m_touchingContact = true;
|
||||
if (numPenetrationLoops > 4)
|
||||
{
|
||||
//printf("character could not recover from penetration = %d\n", numPenetrationLoops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_targetPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||
m_currentPosition = m_targetPosition;
|
||||
|
||||
if (m_verticalOffset > 0)
|
||||
{
|
||||
m_verticalOffset = 0.0;
|
||||
m_verticalVelocity = 0.0;
|
||||
m_currentStepOffset = m_stepHeight;
|
||||
}
|
||||
} else {
|
||||
m_currentStepOffset = m_stepHeight;
|
||||
m_currentStepOffset = stepHeight;
|
||||
m_currentPosition = m_targetPosition;
|
||||
}
|
||||
}
|
||||
|
||||
bool btKinematicCharacterController::needsCollision(const btCollisionObject* body0, const btCollisionObject* body1)
|
||||
{
|
||||
bool collides = (body0->getBroadphaseHandle()->m_collisionFilterGroup & body1->getBroadphaseHandle()->m_collisionFilterMask) != 0;
|
||||
collides = collides && (body1->getBroadphaseHandle()->m_collisionFilterGroup & body0->getBroadphaseHandle()->m_collisionFilterMask);
|
||||
return collides;
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag)
|
||||
{
|
||||
btVector3 movementDirection = m_targetPosition - m_currentPosition;
|
||||
|
|
@ -329,6 +383,7 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co
|
|||
// m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]);
|
||||
// phase 2: forward and strafe
|
||||
btTransform start, end;
|
||||
|
||||
m_targetPosition = m_currentPosition + walkMove;
|
||||
|
||||
start.setIdentity ();
|
||||
|
|
@ -338,15 +393,6 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co
|
|||
btScalar distance2 = (m_currentPosition-m_targetPosition).length2();
|
||||
// printf("distance2=%f\n",distance2);
|
||||
|
||||
if (m_touchingContact)
|
||||
{
|
||||
if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0))
|
||||
{
|
||||
//interferes with step movement
|
||||
//updateTargetPositionBasedOnCollision (m_touchingNormal);
|
||||
}
|
||||
}
|
||||
|
||||
int maxIter = 10;
|
||||
|
||||
while (fraction > btScalar(0.01) && maxIter-- > 0)
|
||||
|
|
@ -355,6 +401,9 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co
|
|||
end.setOrigin (m_targetPosition);
|
||||
btVector3 sweepDirNegative(m_currentPosition - m_targetPosition);
|
||||
|
||||
start.setRotation(m_currentOrientation);
|
||||
end.setRotation(m_targetOrientation);
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0));
|
||||
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
|
@ -363,25 +412,27 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co
|
|||
btScalar margin = m_convexShape->getMargin();
|
||||
m_convexShape->setMargin(margin + m_addedMargin);
|
||||
|
||||
|
||||
if (m_useGhostObjectSweepTest)
|
||||
if (!(start == end))
|
||||
{
|
||||
m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
} else
|
||||
{
|
||||
collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
if (m_useGhostObjectSweepTest)
|
||||
{
|
||||
m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
}
|
||||
else
|
||||
{
|
||||
collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
}
|
||||
}
|
||||
|
||||
m_convexShape->setMargin(margin);
|
||||
|
||||
|
||||
fraction -= callback.m_closestHitFraction;
|
||||
|
||||
if (callback.hasHit())
|
||||
if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))
|
||||
{
|
||||
// we moved only a fraction
|
||||
btScalar hitDistance;
|
||||
hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
|
||||
//btScalar hitDistance;
|
||||
//hitDistance = (callback.m_hitPointWorld - m_currentPosition).length();
|
||||
|
||||
// m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
|
||||
|
||||
|
|
@ -402,14 +453,11 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co
|
|||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// we moved whole way
|
||||
m_currentPosition = m_targetPosition;
|
||||
}
|
||||
|
||||
// if (callback.m_closestHitFraction == 0.f)
|
||||
// break;
|
||||
|
||||
else
|
||||
{
|
||||
m_currentPosition = m_targetPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -420,27 +468,30 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
|
||||
// phase 3: down
|
||||
/*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0;
|
||||
btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep);
|
||||
btVector3 step_drop = m_up * (m_currentStepOffset + additionalDownStep);
|
||||
btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt;
|
||||
btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity;
|
||||
btVector3 gravity_drop = m_up * downVelocity;
|
||||
m_targetPosition -= (step_drop + gravity_drop);*/
|
||||
|
||||
btVector3 orig_position = m_targetPosition;
|
||||
|
||||
btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
|
||||
|
||||
if (m_verticalVelocity > 0.0)
|
||||
return;
|
||||
|
||||
if(downVelocity > 0.0 && downVelocity > m_fallSpeed
|
||||
&& (m_wasOnGround || !m_wasJumping))
|
||||
downVelocity = m_fallSpeed;
|
||||
|
||||
btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
|
||||
btVector3 step_drop = m_up * (m_currentStepOffset + downVelocity);
|
||||
m_targetPosition -= step_drop;
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine);
|
||||
btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, m_up, m_maxSlopeCosine);
|
||||
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
btKinematicClosestNotMeConvexResultCallback callback2 (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine);
|
||||
btKinematicClosestNotMeConvexResultCallback callback2(m_ghostObject, m_up, m_maxSlopeCosine);
|
||||
callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
|
|
@ -454,6 +505,9 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
start.setOrigin (m_currentPosition);
|
||||
end.setOrigin (m_targetPosition);
|
||||
|
||||
start.setRotation(m_currentOrientation);
|
||||
end.setRotation(m_targetOrientation);
|
||||
|
||||
//set double test for 2x the step drop, to check for a large drop vs small drop
|
||||
end_double.setOrigin (m_targetPosition - step_drop);
|
||||
|
||||
|
|
@ -461,7 +515,7 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
{
|
||||
m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
|
||||
if (!callback.hasHit())
|
||||
if (!callback.hasHit() && m_ghostObject->hasContactResponse())
|
||||
{
|
||||
//test a double fall height, to see if the character should interpolate it's fall (full) or not (partial)
|
||||
m_ghostObject->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
|
|
@ -470,30 +524,34 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
{
|
||||
collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
|
||||
if (!callback.hasHit())
|
||||
{
|
||||
//test a double fall height, to see if the character should interpolate it's fall (large) or not (small)
|
||||
collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
}
|
||||
if (!callback.hasHit() && m_ghostObject->hasContactResponse())
|
||||
{
|
||||
//test a double fall height, to see if the character should interpolate it's fall (large) or not (small)
|
||||
collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
}
|
||||
}
|
||||
|
||||
btScalar downVelocity2 = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt;
|
||||
bool has_hit = false;
|
||||
bool has_hit;
|
||||
if (bounce_fix == true)
|
||||
has_hit = callback.hasHit() || callback2.hasHit();
|
||||
has_hit = (callback.hasHit() || callback2.hasHit()) && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject);
|
||||
else
|
||||
has_hit = callback2.hasHit();
|
||||
has_hit = callback2.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback2.m_hitCollisionObject);
|
||||
|
||||
if(downVelocity2 > 0.0 && downVelocity2 < m_stepHeight && has_hit == true && runonce == false
|
||||
btScalar stepHeight = 0.0f;
|
||||
if (m_verticalVelocity < 0.0)
|
||||
stepHeight = m_stepHeight;
|
||||
|
||||
if (downVelocity2 > 0.0 && downVelocity2 < stepHeight && has_hit == true && runonce == false
|
||||
&& (m_wasOnGround || !m_wasJumping))
|
||||
{
|
||||
//redo the velocity calculation when falling a small amount, for fast stairs motion
|
||||
//for larger falls, use the smoother/slower interpolated movement by not touching the target position
|
||||
|
||||
m_targetPosition = orig_position;
|
||||
downVelocity = m_stepHeight;
|
||||
downVelocity = stepHeight;
|
||||
|
||||
btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
|
||||
step_drop = m_up * (m_currentStepOffset + downVelocity);
|
||||
m_targetPosition -= step_drop;
|
||||
runonce = true;
|
||||
continue; //re-run previous tests
|
||||
|
|
@ -501,10 +559,9 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
break;
|
||||
}
|
||||
|
||||
if (callback.hasHit() || runonce == true)
|
||||
if (m_ghostObject->hasContactResponse() && (callback.hasHit() && needsCollision(m_ghostObject, callback.m_hitCollisionObject)) || runonce == true)
|
||||
{
|
||||
// we dropped a fraction of the height -> hit floor
|
||||
|
||||
btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2;
|
||||
|
||||
//printf("hitpoint: %g - pos %g\n", callback.m_hitPointWorld.getY(), m_currentPosition.getY());
|
||||
|
|
@ -512,10 +569,10 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
if (bounce_fix == true)
|
||||
{
|
||||
if (full_drop == true)
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
|
||||
else
|
||||
//due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction);
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
|
||||
else
|
||||
//due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction);
|
||||
}
|
||||
else
|
||||
m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction);
|
||||
|
|
@ -527,7 +584,7 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
m_wasJumping = false;
|
||||
} else {
|
||||
// we dropped the full height
|
||||
|
||||
|
||||
full_drop = true;
|
||||
|
||||
if (bounce_fix == true)
|
||||
|
|
@ -537,7 +594,7 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld
|
|||
{
|
||||
m_targetPosition += step_drop; //undo previous target change
|
||||
downVelocity = m_fallSpeed;
|
||||
step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity);
|
||||
step_drop = m_up * (m_currentStepOffset + downVelocity);
|
||||
m_targetPosition -= step_drop;
|
||||
}
|
||||
}
|
||||
|
|
@ -578,21 +635,63 @@ btScalar timeInterval
|
|||
m_velocityTimeInterval += timeInterval;
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setAngularVelocity(const btVector3& velocity)
|
||||
{
|
||||
m_AngVel = velocity;
|
||||
}
|
||||
|
||||
const btVector3& btKinematicCharacterController::getAngularVelocity() const
|
||||
{
|
||||
return m_AngVel;
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setLinearVelocity(const btVector3& velocity)
|
||||
{
|
||||
m_walkDirection = velocity;
|
||||
|
||||
// HACK: if we are moving in the direction of the up, treat it as a jump :(
|
||||
if (m_walkDirection.length2() > 0)
|
||||
{
|
||||
btVector3 w = velocity.normalized();
|
||||
btScalar c = w.dot(m_up);
|
||||
if (c != 0)
|
||||
{
|
||||
//there is a component in walkdirection for vertical velocity
|
||||
btVector3 upComponent = m_up * (sinf(SIMD_HALF_PI - acosf(c)) * m_walkDirection.length());
|
||||
m_walkDirection -= upComponent;
|
||||
m_verticalVelocity = (c < 0.0f ? -1 : 1) * upComponent.length();
|
||||
|
||||
if (c > 0.0f)
|
||||
{
|
||||
m_wasJumping = true;
|
||||
m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_verticalVelocity = 0.0f;
|
||||
}
|
||||
|
||||
btVector3 btKinematicCharacterController::getLinearVelocity() const
|
||||
{
|
||||
return m_walkDirection + (m_verticalVelocity * m_up);
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::reset ( btCollisionWorld* collisionWorld )
|
||||
{
|
||||
m_verticalVelocity = 0.0;
|
||||
m_verticalOffset = 0.0;
|
||||
m_wasOnGround = false;
|
||||
m_wasJumping = false;
|
||||
m_walkDirection.setValue(0,0,0);
|
||||
m_velocityTimeInterval = 0.0;
|
||||
m_verticalVelocity = 0.0;
|
||||
m_verticalOffset = 0.0;
|
||||
m_wasOnGround = false;
|
||||
m_wasJumping = false;
|
||||
m_walkDirection.setValue(0,0,0);
|
||||
m_velocityTimeInterval = 0.0;
|
||||
|
||||
//clear pair cache
|
||||
btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache();
|
||||
while (cache->getOverlappingPairArray().size() > 0)
|
||||
{
|
||||
cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());
|
||||
}
|
||||
//clear pair cache
|
||||
btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache();
|
||||
while (cache->getOverlappingPairArray().size() > 0)
|
||||
{
|
||||
cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher());
|
||||
}
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::warp (const btVector3& origin)
|
||||
|
|
@ -606,62 +705,99 @@ void btKinematicCharacterController::warp (const btVector3& origin)
|
|||
|
||||
void btKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld)
|
||||
{
|
||||
|
||||
int numPenetrationLoops = 0;
|
||||
m_touchingContact = false;
|
||||
while (recoverFromPenetration (collisionWorld))
|
||||
{
|
||||
numPenetrationLoops++;
|
||||
m_touchingContact = true;
|
||||
if (numPenetrationLoops > 4)
|
||||
{
|
||||
//printf("character could not recover from penetration = %d\n", numPenetrationLoops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||
m_targetPosition = m_currentPosition;
|
||||
|
||||
m_currentOrientation = m_ghostObject->getWorldTransform().getRotation();
|
||||
m_targetOrientation = m_currentOrientation;
|
||||
// printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt)
|
||||
{
|
||||
// printf("playerStep(): ");
|
||||
// printf(" dt = %f", dt);
|
||||
|
||||
if (m_AngVel.length2() > 0.0f)
|
||||
{
|
||||
m_AngVel *= btPow(btScalar(1) - m_angularDamping, dt);
|
||||
}
|
||||
|
||||
// integrate for angular velocity
|
||||
if (m_AngVel.length2() > 0.0f)
|
||||
{
|
||||
btTransform xform;
|
||||
xform = m_ghostObject->getWorldTransform();
|
||||
|
||||
btQuaternion rot(m_AngVel.normalized(), m_AngVel.length() * dt);
|
||||
|
||||
btQuaternion orn = rot * xform.getRotation();
|
||||
|
||||
xform.setRotation(orn);
|
||||
m_ghostObject->setWorldTransform(xform);
|
||||
|
||||
m_currentPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||
m_targetPosition = m_currentPosition;
|
||||
m_currentOrientation = m_ghostObject->getWorldTransform().getRotation();
|
||||
m_targetOrientation = m_currentOrientation;
|
||||
}
|
||||
|
||||
// quick check...
|
||||
if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) {
|
||||
if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0)) {
|
||||
// printf("\n");
|
||||
return; // no motion
|
||||
}
|
||||
|
||||
m_wasOnGround = onGround();
|
||||
|
||||
//btVector3 lvel = m_walkDirection;
|
||||
btScalar c = 0.0f;
|
||||
|
||||
if (m_walkDirection.length2() > 0)
|
||||
{
|
||||
// apply damping
|
||||
m_walkDirection *= btPow(btScalar(1) - m_linearDamping, dt);
|
||||
}
|
||||
|
||||
m_verticalVelocity *= btPow(btScalar(1) - m_linearDamping, dt);
|
||||
|
||||
// Update fall velocity.
|
||||
m_verticalVelocity -= m_gravity * dt;
|
||||
if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
|
||||
if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
|
||||
{
|
||||
m_verticalVelocity = m_jumpSpeed;
|
||||
}
|
||||
if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
|
||||
if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
|
||||
{
|
||||
m_verticalVelocity = -btFabs(m_fallSpeed);
|
||||
}
|
||||
m_verticalOffset = m_verticalVelocity * dt;
|
||||
|
||||
|
||||
btTransform xform;
|
||||
xform = m_ghostObject->getWorldTransform ();
|
||||
xform = m_ghostObject->getWorldTransform();
|
||||
|
||||
// printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]);
|
||||
// printf("walkSpeed=%f\n",walkSpeed);
|
||||
|
||||
stepUp (collisionWorld);
|
||||
stepUp(collisionWorld);
|
||||
//todo: Experimenting with behavior of controller when it hits a ceiling..
|
||||
//bool hitUp = stepUp (collisionWorld);
|
||||
//if (hitUp)
|
||||
//{
|
||||
// m_verticalVelocity -= m_gravity * dt;
|
||||
// if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed)
|
||||
// {
|
||||
// m_verticalVelocity = m_jumpSpeed;
|
||||
// }
|
||||
// if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed))
|
||||
// {
|
||||
// m_verticalVelocity = -btFabs(m_fallSpeed);
|
||||
// }
|
||||
// m_verticalOffset = m_verticalVelocity * dt;
|
||||
|
||||
// xform = m_ghostObject->getWorldTransform();
|
||||
//}
|
||||
|
||||
if (m_useWalkDirection) {
|
||||
stepForwardAndStrafe (collisionWorld, m_walkDirection);
|
||||
} else {
|
||||
|
|
@ -681,10 +817,38 @@ void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWo
|
|||
}
|
||||
stepDown (collisionWorld, dt);
|
||||
|
||||
//todo: Experimenting with max jump height
|
||||
//if (m_wasJumping)
|
||||
//{
|
||||
// btScalar ds = m_currentPosition[m_upAxis] - m_jumpPosition[m_upAxis];
|
||||
// if (ds > m_maxJumpHeight)
|
||||
// {
|
||||
// // substract the overshoot
|
||||
// m_currentPosition[m_upAxis] -= ds - m_maxJumpHeight;
|
||||
|
||||
// // max height was reached, so potential energy is at max
|
||||
// // and kinematic energy is 0, thus velocity is 0.
|
||||
// if (m_verticalVelocity > 0.0)
|
||||
// m_verticalVelocity = 0.0;
|
||||
// }
|
||||
//}
|
||||
// printf("\n");
|
||||
|
||||
xform.setOrigin (m_currentPosition);
|
||||
m_ghostObject->setWorldTransform (xform);
|
||||
|
||||
int numPenetrationLoops = 0;
|
||||
m_touchingContact = false;
|
||||
while (recoverFromPenetration(collisionWorld))
|
||||
{
|
||||
numPenetrationLoops++;
|
||||
m_touchingContact = true;
|
||||
if (numPenetrationLoops > 4)
|
||||
{
|
||||
//printf("character could not recover from penetration = %d\n", numPenetrationLoops);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
|
||||
|
|
@ -695,6 +859,7 @@ void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed)
|
|||
void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed)
|
||||
{
|
||||
m_jumpSpeed = jumpSpeed;
|
||||
m_SetjumpSpeed = m_jumpSpeed;
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight)
|
||||
|
|
@ -707,14 +872,16 @@ bool btKinematicCharacterController::canJump () const
|
|||
return onGround();
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::jump ()
|
||||
void btKinematicCharacterController::jump(const btVector3& v)
|
||||
{
|
||||
if (!canJump())
|
||||
return;
|
||||
|
||||
m_jumpSpeed = v.length2() == 0 ? m_SetjumpSpeed : v.length();
|
||||
m_verticalVelocity = m_jumpSpeed;
|
||||
m_wasJumping = true;
|
||||
|
||||
m_jumpAxis = v.length2() == 0 ? m_up : v.normalized();
|
||||
|
||||
m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin();
|
||||
|
||||
#if 0
|
||||
currently no jumping.
|
||||
btTransform xform;
|
||||
|
|
@ -726,14 +893,16 @@ void btKinematicCharacterController::jump ()
|
|||
#endif
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setGravity(btScalar gravity)
|
||||
void btKinematicCharacterController::setGravity(const btVector3& gravity)
|
||||
{
|
||||
m_gravity = gravity;
|
||||
if (gravity.length2() > 0) setUpVector(-gravity);
|
||||
|
||||
m_gravity = gravity.length();
|
||||
}
|
||||
|
||||
btScalar btKinematicCharacterController::getGravity() const
|
||||
btVector3 btKinematicCharacterController::getGravity() const
|
||||
{
|
||||
return m_gravity;
|
||||
return -m_gravity * m_up;
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setMaxSlope(btScalar slopeRadians)
|
||||
|
|
@ -747,11 +916,25 @@ btScalar btKinematicCharacterController::getMaxSlope() const
|
|||
return m_maxSlopeRadians;
|
||||
}
|
||||
|
||||
bool btKinematicCharacterController::onGround () const
|
||||
void btKinematicCharacterController::setMaxPenetrationDepth(btScalar d)
|
||||
{
|
||||
return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0;
|
||||
m_maxPenetrationDepth = d;
|
||||
}
|
||||
|
||||
btScalar btKinematicCharacterController::getMaxPenetrationDepth() const
|
||||
{
|
||||
return m_maxPenetrationDepth;
|
||||
}
|
||||
|
||||
bool btKinematicCharacterController::onGround () const
|
||||
{
|
||||
return (fabs(m_verticalVelocity) < SIMD_EPSILON) && (fabs(m_verticalOffset) < SIMD_EPSILON);
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setStepHeight(btScalar h)
|
||||
{
|
||||
m_stepHeight = h;
|
||||
}
|
||||
|
||||
btVector3* btKinematicCharacterController::getUpAxisDirections()
|
||||
{
|
||||
|
|
@ -768,3 +951,49 @@ void btKinematicCharacterController::setUpInterpolate(bool value)
|
|||
{
|
||||
m_interpolateUp = value;
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setUp(const btVector3& up)
|
||||
{
|
||||
if (up.length2() > 0 && m_gravity > 0.0f)
|
||||
{
|
||||
setGravity(-m_gravity * up.normalized());
|
||||
return;
|
||||
}
|
||||
|
||||
setUpVector(up);
|
||||
}
|
||||
|
||||
void btKinematicCharacterController::setUpVector(const btVector3& up)
|
||||
{
|
||||
if (m_up == up)
|
||||
return;
|
||||
|
||||
btVector3 u = m_up;
|
||||
|
||||
if (up.length2() > 0)
|
||||
m_up = up.normalized();
|
||||
else
|
||||
m_up = btVector3(0.0, 0.0, 0.0);
|
||||
|
||||
if (!m_ghostObject) return;
|
||||
btQuaternion rot = getRotation(m_up, u);
|
||||
|
||||
//set orientation with new up
|
||||
btTransform xform;
|
||||
xform = m_ghostObject->getWorldTransform();
|
||||
btQuaternion orn = rot.inverse() * xform.getRotation();
|
||||
xform.setRotation(orn);
|
||||
m_ghostObject->setWorldTransform(xform);
|
||||
}
|
||||
|
||||
btQuaternion btKinematicCharacterController::getRotation(btVector3& v0, btVector3& v1) const
|
||||
{
|
||||
if (v0.length2() == 0.0f || v1.length2() == 0.0f)
|
||||
{
|
||||
btQuaternion q;
|
||||
return q;
|
||||
}
|
||||
|
||||
return shortestArcQuatNormalize2(v0, v1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,10 +43,12 @@ protected:
|
|||
btPairCachingGhostObject* m_ghostObject;
|
||||
btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast
|
||||
|
||||
btScalar m_maxPenetrationDepth;
|
||||
btScalar m_verticalVelocity;
|
||||
btScalar m_verticalOffset;
|
||||
btScalar m_fallSpeed;
|
||||
btScalar m_jumpSpeed;
|
||||
btScalar m_SetjumpSpeed;
|
||||
btScalar m_maxJumpHeight;
|
||||
btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value)
|
||||
btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization)
|
||||
|
|
@ -61,24 +63,34 @@ protected:
|
|||
///this is the desired walk direction, set by the user
|
||||
btVector3 m_walkDirection;
|
||||
btVector3 m_normalizedDirection;
|
||||
btVector3 m_AngVel;
|
||||
|
||||
btVector3 m_jumpPosition;
|
||||
|
||||
//some internal variables
|
||||
btVector3 m_currentPosition;
|
||||
btScalar m_currentStepOffset;
|
||||
btVector3 m_targetPosition;
|
||||
|
||||
btQuaternion m_currentOrientation;
|
||||
btQuaternion m_targetOrientation;
|
||||
|
||||
///keep track of the contact manifolds
|
||||
btManifoldArray m_manifoldArray;
|
||||
|
||||
bool m_touchingContact;
|
||||
btVector3 m_touchingNormal;
|
||||
|
||||
btScalar m_linearDamping;
|
||||
btScalar m_angularDamping;
|
||||
|
||||
bool m_wasOnGround;
|
||||
bool m_wasJumping;
|
||||
bool m_useGhostObjectSweepTest;
|
||||
bool m_useWalkDirection;
|
||||
btScalar m_velocityTimeInterval;
|
||||
int m_upAxis;
|
||||
btVector3 m_up;
|
||||
btVector3 m_jumpAxis;
|
||||
|
||||
static btVector3* getUpAxisDirections();
|
||||
bool m_interpolateUp;
|
||||
|
|
@ -94,11 +106,18 @@ protected:
|
|||
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);
|
||||
|
||||
virtual bool needsCollision(const btCollisionObject* body0, const btCollisionObject* body1);
|
||||
|
||||
void setUpVector(const btVector3& up);
|
||||
|
||||
btQuaternion getRotation(btVector3& v0, btVector3& v1) const;
|
||||
|
||||
public:
|
||||
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis = 1);
|
||||
btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up = btVector3(1.0,0.0,0.0));
|
||||
~btKinematicCharacterController ();
|
||||
|
||||
|
||||
|
|
@ -112,14 +131,9 @@ public:
|
|||
///btActionInterface interface
|
||||
void debugDraw(btIDebugDraw* debugDrawer);
|
||||
|
||||
void setUpAxis (int axis)
|
||||
{
|
||||
if (axis < 0)
|
||||
axis = 0;
|
||||
if (axis > 2)
|
||||
axis = 2;
|
||||
m_upAxis = axis;
|
||||
}
|
||||
void setUp(const btVector3& up);
|
||||
|
||||
const btVector3& getUp() { return m_up; }
|
||||
|
||||
/// This should probably be called setPositionIncrementPerSimulatorStep.
|
||||
/// This is neither a direction nor a velocity, but the amount to
|
||||
|
|
@ -136,27 +150,47 @@ public:
|
|||
virtual void setVelocityForTimeInterval(const btVector3& velocity,
|
||||
btScalar timeInterval);
|
||||
|
||||
virtual void setAngularVelocity(const btVector3& velocity);
|
||||
virtual const btVector3& getAngularVelocity() const;
|
||||
|
||||
virtual void setLinearVelocity(const btVector3& velocity);
|
||||
virtual btVector3 getLinearVelocity() const;
|
||||
|
||||
void setLinearDamping(btScalar d) { m_linearDamping = btClamped(d, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); }
|
||||
btScalar getLinearDamping() const { return m_linearDamping; }
|
||||
void setAngularDamping(btScalar d) { m_angularDamping = btClamped(d, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); }
|
||||
btScalar getAngularDamping() const { return m_angularDamping; }
|
||||
|
||||
void reset ( btCollisionWorld* collisionWorld );
|
||||
void warp (const btVector3& origin);
|
||||
|
||||
void preStep ( btCollisionWorld* collisionWorld);
|
||||
void playerStep ( btCollisionWorld* collisionWorld, btScalar dt);
|
||||
|
||||
void setStepHeight(btScalar h);
|
||||
btScalar getStepHeight() const { return m_stepHeight; }
|
||||
void setFallSpeed (btScalar fallSpeed);
|
||||
btScalar getFallSpeed() const { return m_fallSpeed; }
|
||||
void setJumpSpeed (btScalar jumpSpeed);
|
||||
btScalar getJumpSpeed() const { return m_jumpSpeed; }
|
||||
void setMaxJumpHeight (btScalar maxJumpHeight);
|
||||
bool canJump () const;
|
||||
|
||||
void jump ();
|
||||
void jump(const btVector3& v = btVector3());
|
||||
|
||||
void setGravity(btScalar gravity);
|
||||
btScalar getGravity() const;
|
||||
void applyImpulse(const btVector3& v) { jump(v); }
|
||||
|
||||
void setGravity(const btVector3& gravity);
|
||||
btVector3 getGravity() const;
|
||||
|
||||
/// The max slope determines the maximum angle that the controller can walk up.
|
||||
/// The slope angle is measured in radians.
|
||||
void setMaxSlope(btScalar slopeRadians);
|
||||
btScalar getMaxSlope() const;
|
||||
|
||||
void setMaxPenetrationDepth(btScalar d);
|
||||
btScalar getMaxPenetrationDepth() const;
|
||||
|
||||
btPairCachingGhostObject* getGhostObject();
|
||||
void setUseGhostSweepTest(bool useGhostObjectSweepTest)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ void btConeTwistConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const bt
|
|||
}
|
||||
// m_swingCorrection is always positive or 0
|
||||
info->m_lowerLimit[srow] = 0;
|
||||
info->m_upperLimit[srow] = SIMD_INFINITY;
|
||||
info->m_upperLimit[srow] = (m_bMotorEnabled && m_maxMotorImpulse >= 0.0f) ? m_maxMotorImpulse : SIMD_INFINITY;
|
||||
srow += info->rowskip;
|
||||
}
|
||||
}
|
||||
|
|
@ -540,8 +540,8 @@ void btConeTwistConstraint::calcAngleInfo()
|
|||
m_solveTwistLimit = false;
|
||||
m_solveSwingLimit = false;
|
||||
|
||||
btVector3 b1Axis1,b1Axis2,b1Axis3;
|
||||
btVector3 b2Axis1,b2Axis2;
|
||||
btVector3 b1Axis1(0,0,0),b1Axis2(0,0,0),b1Axis3(0,0,0);
|
||||
btVector3 b2Axis1(0,0,0),b2Axis2(0,0,0);
|
||||
|
||||
b1Axis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(0);
|
||||
b2Axis1 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(0);
|
||||
|
|
@ -778,8 +778,10 @@ void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTr
|
|||
target[2] = x * ivA[2] + y * jvA[2] + z * kvA[2];
|
||||
target.normalize();
|
||||
m_swingAxis = -ivB.cross(target);
|
||||
m_swingCorrection = m_swingAxis.length();
|
||||
m_swingAxis.normalize();
|
||||
m_swingCorrection = m_swingAxis.length();
|
||||
|
||||
if (!btFuzzyZero(m_swingCorrection))
|
||||
m_swingAxis.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -983,8 +985,8 @@ void btConeTwistConstraint::adjustSwingAxisToUseEllipseNormal(btVector3& vSwingA
|
|||
|
||||
void btConeTwistConstraint::setMotorTarget(const btQuaternion &q)
|
||||
{
|
||||
btTransform trACur = m_rbA.getCenterOfMassTransform();
|
||||
btTransform trBCur = m_rbB.getCenterOfMassTransform();
|
||||
//btTransform trACur = m_rbA.getCenterOfMassTransform();
|
||||
//btTransform trBCur = m_rbB.getCenterOfMassTransform();
|
||||
// btTransform trABCur = trBCur.inverse() * trACur;
|
||||
// btQuaternion qABCur = trABCur.getRotation();
|
||||
// btTransform trConstraintCur = (trBCur * m_rbBFrame).inverse() * (trACur * m_rbAFrame);
|
||||
|
|
|
|||
|
|
@ -170,6 +170,11 @@ public:
|
|||
{
|
||||
m_angularOnly = angularOnly;
|
||||
}
|
||||
|
||||
bool getAngularOnly() const
|
||||
{
|
||||
return m_angularOnly;
|
||||
}
|
||||
|
||||
void setLimit(int limitIndex,btScalar limitValue)
|
||||
{
|
||||
|
|
@ -196,6 +201,33 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
btScalar getLimit(int limitIndex) const
|
||||
{
|
||||
switch (limitIndex)
|
||||
{
|
||||
case 3:
|
||||
{
|
||||
return m_twistSpan;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
return m_swingSpan2;
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
return m_swingSpan1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
btAssert(0 && "Invalid limitIndex specified for btConeTwistConstraint");
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// setLimit(), a few notes:
|
||||
// _softness:
|
||||
// 0->1, recommend ~0.8->1.
|
||||
|
|
@ -218,8 +250,8 @@ public:
|
|||
m_relaxationFactor = _relaxationFactor;
|
||||
}
|
||||
|
||||
const btTransform& getAFrame() { return m_rbAFrame; };
|
||||
const btTransform& getBFrame() { return m_rbBFrame; };
|
||||
const btTransform& getAFrame() const { return m_rbAFrame; };
|
||||
const btTransform& getBFrame() const { return m_rbBFrame; };
|
||||
|
||||
inline int getSolveTwistLimit()
|
||||
{
|
||||
|
|
@ -239,27 +271,43 @@ public:
|
|||
void calcAngleInfo();
|
||||
void calcAngleInfo2(const btTransform& transA, const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB);
|
||||
|
||||
inline btScalar getSwingSpan1()
|
||||
inline btScalar getSwingSpan1() const
|
||||
{
|
||||
return m_swingSpan1;
|
||||
}
|
||||
inline btScalar getSwingSpan2()
|
||||
inline btScalar getSwingSpan2() const
|
||||
{
|
||||
return m_swingSpan2;
|
||||
}
|
||||
inline btScalar getTwistSpan()
|
||||
inline btScalar getTwistSpan() const
|
||||
{
|
||||
return m_twistSpan;
|
||||
}
|
||||
inline btScalar getTwistAngle()
|
||||
inline btScalar getLimitSoftness() const
|
||||
{
|
||||
return m_limitSoftness;
|
||||
}
|
||||
inline btScalar getBiasFactor() const
|
||||
{
|
||||
return m_biasFactor;
|
||||
}
|
||||
inline btScalar getRelaxationFactor() const
|
||||
{
|
||||
return m_relaxationFactor;
|
||||
}
|
||||
inline btScalar getTwistAngle() const
|
||||
{
|
||||
return m_twistAngle;
|
||||
}
|
||||
bool isPastSwingLimit() { return m_solveSwingLimit; }
|
||||
|
||||
btScalar getDamping() const { return m_damping; }
|
||||
void setDamping(btScalar damping) { m_damping = damping; }
|
||||
|
||||
void enableMotor(bool b) { m_bMotorEnabled = b; }
|
||||
bool isMotorEnabled() const { return m_bMotorEnabled; }
|
||||
btScalar getMaxMotorImpulse() const { return m_maxMotorImpulse; }
|
||||
bool isMaxMotorImpulseNormalized() const { return m_bNormalizedMotorStrength; }
|
||||
void setMaxMotorImpulse(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; m_bNormalizedMotorStrength = false; }
|
||||
void setMaxMotorImpulseNormalized(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; m_bNormalizedMotorStrength = true; }
|
||||
|
||||
|
|
@ -271,6 +319,7 @@ public:
|
|||
// note: if q violates the joint limits, the internal target is clamped to avoid conflicting impulses (very bad for stability)
|
||||
// note: don't forget to enableMotor()
|
||||
void setMotorTarget(const btQuaternion &q);
|
||||
const btQuaternion& getMotorTarget() const { return m_qTarget; }
|
||||
|
||||
// same as above, but q is the desired rotation of frameA wrt frameB in constraint space
|
||||
void setMotorTargetInConstraintSpace(const btQuaternion &q);
|
||||
|
|
@ -297,6 +346,11 @@ public:
|
|||
///return the local value of parameter
|
||||
virtual btScalar getParam(int num, int axis = -1) const;
|
||||
|
||||
int getFlags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ class btDispatcher;
|
|||
enum btConstraintSolverType
|
||||
{
|
||||
BT_SEQUENTIAL_IMPULSE_SOLVER=1,
|
||||
BT_MLCP_SOLVER=2
|
||||
BT_MLCP_SOLVER=2,
|
||||
BT_NNCG_SOLVER=4
|
||||
};
|
||||
|
||||
class btConstraintSolver
|
||||
|
|
|
|||
|
|
@ -155,8 +155,7 @@ void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1,
|
|||
body1.getCenterOfMassTransform().getBasis().transpose() * body1.getAngularVelocity(),
|
||||
body2.getLinearVelocity(),
|
||||
body2.getCenterOfMassTransform().getBasis().transpose() * body2.getAngularVelocity());
|
||||
btScalar a;
|
||||
a=jacDiagABInv;
|
||||
|
||||
|
||||
|
||||
rel_vel = normal.dot(vel);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ struct btContactSolverInfoData
|
|||
int m_minimumSolverBatchSize;
|
||||
btScalar m_maxGyroscopicForce;
|
||||
btScalar m_singleAxisRollingFrictionThreshold;
|
||||
|
||||
btScalar m_leastSquaresResidualThreshold;
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ struct btContactSolverInfo : public btContactSolverInfoData
|
|||
m_maxErrorReduction = btScalar(20.);
|
||||
m_numIterations = 10;
|
||||
m_erp = btScalar(0.2);
|
||||
m_erp2 = btScalar(0.8);
|
||||
m_erp2 = btScalar(0.2);
|
||||
m_globalCfm = btScalar(0.);
|
||||
m_sor = btScalar(1.);
|
||||
m_splitImpulse = true;
|
||||
|
|
@ -89,8 +89,9 @@ struct btContactSolverInfo : public btContactSolverInfoData
|
|||
m_solverMode = SOLVER_USE_WARMSTARTING | SOLVER_SIMD;// | SOLVER_RANDMIZE_ORDER;
|
||||
m_restingContactRestitutionThreshold = 2;//unused as of 2.81
|
||||
m_minimumSolverBatchSize = 128; //try to combine islands until the amount of constraints reaches this limit
|
||||
m_maxGyroscopicForce = 100.f; ///only used to clamp forces for bodies that have their BT_ENABLE_GYROPSCOPIC_FORCE flag set (using btRigidBody::setFlag)
|
||||
m_maxGyroscopicForce = 100.f; ///it is only used for 'explicit' version of gyroscopic force
|
||||
m_singleAxisRollingFrictionThreshold = 1e30f;///if the velocity is above this threshold, it will use a single constraint row (axis), otherwise 3 rows.
|
||||
m_leastSquaresResidualThreshold = 0.f;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -111,7 +112,7 @@ struct btContactSolverInfoDoubleData
|
|||
double m_splitImpulseTurnErp;
|
||||
double m_linearSlop;
|
||||
double m_warmstartingFactor;
|
||||
double m_maxGyroscopicForce;
|
||||
double m_maxGyroscopicForce;///it is only used for 'explicit' version of gyroscopic force
|
||||
double m_singleAxisRollingFrictionThreshold;
|
||||
|
||||
int m_numIterations;
|
||||
|
|
|
|||
|
|
@ -21,109 +21,17 @@ subject to the following restrictions:
|
|||
|
||||
|
||||
btFixedConstraint::btFixedConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& frameInA,const btTransform& frameInB)
|
||||
:btTypedConstraint(FIXED_CONSTRAINT_TYPE,rbA,rbB)
|
||||
:btGeneric6DofSpring2Constraint(rbA,rbB,frameInA,frameInB)
|
||||
{
|
||||
m_pivotInA = frameInA.getOrigin();
|
||||
m_pivotInB = frameInB.getOrigin();
|
||||
m_relTargetAB = frameInA.getRotation()*frameInB.getRotation().inverse();
|
||||
|
||||
setAngularLowerLimit(btVector3(0,0,0));
|
||||
setAngularUpperLimit(btVector3(0,0,0));
|
||||
setLinearLowerLimit(btVector3(0,0,0));
|
||||
setLinearUpperLimit(btVector3(0,0,0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
btFixedConstraint::~btFixedConstraint ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void btFixedConstraint::getInfo1 (btConstraintInfo1* info)
|
||||
{
|
||||
info->m_numConstraintRows = 6;
|
||||
info->nub = 6;
|
||||
}
|
||||
|
||||
void btFixedConstraint::getInfo2 (btConstraintInfo2* info)
|
||||
{
|
||||
//fix the 3 linear degrees of freedom
|
||||
|
||||
|
||||
const btVector3& worldPosA = m_rbA.getCenterOfMassTransform().getOrigin();
|
||||
const btMatrix3x3& worldOrnA = m_rbA.getCenterOfMassTransform().getBasis();
|
||||
const btVector3& worldPosB= m_rbB.getCenterOfMassTransform().getOrigin();
|
||||
const btMatrix3x3& worldOrnB = m_rbB.getCenterOfMassTransform().getBasis();
|
||||
|
||||
|
||||
info->m_J1linearAxis[0] = 1;
|
||||
info->m_J1linearAxis[info->rowskip+1] = 1;
|
||||
info->m_J1linearAxis[2*info->rowskip+2] = 1;
|
||||
|
||||
btVector3 a1 = worldOrnA*m_pivotInA;
|
||||
{
|
||||
btVector3* angular0 = (btVector3*)(info->m_J1angularAxis);
|
||||
btVector3* angular1 = (btVector3*)(info->m_J1angularAxis+info->rowskip);
|
||||
btVector3* angular2 = (btVector3*)(info->m_J1angularAxis+2*info->rowskip);
|
||||
btVector3 a1neg = -a1;
|
||||
a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2);
|
||||
}
|
||||
|
||||
if (info->m_J2linearAxis)
|
||||
{
|
||||
info->m_J2linearAxis[0] = -1;
|
||||
info->m_J2linearAxis[info->rowskip+1] = -1;
|
||||
info->m_J2linearAxis[2*info->rowskip+2] = -1;
|
||||
}
|
||||
|
||||
btVector3 a2 = worldOrnB*m_pivotInB;
|
||||
|
||||
{
|
||||
// btVector3 a2n = -a2;
|
||||
btVector3* angular0 = (btVector3*)(info->m_J2angularAxis);
|
||||
btVector3* angular1 = (btVector3*)(info->m_J2angularAxis+info->rowskip);
|
||||
btVector3* angular2 = (btVector3*)(info->m_J2angularAxis+2*info->rowskip);
|
||||
a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
|
||||
}
|
||||
|
||||
// set right hand side for the linear dofs
|
||||
btScalar k = info->fps * info->erp;
|
||||
|
||||
btVector3 linearError = k*(a2+worldPosB-a1-worldPosA);
|
||||
int j;
|
||||
for (j=0; j<3; j++)
|
||||
{
|
||||
|
||||
|
||||
|
||||
info->m_constraintError[j*info->rowskip] = linearError[j];
|
||||
//printf("info->m_constraintError[%d]=%f\n",j,info->m_constraintError[j]);
|
||||
}
|
||||
|
||||
//fix the 3 angular degrees of freedom
|
||||
|
||||
int start_row = 3;
|
||||
int s = info->rowskip;
|
||||
int start_index = start_row * s;
|
||||
|
||||
// 3 rows to make body rotations equal
|
||||
info->m_J1angularAxis[start_index] = 1;
|
||||
info->m_J1angularAxis[start_index + s + 1] = 1;
|
||||
info->m_J1angularAxis[start_index + s*2+2] = 1;
|
||||
if ( info->m_J2angularAxis)
|
||||
{
|
||||
info->m_J2angularAxis[start_index] = -1;
|
||||
info->m_J2angularAxis[start_index + s+1] = -1;
|
||||
info->m_J2angularAxis[start_index + s*2+2] = -1;
|
||||
}
|
||||
|
||||
// set right hand side for the angular dofs
|
||||
|
||||
btVector3 diff;
|
||||
btScalar angle;
|
||||
btMatrix3x3 mrelCur = worldOrnA *worldOrnB.inverse();
|
||||
btQuaternion qrelCur;
|
||||
mrelCur.getRotation(qrelCur);
|
||||
btTransformUtil::calculateDiffAxisAngleQuaternion(m_relTargetAB,qrelCur,diff,angle);
|
||||
diff*=-angle;
|
||||
for (j=0; j<3; j++)
|
||||
{
|
||||
info->m_constraintError[(3+j)*info->rowskip] = k * diff[j];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,34 +16,18 @@ subject to the following restrictions:
|
|||
#ifndef BT_FIXED_CONSTRAINT_H
|
||||
#define BT_FIXED_CONSTRAINT_H
|
||||
|
||||
#include "btTypedConstraint.h"
|
||||
#include "btGeneric6DofSpring2Constraint.h"
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) btFixedConstraint : public btTypedConstraint
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) btFixedConstraint : public btGeneric6DofSpring2Constraint
|
||||
{
|
||||
btVector3 m_pivotInA;
|
||||
btVector3 m_pivotInB;
|
||||
btQuaternion m_relTargetAB;
|
||||
|
||||
public:
|
||||
btFixedConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& frameInA,const btTransform& frameInB);
|
||||
|
||||
|
||||
virtual ~btFixedConstraint();
|
||||
|
||||
|
||||
virtual void getInfo1 (btConstraintInfo1* info);
|
||||
|
||||
virtual void getInfo2 (btConstraintInfo2* info);
|
||||
|
||||
virtual void setParam(int num, btScalar value, int axis = -1)
|
||||
{
|
||||
btAssert(0);
|
||||
}
|
||||
virtual btScalar getParam(int num, int axis = -1) const
|
||||
{
|
||||
btAssert(0);
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //BT_FIXED_CONSTRAINT_H
|
||||
|
|
|
|||
|
|
@ -111,14 +111,14 @@ public:
|
|||
|
||||
|
||||
//! Is limited
|
||||
bool isLimited()
|
||||
bool isLimited() const
|
||||
{
|
||||
if(m_loLimit > m_hiLimit) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Need apply correction
|
||||
bool needApplyTorques()
|
||||
bool needApplyTorques() const
|
||||
{
|
||||
if(m_currentLimit == 0 && m_enableMotor == false) return false;
|
||||
return true;
|
||||
|
|
@ -207,11 +207,11 @@ public:
|
|||
- limited means upper > lower
|
||||
- limitIndex: first 3 are linear, next 3 are angular
|
||||
*/
|
||||
inline bool isLimited(int limitIndex)
|
||||
inline bool isLimited(int limitIndex) const
|
||||
{
|
||||
return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
|
||||
}
|
||||
inline bool needApplyForce(int limitIndex)
|
||||
inline bool needApplyForce(int limitIndex) const
|
||||
{
|
||||
if(m_currentLimit[limitIndex] == 0 && m_enableMotor[limitIndex] == false) return false;
|
||||
return true;
|
||||
|
|
@ -457,7 +457,7 @@ public:
|
|||
m_linearLimits.m_lowerLimit = linearLower;
|
||||
}
|
||||
|
||||
void getLinearLowerLimit(btVector3& linearLower)
|
||||
void getLinearLowerLimit(btVector3& linearLower) const
|
||||
{
|
||||
linearLower = m_linearLimits.m_lowerLimit;
|
||||
}
|
||||
|
|
@ -467,7 +467,7 @@ public:
|
|||
m_linearLimits.m_upperLimit = linearUpper;
|
||||
}
|
||||
|
||||
void getLinearUpperLimit(btVector3& linearUpper)
|
||||
void getLinearUpperLimit(btVector3& linearUpper) const
|
||||
{
|
||||
linearUpper = m_linearLimits.m_upperLimit;
|
||||
}
|
||||
|
|
@ -478,7 +478,7 @@ public:
|
|||
m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]);
|
||||
}
|
||||
|
||||
void getAngularLowerLimit(btVector3& angularLower)
|
||||
void getAngularLowerLimit(btVector3& angularLower) const
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
angularLower[i] = m_angularLimits[i].m_loLimit;
|
||||
|
|
@ -490,7 +490,7 @@ public:
|
|||
m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]);
|
||||
}
|
||||
|
||||
void getAngularUpperLimit(btVector3& angularUpper)
|
||||
void getAngularUpperLimit(btVector3& angularUpper) const
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
angularUpper[i] = m_angularLimits[i].m_hiLimit;
|
||||
|
|
@ -532,7 +532,7 @@ public:
|
|||
- limited means upper > lower
|
||||
- limitIndex: first 3 are linear, next 3 are angular
|
||||
*/
|
||||
bool isLimited(int limitIndex)
|
||||
bool isLimited(int limitIndex) const
|
||||
{
|
||||
if(limitIndex<3)
|
||||
{
|
||||
|
|
@ -549,8 +549,11 @@ public:
|
|||
btConstraintInfo2 *info, int row, btVector3& ax1, int rotational, int rotAllowed = false);
|
||||
|
||||
// access for UseFrameOffset
|
||||
bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; }
|
||||
bool getUseFrameOffset() const { return m_useOffsetForConstraintFrame; }
|
||||
void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; }
|
||||
|
||||
bool getUseLinearReferenceFrameA() const { return m_useLinearReferenceFrameA; }
|
||||
void setUseLinearReferenceFrameA(bool linearReferenceFrameA) { m_useLinearReferenceFrameA = linearReferenceFrameA; }
|
||||
|
||||
///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
|
||||
///If no axis is provided, it uses the default axis for this constraint.
|
||||
|
|
@ -560,6 +563,10 @@ public:
|
|||
|
||||
void setAxis( const btVector3& axis1, const btVector3& axis2);
|
||||
|
||||
virtual int getFlags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,674 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer
|
||||
Pros:
|
||||
- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled)
|
||||
- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring)
|
||||
- Servo motor functionality
|
||||
- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision)
|
||||
- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2)
|
||||
|
||||
Cons:
|
||||
- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation.
|
||||
- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.)
|
||||
*/
|
||||
|
||||
/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev
|
||||
/// Added support for generic constraint solver through getInfo1/getInfo2 methods
|
||||
|
||||
/*
|
||||
2007-09-09
|
||||
btGeneric6DofConstraint Refactored by Francisco Le?n
|
||||
email: projectileman@yahoo.com
|
||||
http://gimpact.sf.net
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BT_GENERIC_6DOF_CONSTRAINT2_H
|
||||
#define BT_GENERIC_6DOF_CONSTRAINT2_H
|
||||
|
||||
#include "LinearMath/btVector3.h"
|
||||
#include "btJacobianEntry.h"
|
||||
#include "btTypedConstraint.h"
|
||||
|
||||
class btRigidBody;
|
||||
|
||||
|
||||
#ifdef BT_USE_DOUBLE_PRECISION
|
||||
#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintDoubleData2
|
||||
#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintDoubleData2"
|
||||
#else
|
||||
#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintData
|
||||
#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintData"
|
||||
#endif //BT_USE_DOUBLE_PRECISION
|
||||
|
||||
enum RotateOrder
|
||||
{
|
||||
RO_XYZ=0,
|
||||
RO_XZY,
|
||||
RO_YXZ,
|
||||
RO_YZX,
|
||||
RO_ZXY,
|
||||
RO_ZYX
|
||||
};
|
||||
|
||||
class btRotationalLimitMotor2
|
||||
{
|
||||
public:
|
||||
// upper < lower means free
|
||||
// upper == lower means locked
|
||||
// upper > lower means limited
|
||||
btScalar m_loLimit;
|
||||
btScalar m_hiLimit;
|
||||
btScalar m_bounce;
|
||||
btScalar m_stopERP;
|
||||
btScalar m_stopCFM;
|
||||
btScalar m_motorERP;
|
||||
btScalar m_motorCFM;
|
||||
bool m_enableMotor;
|
||||
btScalar m_targetVelocity;
|
||||
btScalar m_maxMotorForce;
|
||||
bool m_servoMotor;
|
||||
btScalar m_servoTarget;
|
||||
bool m_enableSpring;
|
||||
btScalar m_springStiffness;
|
||||
bool m_springStiffnessLimited;
|
||||
btScalar m_springDamping;
|
||||
bool m_springDampingLimited;
|
||||
btScalar m_equilibriumPoint;
|
||||
|
||||
btScalar m_currentLimitError;
|
||||
btScalar m_currentLimitErrorHi;
|
||||
btScalar m_currentPosition;
|
||||
int m_currentLimit;
|
||||
|
||||
btRotationalLimitMotor2()
|
||||
{
|
||||
m_loLimit = 1.0f;
|
||||
m_hiLimit = -1.0f;
|
||||
m_bounce = 0.0f;
|
||||
m_stopERP = 0.2f;
|
||||
m_stopCFM = 0.f;
|
||||
m_motorERP = 0.9f;
|
||||
m_motorCFM = 0.f;
|
||||
m_enableMotor = false;
|
||||
m_targetVelocity = 0;
|
||||
m_maxMotorForce = 0.1f;
|
||||
m_servoMotor = false;
|
||||
m_servoTarget = 0;
|
||||
m_enableSpring = false;
|
||||
m_springStiffness = 0;
|
||||
m_springStiffnessLimited = false;
|
||||
m_springDamping = 0;
|
||||
m_springDampingLimited = false;
|
||||
m_equilibriumPoint = 0;
|
||||
|
||||
m_currentLimitError = 0;
|
||||
m_currentLimitErrorHi = 0;
|
||||
m_currentPosition = 0;
|
||||
m_currentLimit = 0;
|
||||
}
|
||||
|
||||
btRotationalLimitMotor2(const btRotationalLimitMotor2 & limot)
|
||||
{
|
||||
m_loLimit = limot.m_loLimit;
|
||||
m_hiLimit = limot.m_hiLimit;
|
||||
m_bounce = limot.m_bounce;
|
||||
m_stopERP = limot.m_stopERP;
|
||||
m_stopCFM = limot.m_stopCFM;
|
||||
m_motorERP = limot.m_motorERP;
|
||||
m_motorCFM = limot.m_motorCFM;
|
||||
m_enableMotor = limot.m_enableMotor;
|
||||
m_targetVelocity = limot.m_targetVelocity;
|
||||
m_maxMotorForce = limot.m_maxMotorForce;
|
||||
m_servoMotor = limot.m_servoMotor;
|
||||
m_servoTarget = limot.m_servoTarget;
|
||||
m_enableSpring = limot.m_enableSpring;
|
||||
m_springStiffness = limot.m_springStiffness;
|
||||
m_springStiffnessLimited = limot.m_springStiffnessLimited;
|
||||
m_springDamping = limot.m_springDamping;
|
||||
m_springDampingLimited = limot.m_springDampingLimited;
|
||||
m_equilibriumPoint = limot.m_equilibriumPoint;
|
||||
|
||||
m_currentLimitError = limot.m_currentLimitError;
|
||||
m_currentLimitErrorHi = limot.m_currentLimitErrorHi;
|
||||
m_currentPosition = limot.m_currentPosition;
|
||||
m_currentLimit = limot.m_currentLimit;
|
||||
}
|
||||
|
||||
|
||||
bool isLimited()
|
||||
{
|
||||
if(m_loLimit > m_hiLimit) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void testLimitValue(btScalar test_value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class btTranslationalLimitMotor2
|
||||
{
|
||||
public:
|
||||
// upper < lower means free
|
||||
// upper == lower means locked
|
||||
// upper > lower means limited
|
||||
btVector3 m_lowerLimit;
|
||||
btVector3 m_upperLimit;
|
||||
btVector3 m_bounce;
|
||||
btVector3 m_stopERP;
|
||||
btVector3 m_stopCFM;
|
||||
btVector3 m_motorERP;
|
||||
btVector3 m_motorCFM;
|
||||
bool m_enableMotor[3];
|
||||
bool m_servoMotor[3];
|
||||
bool m_enableSpring[3];
|
||||
btVector3 m_servoTarget;
|
||||
btVector3 m_springStiffness;
|
||||
bool m_springStiffnessLimited[3];
|
||||
btVector3 m_springDamping;
|
||||
bool m_springDampingLimited[3];
|
||||
btVector3 m_equilibriumPoint;
|
||||
btVector3 m_targetVelocity;
|
||||
btVector3 m_maxMotorForce;
|
||||
|
||||
btVector3 m_currentLimitError;
|
||||
btVector3 m_currentLimitErrorHi;
|
||||
btVector3 m_currentLinearDiff;
|
||||
int m_currentLimit[3];
|
||||
|
||||
btTranslationalLimitMotor2()
|
||||
{
|
||||
m_lowerLimit .setValue(0.f , 0.f , 0.f );
|
||||
m_upperLimit .setValue(0.f , 0.f , 0.f );
|
||||
m_bounce .setValue(0.f , 0.f , 0.f );
|
||||
m_stopERP .setValue(0.2f, 0.2f, 0.2f);
|
||||
m_stopCFM .setValue(0.f , 0.f , 0.f );
|
||||
m_motorERP .setValue(0.9f, 0.9f, 0.9f);
|
||||
m_motorCFM .setValue(0.f , 0.f , 0.f );
|
||||
|
||||
m_currentLimitError .setValue(0.f , 0.f , 0.f );
|
||||
m_currentLimitErrorHi.setValue(0.f , 0.f , 0.f );
|
||||
m_currentLinearDiff .setValue(0.f , 0.f , 0.f );
|
||||
|
||||
for(int i=0; i < 3; i++)
|
||||
{
|
||||
m_enableMotor[i] = false;
|
||||
m_servoMotor[i] = false;
|
||||
m_enableSpring[i] = false;
|
||||
m_servoTarget[i] = btScalar(0.f);
|
||||
m_springStiffness[i] = btScalar(0.f);
|
||||
m_springStiffnessLimited[i] = false;
|
||||
m_springDamping[i] = btScalar(0.f);
|
||||
m_springDampingLimited[i] = false;
|
||||
m_equilibriumPoint[i] = btScalar(0.f);
|
||||
m_targetVelocity[i] = btScalar(0.f);
|
||||
m_maxMotorForce[i] = btScalar(0.f);
|
||||
|
||||
m_currentLimit[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
btTranslationalLimitMotor2(const btTranslationalLimitMotor2 & other )
|
||||
{
|
||||
m_lowerLimit = other.m_lowerLimit;
|
||||
m_upperLimit = other.m_upperLimit;
|
||||
m_bounce = other.m_bounce;
|
||||
m_stopERP = other.m_stopERP;
|
||||
m_stopCFM = other.m_stopCFM;
|
||||
m_motorERP = other.m_motorERP;
|
||||
m_motorCFM = other.m_motorCFM;
|
||||
|
||||
m_currentLimitError = other.m_currentLimitError;
|
||||
m_currentLimitErrorHi = other.m_currentLimitErrorHi;
|
||||
m_currentLinearDiff = other.m_currentLinearDiff;
|
||||
|
||||
for(int i=0; i < 3; i++)
|
||||
{
|
||||
m_enableMotor[i] = other.m_enableMotor[i];
|
||||
m_servoMotor[i] = other.m_servoMotor[i];
|
||||
m_enableSpring[i] = other.m_enableSpring[i];
|
||||
m_servoTarget[i] = other.m_servoTarget[i];
|
||||
m_springStiffness[i] = other.m_springStiffness[i];
|
||||
m_springStiffnessLimited[i] = other.m_springStiffnessLimited[i];
|
||||
m_springDamping[i] = other.m_springDamping[i];
|
||||
m_springDampingLimited[i] = other.m_springDampingLimited[i];
|
||||
m_equilibriumPoint[i] = other.m_equilibriumPoint[i];
|
||||
m_targetVelocity[i] = other.m_targetVelocity[i];
|
||||
m_maxMotorForce[i] = other.m_maxMotorForce[i];
|
||||
|
||||
m_currentLimit[i] = other.m_currentLimit[i];
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isLimited(int limitIndex)
|
||||
{
|
||||
return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
|
||||
}
|
||||
|
||||
void testLimitValue(int limitIndex, btScalar test_value);
|
||||
};
|
||||
|
||||
enum bt6DofFlags2
|
||||
{
|
||||
BT_6DOF_FLAGS_CFM_STOP2 = 1,
|
||||
BT_6DOF_FLAGS_ERP_STOP2 = 2,
|
||||
BT_6DOF_FLAGS_CFM_MOTO2 = 4,
|
||||
BT_6DOF_FLAGS_ERP_MOTO2 = 8
|
||||
};
|
||||
#define BT_6DOF_FLAGS_AXIS_SHIFT2 4 // bits per axis
|
||||
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) btGeneric6DofSpring2Constraint : public btTypedConstraint
|
||||
{
|
||||
protected:
|
||||
|
||||
btTransform m_frameInA;
|
||||
btTransform m_frameInB;
|
||||
|
||||
btJacobianEntry m_jacLinear[3];
|
||||
btJacobianEntry m_jacAng[3];
|
||||
|
||||
btTranslationalLimitMotor2 m_linearLimits;
|
||||
btRotationalLimitMotor2 m_angularLimits[3];
|
||||
|
||||
RotateOrder m_rotateOrder;
|
||||
|
||||
protected:
|
||||
|
||||
btTransform m_calculatedTransformA;
|
||||
btTransform m_calculatedTransformB;
|
||||
btVector3 m_calculatedAxisAngleDiff;
|
||||
btVector3 m_calculatedAxis[3];
|
||||
btVector3 m_calculatedLinearDiff;
|
||||
btScalar m_factA;
|
||||
btScalar m_factB;
|
||||
bool m_hasStaticBody;
|
||||
int m_flags;
|
||||
|
||||
btGeneric6DofSpring2Constraint& operator=(btGeneric6DofSpring2Constraint&)
|
||||
{
|
||||
btAssert(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
int setAngularLimits(btConstraintInfo2 *info, int row_offset,const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB);
|
||||
int setLinearLimits(btConstraintInfo2 *info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB);
|
||||
|
||||
void calculateLinearInfo();
|
||||
void calculateAngleInfo();
|
||||
void testAngularLimitMotor(int axis_index);
|
||||
|
||||
void calculateJacobi(btRotationalLimitMotor2* limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2* info, int srow, btVector3& ax1, int rotational, int rotAllowed);
|
||||
int get_limit_motor_info2(btRotationalLimitMotor2* limot,
|
||||
const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
|
||||
btConstraintInfo2* info, int row, btVector3& ax1, int rotational, int rotAllowed = false);
|
||||
|
||||
public:
|
||||
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ);
|
||||
btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ);
|
||||
|
||||
virtual void buildJacobian() {}
|
||||
virtual void getInfo1 (btConstraintInfo1* info);
|
||||
virtual void getInfo2 (btConstraintInfo2* info);
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const;
|
||||
|
||||
btRotationalLimitMotor2* getRotationalLimitMotor(int index) { return &m_angularLimits[index]; }
|
||||
btTranslationalLimitMotor2* getTranslationalLimitMotor() { return &m_linearLimits; }
|
||||
|
||||
// Calculates the global transform for the joint offset for body A an B, and also calculates the angle differences between the bodies.
|
||||
void calculateTransforms(const btTransform& transA,const btTransform& transB);
|
||||
void calculateTransforms();
|
||||
|
||||
// Gets the global transform of the offset for body A
|
||||
const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; }
|
||||
// Gets the global transform of the offset for body B
|
||||
const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; }
|
||||
|
||||
const btTransform & getFrameOffsetA() const { return m_frameInA; }
|
||||
const btTransform & getFrameOffsetB() const { return m_frameInB; }
|
||||
|
||||
btTransform & getFrameOffsetA() { return m_frameInA; }
|
||||
btTransform & getFrameOffsetB() { return m_frameInB; }
|
||||
|
||||
// Get the rotation axis in global coordinates ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously )
|
||||
btVector3 getAxis(int axis_index) const { return m_calculatedAxis[axis_index]; }
|
||||
|
||||
// Get the relative Euler angle ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously )
|
||||
btScalar getAngle(int axis_index) const { return m_calculatedAxisAngleDiff[axis_index]; }
|
||||
|
||||
// Get the relative position of the constraint pivot ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously )
|
||||
btScalar getRelativePivotPosition(int axis_index) const { return m_calculatedLinearDiff[axis_index]; }
|
||||
|
||||
void setFrames(const btTransform & frameA, const btTransform & frameB);
|
||||
|
||||
void setLinearLowerLimit(const btVector3& linearLower) { m_linearLimits.m_lowerLimit = linearLower; }
|
||||
void getLinearLowerLimit(btVector3& linearLower) { linearLower = m_linearLimits.m_lowerLimit; }
|
||||
void setLinearUpperLimit(const btVector3& linearUpper) { m_linearLimits.m_upperLimit = linearUpper; }
|
||||
void getLinearUpperLimit(btVector3& linearUpper) { linearUpper = m_linearLimits.m_upperLimit; }
|
||||
|
||||
void setAngularLowerLimit(const btVector3& angularLower)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]);
|
||||
}
|
||||
|
||||
void setAngularLowerLimitReversed(const btVector3& angularLower)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
m_angularLimits[i].m_hiLimit = btNormalizeAngle(-angularLower[i]);
|
||||
}
|
||||
|
||||
void getAngularLowerLimit(btVector3& angularLower)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
angularLower[i] = m_angularLimits[i].m_loLimit;
|
||||
}
|
||||
|
||||
void getAngularLowerLimitReversed(btVector3& angularLower)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
angularLower[i] = -m_angularLimits[i].m_hiLimit;
|
||||
}
|
||||
|
||||
void setAngularUpperLimit(const btVector3& angularUpper)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]);
|
||||
}
|
||||
|
||||
void setAngularUpperLimitReversed(const btVector3& angularUpper)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
m_angularLimits[i].m_loLimit = btNormalizeAngle(-angularUpper[i]);
|
||||
}
|
||||
|
||||
void getAngularUpperLimit(btVector3& angularUpper)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
angularUpper[i] = m_angularLimits[i].m_hiLimit;
|
||||
}
|
||||
|
||||
void getAngularUpperLimitReversed(btVector3& angularUpper)
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
angularUpper[i] = -m_angularLimits[i].m_loLimit;
|
||||
}
|
||||
|
||||
//first 3 are linear, next 3 are angular
|
||||
|
||||
void setLimit(int axis, btScalar lo, btScalar hi)
|
||||
{
|
||||
if(axis<3)
|
||||
{
|
||||
m_linearLimits.m_lowerLimit[axis] = lo;
|
||||
m_linearLimits.m_upperLimit[axis] = hi;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = btNormalizeAngle(lo);
|
||||
hi = btNormalizeAngle(hi);
|
||||
m_angularLimits[axis-3].m_loLimit = lo;
|
||||
m_angularLimits[axis-3].m_hiLimit = hi;
|
||||
}
|
||||
}
|
||||
|
||||
void setLimitReversed(int axis, btScalar lo, btScalar hi)
|
||||
{
|
||||
if(axis<3)
|
||||
{
|
||||
m_linearLimits.m_lowerLimit[axis] = lo;
|
||||
m_linearLimits.m_upperLimit[axis] = hi;
|
||||
}
|
||||
else
|
||||
{
|
||||
lo = btNormalizeAngle(lo);
|
||||
hi = btNormalizeAngle(hi);
|
||||
m_angularLimits[axis-3].m_hiLimit = -lo;
|
||||
m_angularLimits[axis-3].m_loLimit = -hi;
|
||||
}
|
||||
}
|
||||
|
||||
bool isLimited(int limitIndex)
|
||||
{
|
||||
if(limitIndex<3)
|
||||
{
|
||||
return m_linearLimits.isLimited(limitIndex);
|
||||
}
|
||||
return m_angularLimits[limitIndex-3].isLimited();
|
||||
}
|
||||
|
||||
void setRotationOrder(RotateOrder order) { m_rotateOrder = order; }
|
||||
RotateOrder getRotationOrder() { return m_rotateOrder; }
|
||||
|
||||
void setAxis( const btVector3& axis1, const btVector3& axis2);
|
||||
|
||||
void setBounce(int index, btScalar bounce);
|
||||
|
||||
void enableMotor(int index, bool onOff);
|
||||
void setServo(int index, bool onOff); // set the type of the motor (servo or not) (the motor has to be turned on for servo also)
|
||||
void setTargetVelocity(int index, btScalar velocity);
|
||||
void setServoTarget(int index, btScalar target);
|
||||
void setMaxMotorForce(int index, btScalar force);
|
||||
|
||||
void enableSpring(int index, bool onOff);
|
||||
void setStiffness(int index, btScalar stiffness, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the stiffness in necessary situations where otherwise the spring would move unrealistically too widely
|
||||
void setDamping(int index, btScalar damping, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the damping in necessary situations where otherwise the spring would blow up
|
||||
void setEquilibriumPoint(); // set the current constraint position/orientation as an equilibrium point for all DOF
|
||||
void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF
|
||||
void setEquilibriumPoint(int index, btScalar val);
|
||||
|
||||
//override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
|
||||
//If no axis is provided, it uses the default axis for this constraint.
|
||||
virtual void setParam(int num, btScalar value, int axis = -1);
|
||||
virtual btScalar getParam(int num, int axis = -1) const;
|
||||
|
||||
static btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
|
||||
static bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
|
||||
static bool matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz);
|
||||
static bool matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz);
|
||||
static bool matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz);
|
||||
static bool matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz);
|
||||
static bool matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz);
|
||||
};
|
||||
|
||||
|
||||
struct btGeneric6DofSpring2ConstraintData
|
||||
{
|
||||
btTypedConstraintData m_typeConstraintData;
|
||||
btTransformFloatData m_rbAFrame;
|
||||
btTransformFloatData m_rbBFrame;
|
||||
|
||||
btVector3FloatData m_linearUpperLimit;
|
||||
btVector3FloatData m_linearLowerLimit;
|
||||
btVector3FloatData m_linearBounce;
|
||||
btVector3FloatData m_linearStopERP;
|
||||
btVector3FloatData m_linearStopCFM;
|
||||
btVector3FloatData m_linearMotorERP;
|
||||
btVector3FloatData m_linearMotorCFM;
|
||||
btVector3FloatData m_linearTargetVelocity;
|
||||
btVector3FloatData m_linearMaxMotorForce;
|
||||
btVector3FloatData m_linearServoTarget;
|
||||
btVector3FloatData m_linearSpringStiffness;
|
||||
btVector3FloatData m_linearSpringDamping;
|
||||
btVector3FloatData m_linearEquilibriumPoint;
|
||||
char m_linearEnableMotor[4];
|
||||
char m_linearServoMotor[4];
|
||||
char m_linearEnableSpring[4];
|
||||
char m_linearSpringStiffnessLimited[4];
|
||||
char m_linearSpringDampingLimited[4];
|
||||
char m_padding1[4];
|
||||
|
||||
btVector3FloatData m_angularUpperLimit;
|
||||
btVector3FloatData m_angularLowerLimit;
|
||||
btVector3FloatData m_angularBounce;
|
||||
btVector3FloatData m_angularStopERP;
|
||||
btVector3FloatData m_angularStopCFM;
|
||||
btVector3FloatData m_angularMotorERP;
|
||||
btVector3FloatData m_angularMotorCFM;
|
||||
btVector3FloatData m_angularTargetVelocity;
|
||||
btVector3FloatData m_angularMaxMotorForce;
|
||||
btVector3FloatData m_angularServoTarget;
|
||||
btVector3FloatData m_angularSpringStiffness;
|
||||
btVector3FloatData m_angularSpringDamping;
|
||||
btVector3FloatData m_angularEquilibriumPoint;
|
||||
char m_angularEnableMotor[4];
|
||||
char m_angularServoMotor[4];
|
||||
char m_angularEnableSpring[4];
|
||||
char m_angularSpringStiffnessLimited[4];
|
||||
char m_angularSpringDampingLimited[4];
|
||||
|
||||
int m_rotateOrder;
|
||||
};
|
||||
|
||||
struct btGeneric6DofSpring2ConstraintDoubleData2
|
||||
{
|
||||
btTypedConstraintDoubleData m_typeConstraintData;
|
||||
btTransformDoubleData m_rbAFrame;
|
||||
btTransformDoubleData m_rbBFrame;
|
||||
|
||||
btVector3DoubleData m_linearUpperLimit;
|
||||
btVector3DoubleData m_linearLowerLimit;
|
||||
btVector3DoubleData m_linearBounce;
|
||||
btVector3DoubleData m_linearStopERP;
|
||||
btVector3DoubleData m_linearStopCFM;
|
||||
btVector3DoubleData m_linearMotorERP;
|
||||
btVector3DoubleData m_linearMotorCFM;
|
||||
btVector3DoubleData m_linearTargetVelocity;
|
||||
btVector3DoubleData m_linearMaxMotorForce;
|
||||
btVector3DoubleData m_linearServoTarget;
|
||||
btVector3DoubleData m_linearSpringStiffness;
|
||||
btVector3DoubleData m_linearSpringDamping;
|
||||
btVector3DoubleData m_linearEquilibriumPoint;
|
||||
char m_linearEnableMotor[4];
|
||||
char m_linearServoMotor[4];
|
||||
char m_linearEnableSpring[4];
|
||||
char m_linearSpringStiffnessLimited[4];
|
||||
char m_linearSpringDampingLimited[4];
|
||||
char m_padding1[4];
|
||||
|
||||
btVector3DoubleData m_angularUpperLimit;
|
||||
btVector3DoubleData m_angularLowerLimit;
|
||||
btVector3DoubleData m_angularBounce;
|
||||
btVector3DoubleData m_angularStopERP;
|
||||
btVector3DoubleData m_angularStopCFM;
|
||||
btVector3DoubleData m_angularMotorERP;
|
||||
btVector3DoubleData m_angularMotorCFM;
|
||||
btVector3DoubleData m_angularTargetVelocity;
|
||||
btVector3DoubleData m_angularMaxMotorForce;
|
||||
btVector3DoubleData m_angularServoTarget;
|
||||
btVector3DoubleData m_angularSpringStiffness;
|
||||
btVector3DoubleData m_angularSpringDamping;
|
||||
btVector3DoubleData m_angularEquilibriumPoint;
|
||||
char m_angularEnableMotor[4];
|
||||
char m_angularServoMotor[4];
|
||||
char m_angularEnableSpring[4];
|
||||
char m_angularSpringStiffnessLimited[4];
|
||||
char m_angularSpringDampingLimited[4];
|
||||
|
||||
int m_rotateOrder;
|
||||
};
|
||||
|
||||
SIMD_FORCE_INLINE int btGeneric6DofSpring2Constraint::calculateSerializeBufferSize() const
|
||||
{
|
||||
return sizeof(btGeneric6DofSpring2ConstraintData2);
|
||||
}
|
||||
|
||||
SIMD_FORCE_INLINE const char* btGeneric6DofSpring2Constraint::serialize(void* dataBuffer, btSerializer* serializer) const
|
||||
{
|
||||
btGeneric6DofSpring2ConstraintData2* dof = (btGeneric6DofSpring2ConstraintData2*)dataBuffer;
|
||||
btTypedConstraint::serialize(&dof->m_typeConstraintData,serializer);
|
||||
|
||||
m_frameInA.serialize(dof->m_rbAFrame);
|
||||
m_frameInB.serialize(dof->m_rbBFrame);
|
||||
|
||||
int i;
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
dof->m_angularLowerLimit.m_floats[i] = m_angularLimits[i].m_loLimit;
|
||||
dof->m_angularUpperLimit.m_floats[i] = m_angularLimits[i].m_hiLimit;
|
||||
dof->m_angularBounce.m_floats[i] = m_angularLimits[i].m_bounce;
|
||||
dof->m_angularStopERP.m_floats[i] = m_angularLimits[i].m_stopERP;
|
||||
dof->m_angularStopCFM.m_floats[i] = m_angularLimits[i].m_stopCFM;
|
||||
dof->m_angularMotorERP.m_floats[i] = m_angularLimits[i].m_motorERP;
|
||||
dof->m_angularMotorCFM.m_floats[i] = m_angularLimits[i].m_motorCFM;
|
||||
dof->m_angularTargetVelocity.m_floats[i] = m_angularLimits[i].m_targetVelocity;
|
||||
dof->m_angularMaxMotorForce.m_floats[i] = m_angularLimits[i].m_maxMotorForce;
|
||||
dof->m_angularServoTarget.m_floats[i] = m_angularLimits[i].m_servoTarget;
|
||||
dof->m_angularSpringStiffness.m_floats[i] = m_angularLimits[i].m_springStiffness;
|
||||
dof->m_angularSpringDamping.m_floats[i] = m_angularLimits[i].m_springDamping;
|
||||
dof->m_angularEquilibriumPoint.m_floats[i] = m_angularLimits[i].m_equilibriumPoint;
|
||||
}
|
||||
dof->m_angularLowerLimit.m_floats[3] = 0;
|
||||
dof->m_angularUpperLimit.m_floats[3] = 0;
|
||||
dof->m_angularBounce.m_floats[3] = 0;
|
||||
dof->m_angularStopERP.m_floats[3] = 0;
|
||||
dof->m_angularStopCFM.m_floats[3] = 0;
|
||||
dof->m_angularMotorERP.m_floats[3] = 0;
|
||||
dof->m_angularMotorCFM.m_floats[3] = 0;
|
||||
dof->m_angularTargetVelocity.m_floats[3] = 0;
|
||||
dof->m_angularMaxMotorForce.m_floats[3] = 0;
|
||||
dof->m_angularServoTarget.m_floats[3] = 0;
|
||||
dof->m_angularSpringStiffness.m_floats[3] = 0;
|
||||
dof->m_angularSpringDamping.m_floats[3] = 0;
|
||||
dof->m_angularEquilibriumPoint.m_floats[3] = 0;
|
||||
for (i=0;i<4;i++)
|
||||
{
|
||||
dof->m_angularEnableMotor[i] = i < 3 ? ( m_angularLimits[i].m_enableMotor ? 1 : 0 ) : 0;
|
||||
dof->m_angularServoMotor[i] = i < 3 ? ( m_angularLimits[i].m_servoMotor ? 1 : 0 ) : 0;
|
||||
dof->m_angularEnableSpring[i] = i < 3 ? ( m_angularLimits[i].m_enableSpring ? 1 : 0 ) : 0;
|
||||
dof->m_angularSpringStiffnessLimited[i] = i < 3 ? ( m_angularLimits[i].m_springStiffnessLimited ? 1 : 0 ) : 0;
|
||||
dof->m_angularSpringDampingLimited[i] = i < 3 ? ( m_angularLimits[i].m_springDampingLimited ? 1 : 0 ) : 0;
|
||||
}
|
||||
|
||||
m_linearLimits.m_lowerLimit.serialize( dof->m_linearLowerLimit );
|
||||
m_linearLimits.m_upperLimit.serialize( dof->m_linearUpperLimit );
|
||||
m_linearLimits.m_bounce.serialize( dof->m_linearBounce );
|
||||
m_linearLimits.m_stopERP.serialize( dof->m_linearStopERP );
|
||||
m_linearLimits.m_stopCFM.serialize( dof->m_linearStopCFM );
|
||||
m_linearLimits.m_motorERP.serialize( dof->m_linearMotorERP );
|
||||
m_linearLimits.m_motorCFM.serialize( dof->m_linearMotorCFM );
|
||||
m_linearLimits.m_targetVelocity.serialize( dof->m_linearTargetVelocity );
|
||||
m_linearLimits.m_maxMotorForce.serialize( dof->m_linearMaxMotorForce );
|
||||
m_linearLimits.m_servoTarget.serialize( dof->m_linearServoTarget );
|
||||
m_linearLimits.m_springStiffness.serialize( dof->m_linearSpringStiffness );
|
||||
m_linearLimits.m_springDamping.serialize( dof->m_linearSpringDamping );
|
||||
m_linearLimits.m_equilibriumPoint.serialize( dof->m_linearEquilibriumPoint );
|
||||
for (i=0;i<4;i++)
|
||||
{
|
||||
dof->m_linearEnableMotor[i] = i < 3 ? ( m_linearLimits.m_enableMotor[i] ? 1 : 0 ) : 0;
|
||||
dof->m_linearServoMotor[i] = i < 3 ? ( m_linearLimits.m_servoMotor[i] ? 1 : 0 ) : 0;
|
||||
dof->m_linearEnableSpring[i] = i < 3 ? ( m_linearLimits.m_enableSpring[i] ? 1 : 0 ) : 0;
|
||||
dof->m_linearSpringStiffnessLimited[i] = i < 3 ? ( m_linearLimits.m_springStiffnessLimited[i] ? 1 : 0 ) : 0;
|
||||
dof->m_linearSpringDampingLimited[i] = i < 3 ? ( m_linearLimits.m_springDampingLimited[i] ? 1 : 0 ) : 0;
|
||||
}
|
||||
|
||||
dof->m_rotateOrder = m_rotateOrder;
|
||||
|
||||
return btGeneric6DofSpring2ConstraintDataName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //BT_GENERIC_6DOF_CONSTRAINT_H
|
||||
|
|
@ -63,6 +63,26 @@ public:
|
|||
void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF
|
||||
void setEquilibriumPoint(int index, btScalar val);
|
||||
|
||||
bool isSpringEnabled(int index) const
|
||||
{
|
||||
return m_springEnabled[index];
|
||||
}
|
||||
|
||||
btScalar getStiffness(int index) const
|
||||
{
|
||||
return m_springStiffness[index];
|
||||
}
|
||||
|
||||
btScalar getDamping(int index) const
|
||||
{
|
||||
return m_springDamping[index];
|
||||
}
|
||||
|
||||
btScalar getEquilibriumPoint(int index) const
|
||||
{
|
||||
return m_equilibriumPoint[index];
|
||||
}
|
||||
|
||||
virtual void setAxis( const btVector3& axis1, const btVector3& axis2);
|
||||
|
||||
virtual void getInfo2 (btConstraintInfo2* info);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ subject to the following restrictions:
|
|||
// anchor, axis1 and axis2 are in world coordinate system
|
||||
// axis1 must be orthogonal to axis2
|
||||
btHinge2Constraint::btHinge2Constraint(btRigidBody& rbA, btRigidBody& rbB, btVector3& anchor, btVector3& axis1, btVector3& axis2)
|
||||
: btGeneric6DofSpringConstraint(rbA, rbB, btTransform::getIdentity(), btTransform::getIdentity(), true),
|
||||
: btGeneric6DofSpring2Constraint(rbA, rbB, btTransform::getIdentity(), btTransform::getIdentity(),RO_XYZ),
|
||||
m_anchor(anchor),
|
||||
m_axis1(axis1),
|
||||
m_axis2(axis2)
|
||||
|
|
@ -59,7 +59,7 @@ btHinge2Constraint::btHinge2Constraint(btRigidBody& rbA, btRigidBody& rbB, btVec
|
|||
setAngularUpperLimit(btVector3(-1.f, 0.f, SIMD_HALF_PI * 0.5f));
|
||||
// enable suspension
|
||||
enableSpring(2, true);
|
||||
setStiffness(2, SIMD_PI * SIMD_PI * 4.f); // period 1 sec for 1 kilogramm weel :-)
|
||||
setStiffness(2, SIMD_PI * SIMD_PI * 4.f);
|
||||
setDamping(2, 0.01f);
|
||||
setEquilibriumPoint();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ subject to the following restrictions:
|
|||
|
||||
#include "LinearMath/btVector3.h"
|
||||
#include "btTypedConstraint.h"
|
||||
#include "btGeneric6DofSpringConstraint.h"
|
||||
#include "btGeneric6DofSpring2Constraint.h"
|
||||
|
||||
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ subject to the following restrictions:
|
|||
// 2 rotational degrees of freedom, similar to Euler rotations around Z (axis 1) and X (axis 2)
|
||||
// 1 translational (along axis Z) with suspension spring
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) btHinge2Constraint : public btGeneric6DofSpringConstraint
|
||||
ATTRIBUTE_ALIGNED16(class) btHinge2Constraint : public btGeneric6DofSpring2Constraint
|
||||
{
|
||||
protected:
|
||||
btVector3 m_anchor;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,11 @@ btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const bt
|
|||
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
|
||||
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
|
||||
m_useReferenceFrameA(useReferenceFrameA),
|
||||
m_flags(0)
|
||||
m_flags(0),
|
||||
m_normalCFM(0),
|
||||
m_normalERP(0),
|
||||
m_stopCFM(0),
|
||||
m_stopERP(0)
|
||||
{
|
||||
m_rbAFrame.getOrigin() = pivotInA;
|
||||
|
||||
|
|
@ -101,7 +105,11 @@ m_angularOnly(false), m_enableAngularMotor(false),
|
|||
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
|
||||
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
|
||||
m_useReferenceFrameA(useReferenceFrameA),
|
||||
m_flags(0)
|
||||
m_flags(0),
|
||||
m_normalCFM(0),
|
||||
m_normalERP(0),
|
||||
m_stopCFM(0),
|
||||
m_stopERP(0)
|
||||
{
|
||||
|
||||
// since no frame is given, assume this to be zero angle and just pick rb transform axis
|
||||
|
|
@ -151,7 +159,11 @@ m_enableAngularMotor(false),
|
|||
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
|
||||
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
|
||||
m_useReferenceFrameA(useReferenceFrameA),
|
||||
m_flags(0)
|
||||
m_flags(0),
|
||||
m_normalCFM(0),
|
||||
m_normalERP(0),
|
||||
m_stopCFM(0),
|
||||
m_stopERP(0)
|
||||
{
|
||||
#ifndef _BT_USE_CENTER_LIMIT_
|
||||
//start with free
|
||||
|
|
@ -177,7 +189,11 @@ m_enableAngularMotor(false),
|
|||
m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER),
|
||||
m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET),
|
||||
m_useReferenceFrameA(useReferenceFrameA),
|
||||
m_flags(0)
|
||||
m_flags(0),
|
||||
m_normalCFM(0),
|
||||
m_normalERP(0),
|
||||
m_stopCFM(0),
|
||||
m_stopERP(0)
|
||||
{
|
||||
///not providing rigidbody B means implicitly using worldspace for body B
|
||||
|
||||
|
|
@ -285,8 +301,60 @@ void btHingeConstraint::buildJacobian()
|
|||
#endif //__SPU__
|
||||
|
||||
|
||||
static inline btScalar btNormalizeAnglePositive(btScalar angle)
|
||||
{
|
||||
return btFmod(btFmod(angle, btScalar(2.0*SIMD_PI)) + btScalar(2.0*SIMD_PI), btScalar(2.0*SIMD_PI));
|
||||
}
|
||||
|
||||
|
||||
|
||||
static btScalar btShortestAngularDistance(btScalar accAngle, btScalar curAngle)
|
||||
{
|
||||
btScalar result = btNormalizeAngle(btNormalizeAnglePositive(btNormalizeAnglePositive(curAngle) -
|
||||
btNormalizeAnglePositive(accAngle)));
|
||||
return result;
|
||||
}
|
||||
|
||||
static btScalar btShortestAngleUpdate(btScalar accAngle, btScalar curAngle)
|
||||
{
|
||||
btScalar tol(0.3);
|
||||
btScalar result = btShortestAngularDistance(accAngle, curAngle);
|
||||
|
||||
if (btFabs(result) > tol)
|
||||
return curAngle;
|
||||
else
|
||||
return accAngle + result;
|
||||
|
||||
return curAngle;
|
||||
}
|
||||
|
||||
|
||||
btScalar btHingeAccumulatedAngleConstraint::getAccumulatedHingeAngle()
|
||||
{
|
||||
btScalar hingeAngle = getHingeAngle();
|
||||
m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,hingeAngle);
|
||||
return m_accumulatedAngle;
|
||||
}
|
||||
void btHingeAccumulatedAngleConstraint::setAccumulatedHingeAngle(btScalar accAngle)
|
||||
{
|
||||
m_accumulatedAngle = accAngle;
|
||||
}
|
||||
|
||||
void btHingeAccumulatedAngleConstraint::getInfo1(btConstraintInfo1* info)
|
||||
{
|
||||
//update m_accumulatedAngle
|
||||
btScalar curHingeAngle = getHingeAngle();
|
||||
m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,curHingeAngle);
|
||||
|
||||
btHingeConstraint::getInfo1(info);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void btHingeConstraint::getInfo1(btConstraintInfo1* info)
|
||||
{
|
||||
|
||||
|
||||
if (m_useSolveConstraintObsolete)
|
||||
{
|
||||
info->m_numConstraintRows = 0;
|
||||
|
|
@ -413,7 +481,9 @@ void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransf
|
|||
a2.getSkewSymmetricMatrix(angular0,angular1,angular2);
|
||||
}
|
||||
// linear RHS
|
||||
btScalar k = info->fps * info->erp;
|
||||
btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM) ? m_normalERP : info->erp;
|
||||
|
||||
btScalar k = info->fps * normalErp;
|
||||
if (!m_angularOnly)
|
||||
{
|
||||
for(i = 0; i < 3; i++)
|
||||
|
|
@ -510,7 +580,7 @@ void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransf
|
|||
powered = 0;
|
||||
}
|
||||
info->m_constraintError[srow] = btScalar(0.0f);
|
||||
btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp;
|
||||
btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp;
|
||||
if(powered)
|
||||
{
|
||||
if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
|
||||
|
|
@ -606,6 +676,8 @@ void btHingeConstraint::updateRHS(btScalar timeStep)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
btScalar btHingeConstraint::getHingeAngle()
|
||||
{
|
||||
return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
|
||||
|
|
@ -798,7 +870,8 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info
|
|||
for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i];
|
||||
for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i];
|
||||
|
||||
btScalar k = info->fps * info->erp;
|
||||
btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM)? m_normalERP : info->erp;
|
||||
btScalar k = info->fps * normalErp;
|
||||
|
||||
if (!m_angularOnly)
|
||||
{
|
||||
|
|
@ -856,7 +929,8 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info
|
|||
// angular_velocity = (erp*fps) * (ax1 x ax2)
|
||||
// ax1 x ax2 is in the plane space of ax1, so we project the angular
|
||||
// velocity to p and q to find the right hand side.
|
||||
k = info->fps * info->erp;
|
||||
k = info->fps * normalErp;//??
|
||||
|
||||
btVector3 u = ax1A.cross(ax1B);
|
||||
info->m_constraintError[s3] = k * u.dot(p);
|
||||
info->m_constraintError[s4] = k * u.dot(q);
|
||||
|
|
@ -901,7 +975,7 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info
|
|||
powered = 0;
|
||||
}
|
||||
info->m_constraintError[srow] = btScalar(0.0f);
|
||||
btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp;
|
||||
btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp;
|
||||
if(powered)
|
||||
{
|
||||
if(m_flags & BT_HINGE_FLAGS_CFM_NORM)
|
||||
|
|
@ -1002,6 +1076,10 @@ void btHingeConstraint::setParam(int num, btScalar value, int axis)
|
|||
m_normalCFM = value;
|
||||
m_flags |= BT_HINGE_FLAGS_CFM_NORM;
|
||||
break;
|
||||
case BT_CONSTRAINT_ERP:
|
||||
m_normalERP = value;
|
||||
m_flags |= BT_HINGE_FLAGS_ERP_NORM;
|
||||
break;
|
||||
default :
|
||||
btAssertConstrParams(0);
|
||||
}
|
||||
|
|
@ -1032,6 +1110,10 @@ btScalar btHingeConstraint::getParam(int num, int axis) const
|
|||
btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_NORM);
|
||||
retVal = m_normalCFM;
|
||||
break;
|
||||
case BT_CONSTRAINT_ERP:
|
||||
btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_NORM);
|
||||
retVal = m_normalERP;
|
||||
break;
|
||||
default :
|
||||
btAssertConstrParams(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ enum btHingeFlags
|
|||
{
|
||||
BT_HINGE_FLAGS_CFM_STOP = 1,
|
||||
BT_HINGE_FLAGS_ERP_STOP = 2,
|
||||
BT_HINGE_FLAGS_CFM_NORM = 4
|
||||
BT_HINGE_FLAGS_CFM_NORM = 4,
|
||||
BT_HINGE_FLAGS_ERP_NORM = 8
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -94,6 +95,7 @@ public:
|
|||
|
||||
int m_flags;
|
||||
btScalar m_normalCFM;
|
||||
btScalar m_normalERP;
|
||||
btScalar m_stopCFM;
|
||||
btScalar m_stopERP;
|
||||
|
||||
|
|
@ -175,6 +177,7 @@ public:
|
|||
// maintain a given angular target.
|
||||
void enableMotor(bool enableMotor) { m_enableAngularMotor = enableMotor; }
|
||||
void setMaxMotorImpulse(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; }
|
||||
void setMotorTargetVelocity(btScalar motorTargetVelocity) { m_motorTargetVelocity = motorTargetVelocity; }
|
||||
void setMotorTarget(const btQuaternion& qAinB, btScalar dt); // qAinB is rotation of body A wrt body B.
|
||||
void setMotorTarget(btScalar targetAngle, btScalar dt);
|
||||
|
||||
|
|
@ -191,6 +194,33 @@ public:
|
|||
m_relaxationFactor = _relaxationFactor;
|
||||
#endif
|
||||
}
|
||||
|
||||
btScalar getLimitSoftness() const
|
||||
{
|
||||
#ifdef _BT_USE_CENTER_LIMIT_
|
||||
return m_limit.getSoftness();
|
||||
#else
|
||||
return m_limitSoftness;
|
||||
#endif
|
||||
}
|
||||
|
||||
btScalar getLimitBiasFactor() const
|
||||
{
|
||||
#ifdef _BT_USE_CENTER_LIMIT_
|
||||
return m_limit.getBiasFactor();
|
||||
#else
|
||||
return m_biasFactor;
|
||||
#endif
|
||||
}
|
||||
|
||||
btScalar getLimitRelaxationFactor() const
|
||||
{
|
||||
#ifdef _BT_USE_CENTER_LIMIT_
|
||||
return m_limit.getRelaxationFactor();
|
||||
#else
|
||||
return m_relaxationFactor;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setAxis(btVector3& axisInA)
|
||||
{
|
||||
|
|
@ -217,6 +247,14 @@ public:
|
|||
|
||||
}
|
||||
|
||||
bool hasLimit() const {
|
||||
#ifdef _BT_USE_CENTER_LIMIT_
|
||||
return m_limit.getHalfRange() > 0;
|
||||
#else
|
||||
return m_lowerLimit <= m_upperLimit;
|
||||
#endif
|
||||
}
|
||||
|
||||
btScalar getLowerLimit() const
|
||||
{
|
||||
#ifdef _BT_USE_CENTER_LIMIT_
|
||||
|
|
@ -236,6 +274,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
///The getHingeAngle gives the hinge angle in range [-PI,PI]
|
||||
btScalar getHingeAngle();
|
||||
|
||||
btScalar getHingeAngle(const btTransform& transA,const btTransform& transB);
|
||||
|
|
@ -286,13 +325,20 @@ public:
|
|||
// access for UseFrameOffset
|
||||
bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; }
|
||||
void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; }
|
||||
|
||||
// access for UseReferenceFrameA
|
||||
bool getUseReferenceFrameA() const { return m_useReferenceFrameA; }
|
||||
void setUseReferenceFrameA(bool useReferenceFrameA) { m_useReferenceFrameA = useReferenceFrameA; }
|
||||
|
||||
///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
|
||||
///If no axis is provided, it uses the default axis for this constraint.
|
||||
virtual void setParam(int num, btScalar value, int axis = -1);
|
||||
///return the local value of parameter
|
||||
virtual btScalar getParam(int num, int axis = -1) const;
|
||||
|
||||
virtual int getFlags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
|
|
@ -326,6 +372,43 @@ struct btHingeConstraintDoubleData
|
|||
};
|
||||
#endif //BT_BACKWARDS_COMPATIBLE_SERIALIZATION
|
||||
|
||||
///The getAccumulatedHingeAngle returns the accumulated hinge angle, taking rotation across the -PI/PI boundary into account
|
||||
ATTRIBUTE_ALIGNED16(class) btHingeAccumulatedAngleConstraint : public btHingeConstraint
|
||||
{
|
||||
protected:
|
||||
btScalar m_accumulatedAngle;
|
||||
public:
|
||||
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btHingeAccumulatedAngleConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, const btVector3& axisInA,const btVector3& axisInB, bool useReferenceFrameA = false)
|
||||
:btHingeConstraint(rbA,rbB,pivotInA,pivotInB, axisInA,axisInB, useReferenceFrameA )
|
||||
{
|
||||
m_accumulatedAngle=getHingeAngle();
|
||||
}
|
||||
|
||||
btHingeAccumulatedAngleConstraint(btRigidBody& rbA,const btVector3& pivotInA,const btVector3& axisInA, bool useReferenceFrameA = false)
|
||||
:btHingeConstraint(rbA,pivotInA,axisInA, useReferenceFrameA)
|
||||
{
|
||||
m_accumulatedAngle=getHingeAngle();
|
||||
}
|
||||
|
||||
btHingeAccumulatedAngleConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA = false)
|
||||
:btHingeConstraint(rbA,rbB, rbAFrame, rbBFrame, useReferenceFrameA )
|
||||
{
|
||||
m_accumulatedAngle=getHingeAngle();
|
||||
}
|
||||
|
||||
btHingeAccumulatedAngleConstraint(btRigidBody& rbA,const btTransform& rbAFrame, bool useReferenceFrameA = false)
|
||||
:btHingeConstraint(rbA,rbAFrame, useReferenceFrameA )
|
||||
{
|
||||
m_accumulatedAngle=getHingeAngle();
|
||||
}
|
||||
btScalar getAccumulatedHingeAngle();
|
||||
void setAccumulatedHingeAngle(btScalar accAngle);
|
||||
virtual void getInfo1 (btConstraintInfo1* info);
|
||||
|
||||
};
|
||||
|
||||
struct btHingeConstraintFloatData
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "btNNCGConstraintSolver.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
btScalar btNNCGConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
|
||||
{
|
||||
btScalar val = btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup( bodies,numBodies,manifoldPtr, numManifolds, constraints,numConstraints,infoGlobal,debugDrawer);
|
||||
|
||||
m_pNC.resizeNoInitialize(m_tmpSolverNonContactConstraintPool.size());
|
||||
m_pC.resizeNoInitialize(m_tmpSolverContactConstraintPool.size());
|
||||
m_pCF.resizeNoInitialize(m_tmpSolverContactFrictionConstraintPool.size());
|
||||
m_pCRF.resizeNoInitialize(m_tmpSolverContactRollingFrictionConstraintPool.size());
|
||||
|
||||
m_deltafNC.resizeNoInitialize(m_tmpSolverNonContactConstraintPool.size());
|
||||
m_deltafC.resizeNoInitialize(m_tmpSolverContactConstraintPool.size());
|
||||
m_deltafCF.resizeNoInitialize(m_tmpSolverContactFrictionConstraintPool.size());
|
||||
m_deltafCRF.resizeNoInitialize(m_tmpSolverContactRollingFrictionConstraintPool.size());
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
btScalar btNNCGConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** /*bodies */,int /*numBodies*/,btPersistentManifold** /*manifoldPtr*/, int /*numManifolds*/,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* /*debugDrawer*/)
|
||||
{
|
||||
|
||||
int numNonContactPool = m_tmpSolverNonContactConstraintPool.size();
|
||||
int numConstraintPool = m_tmpSolverContactConstraintPool.size();
|
||||
int numFrictionPool = m_tmpSolverContactFrictionConstraintPool.size();
|
||||
|
||||
if (infoGlobal.m_solverMode & SOLVER_RANDMIZE_ORDER)
|
||||
{
|
||||
if (1) // uncomment this for a bit less random ((iteration & 7) == 0)
|
||||
{
|
||||
|
||||
for (int j=0; j<numNonContactPool; ++j) {
|
||||
int tmp = m_orderNonContactConstraintPool[j];
|
||||
int swapi = btRandInt2(j+1);
|
||||
m_orderNonContactConstraintPool[j] = m_orderNonContactConstraintPool[swapi];
|
||||
m_orderNonContactConstraintPool[swapi] = tmp;
|
||||
}
|
||||
|
||||
//contact/friction constraints are not solved more than
|
||||
if (iteration< infoGlobal.m_numIterations)
|
||||
{
|
||||
for (int j=0; j<numConstraintPool; ++j) {
|
||||
int tmp = m_orderTmpConstraintPool[j];
|
||||
int swapi = btRandInt2(j+1);
|
||||
m_orderTmpConstraintPool[j] = m_orderTmpConstraintPool[swapi];
|
||||
m_orderTmpConstraintPool[swapi] = tmp;
|
||||
}
|
||||
|
||||
for (int j=0; j<numFrictionPool; ++j) {
|
||||
int tmp = m_orderFrictionConstraintPool[j];
|
||||
int swapi = btRandInt2(j+1);
|
||||
m_orderFrictionConstraintPool[j] = m_orderFrictionConstraintPool[swapi];
|
||||
m_orderFrictionConstraintPool[swapi] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
btScalar deltaflengthsqr = 0;
|
||||
|
||||
if (infoGlobal.m_solverMode & SOLVER_SIMD)
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
|
||||
if (iteration < constraint.m_overrideNumSolverIterations)
|
||||
{
|
||||
btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint);
|
||||
m_deltafNC[j] = deltaf;
|
||||
deltaflengthsqr += deltaf * deltaf;
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
|
||||
if (iteration < constraint.m_overrideNumSolverIterations)
|
||||
{
|
||||
btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[constraint.m_solverBodyIdA],m_tmpSolverBodyPool[constraint.m_solverBodyIdB],constraint);
|
||||
m_deltafNC[j] = deltaf;
|
||||
deltaflengthsqr += deltaf * deltaf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (m_onlyForNoneContact)
|
||||
{
|
||||
if (iteration==0)
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = m_deltafNC[j];
|
||||
} else {
|
||||
// deltaflengthsqrprev can be 0 only if the solver solved the problem exactly in the previous iteration. In this case we should have quit, but mainly for debug reason with this 'hack' it is now allowed to continue the calculation
|
||||
btScalar beta = m_deltafLengthSqrPrev>0 ? deltaflengthsqr / m_deltafLengthSqrPrev : 2;
|
||||
if (beta>1)
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = 0;
|
||||
} else
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
|
||||
if (iteration < constraint.m_overrideNumSolverIterations)
|
||||
{
|
||||
btScalar additionaldeltaimpulse = beta * m_pNC[j];
|
||||
constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
|
||||
m_pNC[j] = beta * m_pNC[j] + m_deltafNC[j];
|
||||
btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
|
||||
btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
|
||||
const btSolverConstraint& c = constraint;
|
||||
body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
|
||||
body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_deltafLengthSqrPrev = deltaflengthsqr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (infoGlobal.m_solverMode & SOLVER_SIMD)
|
||||
{
|
||||
|
||||
if (iteration< infoGlobal.m_numIterations)
|
||||
{
|
||||
for (int j=0;j<numConstraints;j++)
|
||||
{
|
||||
if (constraints[j]->isEnabled())
|
||||
{
|
||||
int bodyAid = getOrInitSolverBody(constraints[j]->getRigidBodyA(),infoGlobal.m_timeStep);
|
||||
int bodyBid = getOrInitSolverBody(constraints[j]->getRigidBodyB(),infoGlobal.m_timeStep);
|
||||
btSolverBody& bodyA = m_tmpSolverBodyPool[bodyAid];
|
||||
btSolverBody& bodyB = m_tmpSolverBodyPool[bodyBid];
|
||||
constraints[j]->solveConstraintObsolete(bodyA,bodyB,infoGlobal.m_timeStep);
|
||||
}
|
||||
}
|
||||
|
||||
///solve all contact constraints using SIMD, if available
|
||||
if (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS)
|
||||
{
|
||||
int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
|
||||
int multiplier = (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)? 2 : 1;
|
||||
|
||||
for (int c=0;c<numPoolConstraints;c++)
|
||||
{
|
||||
btScalar totalImpulse =0;
|
||||
|
||||
{
|
||||
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[c]];
|
||||
btScalar deltaf = resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafC[c] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
totalImpulse = solveManifold.m_appliedImpulse;
|
||||
}
|
||||
bool applyFriction = true;
|
||||
if (applyFriction)
|
||||
{
|
||||
{
|
||||
|
||||
btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[c*multiplier]];
|
||||
|
||||
if (totalImpulse>btScalar(0))
|
||||
{
|
||||
solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
|
||||
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
|
||||
btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafCF[c*multiplier] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
} else {
|
||||
m_deltafCF[c*multiplier] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)
|
||||
{
|
||||
|
||||
btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[c*multiplier+1]];
|
||||
|
||||
if (totalImpulse>btScalar(0))
|
||||
{
|
||||
solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
|
||||
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
|
||||
btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafCF[c*multiplier+1] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
} else {
|
||||
m_deltafCF[c*multiplier+1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else//SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS
|
||||
{
|
||||
//solve the friction constraints after all contact constraints, don't interleave them
|
||||
int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
|
||||
int j;
|
||||
|
||||
for (j=0;j<numPoolConstraints;j++)
|
||||
{
|
||||
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
|
||||
//resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
btScalar deltaf = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafC[j] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///solve all friction constraints, using SIMD, if available
|
||||
|
||||
int numFrictionPoolConstraints = m_tmpSolverContactFrictionConstraintPool.size();
|
||||
for (j=0;j<numFrictionPoolConstraints;j++)
|
||||
{
|
||||
btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[j]];
|
||||
btScalar totalImpulse = m_tmpSolverContactConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse;
|
||||
|
||||
if (totalImpulse>btScalar(0))
|
||||
{
|
||||
solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
|
||||
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
|
||||
|
||||
//resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafCF[j] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
} else {
|
||||
m_deltafCF[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size();
|
||||
for (j=0;j<numRollingFrictionPoolConstraints;j++)
|
||||
{
|
||||
|
||||
btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[j];
|
||||
btScalar totalImpulse = m_tmpSolverContactConstraintPool[rollingFrictionConstraint.m_frictionIndex].m_appliedImpulse;
|
||||
if (totalImpulse>btScalar(0))
|
||||
{
|
||||
btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
|
||||
if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction)
|
||||
rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
|
||||
|
||||
rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
|
||||
rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
|
||||
|
||||
btScalar deltaf = resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint);
|
||||
m_deltafCRF[j] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
} else {
|
||||
m_deltafCRF[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} else
|
||||
{
|
||||
|
||||
if (iteration< infoGlobal.m_numIterations)
|
||||
{
|
||||
for (int j=0;j<numConstraints;j++)
|
||||
{
|
||||
if (constraints[j]->isEnabled())
|
||||
{
|
||||
int bodyAid = getOrInitSolverBody(constraints[j]->getRigidBodyA(),infoGlobal.m_timeStep);
|
||||
int bodyBid = getOrInitSolverBody(constraints[j]->getRigidBodyB(),infoGlobal.m_timeStep);
|
||||
btSolverBody& bodyA = m_tmpSolverBodyPool[bodyAid];
|
||||
btSolverBody& bodyB = m_tmpSolverBodyPool[bodyBid];
|
||||
constraints[j]->solveConstraintObsolete(bodyA,bodyB,infoGlobal.m_timeStep);
|
||||
}
|
||||
}
|
||||
///solve all contact constraints
|
||||
int numPoolConstraints = m_tmpSolverContactConstraintPool.size();
|
||||
for (int j=0;j<numPoolConstraints;j++)
|
||||
{
|
||||
const btSolverConstraint& solveManifold = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
|
||||
btScalar deltaf = resolveSingleConstraintRowLowerLimit(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafC[j] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
}
|
||||
///solve all friction constraints
|
||||
int numFrictionPoolConstraints = m_tmpSolverContactFrictionConstraintPool.size();
|
||||
for (int j=0;j<numFrictionPoolConstraints;j++)
|
||||
{
|
||||
btSolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[j]];
|
||||
btScalar totalImpulse = m_tmpSolverContactConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse;
|
||||
|
||||
if (totalImpulse>btScalar(0))
|
||||
{
|
||||
solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse);
|
||||
solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse;
|
||||
|
||||
btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold);
|
||||
m_deltafCF[j] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
} else {
|
||||
m_deltafCF[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size();
|
||||
for (int j=0;j<numRollingFrictionPoolConstraints;j++)
|
||||
{
|
||||
btSolverConstraint& rollingFrictionConstraint = m_tmpSolverContactRollingFrictionConstraintPool[j];
|
||||
btScalar totalImpulse = m_tmpSolverContactConstraintPool[rollingFrictionConstraint.m_frictionIndex].m_appliedImpulse;
|
||||
if (totalImpulse>btScalar(0))
|
||||
{
|
||||
btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse;
|
||||
if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction)
|
||||
rollingFrictionMagnitude = rollingFrictionConstraint.m_friction;
|
||||
|
||||
rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude;
|
||||
rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude;
|
||||
|
||||
btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint);
|
||||
m_deltafCRF[j] = deltaf;
|
||||
deltaflengthsqr += deltaf*deltaf;
|
||||
} else {
|
||||
m_deltafCRF[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (!m_onlyForNoneContact)
|
||||
{
|
||||
if (iteration==0)
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = m_deltafNC[j];
|
||||
for (int j=0;j<m_tmpSolverContactConstraintPool.size();j++) m_pC[j] = m_deltafC[j];
|
||||
for (int j=0;j<m_tmpSolverContactFrictionConstraintPool.size();j++) m_pCF[j] = m_deltafCF[j];
|
||||
if ( (infoGlobal.m_solverMode & SOLVER_SIMD) ==0 || (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) == 0 )
|
||||
{
|
||||
for (int j=0;j<m_tmpSolverContactRollingFrictionConstraintPool.size();j++) m_pCRF[j] = m_deltafCRF[j];
|
||||
}
|
||||
} else
|
||||
{
|
||||
// deltaflengthsqrprev can be 0 only if the solver solved the problem exactly in the previous iteration. In this case we should have quit, but mainly for debug reason with this 'hack' it is now allowed to continue the calculation
|
||||
btScalar beta = m_deltafLengthSqrPrev>0 ? deltaflengthsqr / m_deltafLengthSqrPrev : 2;
|
||||
if (beta>1) {
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++) m_pNC[j] = 0;
|
||||
for (int j=0;j<m_tmpSolverContactConstraintPool.size();j++) m_pC[j] = 0;
|
||||
for (int j=0;j<m_tmpSolverContactFrictionConstraintPool.size();j++) m_pCF[j] = 0;
|
||||
if ( (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) == 0 ) {
|
||||
for (int j=0;j<m_tmpSolverContactRollingFrictionConstraintPool.size();j++) m_pCRF[j] = 0;
|
||||
}
|
||||
} else {
|
||||
for (int j=0;j<m_tmpSolverNonContactConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverNonContactConstraintPool[m_orderNonContactConstraintPool[j]];
|
||||
if (iteration < constraint.m_overrideNumSolverIterations) {
|
||||
btScalar additionaldeltaimpulse = beta * m_pNC[j];
|
||||
constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
|
||||
m_pNC[j] = beta * m_pNC[j] + m_deltafNC[j];
|
||||
btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
|
||||
btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
|
||||
const btSolverConstraint& c = constraint;
|
||||
body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
|
||||
body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
|
||||
}
|
||||
}
|
||||
for (int j=0;j<m_tmpSolverContactConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverContactConstraintPool[m_orderTmpConstraintPool[j]];
|
||||
if (iteration< infoGlobal.m_numIterations) {
|
||||
btScalar additionaldeltaimpulse = beta * m_pC[j];
|
||||
constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
|
||||
m_pC[j] = beta * m_pC[j] + m_deltafC[j];
|
||||
btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
|
||||
btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
|
||||
const btSolverConstraint& c = constraint;
|
||||
body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
|
||||
body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
|
||||
}
|
||||
}
|
||||
for (int j=0;j<m_tmpSolverContactFrictionConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[j]];
|
||||
if (iteration< infoGlobal.m_numIterations) {
|
||||
btScalar additionaldeltaimpulse = beta * m_pCF[j];
|
||||
constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
|
||||
m_pCF[j] = beta * m_pCF[j] + m_deltafCF[j];
|
||||
btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
|
||||
btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
|
||||
const btSolverConstraint& c = constraint;
|
||||
body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
|
||||
body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
|
||||
}
|
||||
}
|
||||
if ( (infoGlobal.m_solverMode & SOLVER_SIMD) ==0 || (infoGlobal.m_solverMode & SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) == 0 ) {
|
||||
for (int j=0;j<m_tmpSolverContactRollingFrictionConstraintPool.size();j++)
|
||||
{
|
||||
btSolverConstraint& constraint = m_tmpSolverContactRollingFrictionConstraintPool[j];
|
||||
if (iteration< infoGlobal.m_numIterations) {
|
||||
btScalar additionaldeltaimpulse = beta * m_pCRF[j];
|
||||
constraint.m_appliedImpulse = btScalar(constraint.m_appliedImpulse) + additionaldeltaimpulse;
|
||||
m_pCRF[j] = beta * m_pCRF[j] + m_deltafCRF[j];
|
||||
btSolverBody& body1 = m_tmpSolverBodyPool[constraint.m_solverBodyIdA];
|
||||
btSolverBody& body2 = m_tmpSolverBodyPool[constraint.m_solverBodyIdB];
|
||||
const btSolverConstraint& c = constraint;
|
||||
body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,additionaldeltaimpulse);
|
||||
body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,additionaldeltaimpulse);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_deltafLengthSqrPrev = deltaflengthsqr;
|
||||
}
|
||||
|
||||
return deltaflengthsqr;
|
||||
}
|
||||
|
||||
btScalar btNNCGConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal)
|
||||
{
|
||||
m_pNC.resizeNoInitialize(0);
|
||||
m_pC.resizeNoInitialize(0);
|
||||
m_pCF.resizeNoInitialize(0);
|
||||
m_pCRF.resizeNoInitialize(0);
|
||||
|
||||
m_deltafNC.resizeNoInitialize(0);
|
||||
m_deltafC.resizeNoInitialize(0);
|
||||
m_deltafCF.resizeNoInitialize(0);
|
||||
m_deltafCRF.resizeNoInitialize(0);
|
||||
|
||||
return btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(bodies, numBodies, infoGlobal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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 BT_NNCG_CONSTRAINT_SOLVER_H
|
||||
#define BT_NNCG_CONSTRAINT_SOLVER_H
|
||||
|
||||
#include "btSequentialImpulseConstraintSolver.h"
|
||||
|
||||
ATTRIBUTE_ALIGNED16(class) btNNCGConstraintSolver : public btSequentialImpulseConstraintSolver
|
||||
{
|
||||
protected:
|
||||
|
||||
btScalar m_deltafLengthSqrPrev;
|
||||
|
||||
btAlignedObjectArray<btScalar> m_pNC; // p for None Contact constraints
|
||||
btAlignedObjectArray<btScalar> m_pC; // p for Contact constraints
|
||||
btAlignedObjectArray<btScalar> m_pCF; // p for ContactFriction constraints
|
||||
btAlignedObjectArray<btScalar> m_pCRF; // p for ContactRollingFriction constraints
|
||||
|
||||
//These are recalculated in every iterations. We just keep these to prevent reallocation in each iteration.
|
||||
btAlignedObjectArray<btScalar> m_deltafNC; // deltaf for NoneContact constraints
|
||||
btAlignedObjectArray<btScalar> m_deltafC; // deltaf for Contact constraints
|
||||
btAlignedObjectArray<btScalar> m_deltafCF; // deltaf for ContactFriction constraints
|
||||
btAlignedObjectArray<btScalar> m_deltafCRF; // deltaf for ContactRollingFriction constraints
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual btScalar solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal);
|
||||
virtual btScalar solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
|
||||
|
||||
virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer);
|
||||
|
||||
public:
|
||||
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
btNNCGConstraintSolver() : btSequentialImpulseConstraintSolver(), m_onlyForNoneContact(false) {}
|
||||
|
||||
virtual btConstraintSolverType getSolverType() const
|
||||
{
|
||||
return BT_NNCG_SOLVER;
|
||||
}
|
||||
|
||||
bool m_onlyForNoneContact;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif //BT_NNCG_CONSTRAINT_SOLVER_H
|
||||
|
||||
|
|
@ -116,6 +116,11 @@ public:
|
|||
virtual void setParam(int num, btScalar value, int axis = -1);
|
||||
///return the local value of parameter
|
||||
virtual btScalar getParam(int num, int axis = -1) const;
|
||||
|
||||
virtual int getFlags() const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue