internal override void processCollision( btCollisionObjectWrapper body0Wrap, ref btTransform body0Transform , btCollisionObjectWrapper body1Wrap, ref btTransform body1Transform, btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { if( m_manifoldPtr == null ) return; btBoxShape box0 = (btBoxShape)body0Wrap.m_shape; btBoxShape box1 = (btBoxShape)body1Wrap.m_shape; /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut.setPersistentManifold( m_manifoldPtr ); #if !USE_PERSISTENT_CONTACTS m_manifoldPtr.clearManifold(); #endif //USE_PERSISTENT_CONTACTS btDiscreteCollisionDetectorInterface.ClosestPointInput input = new btDiscreteCollisionDetectorInterface.ClosestPointInput(); input.m_maximumDistanceSquared = btScalar.BT_LARGE_FLOAT; input.m_transformA = body0Transform; input.m_transformB = body1Transform; //btBoxBoxDetector detector = BulletGlobals. // new btBoxBoxDetectors( box0, box1 ); btBoxBoxDetector.getClosestPoints( box0, box1, input, resultOut, dispatchInfo.m_debugDraw ); #if USE_PERSISTENT_CONTACTS // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added if( m_ownManifold ) { resultOut.refreshContactPoints(); } #endif //USE_PERSISTENT_CONTACTS }
internal override void processCollision( btCollisionObjectWrapper body0Wrap , ref btTransform body0Transform , btCollisionObjectWrapper body1Wrap , ref btTransform body1Transform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { btCollisionObjectWrapper colObjWrap = m_isSwapped ? body1Wrap : body0Wrap; btCollisionObjectWrapper otherObjWrap = m_isSwapped ? body0Wrap : body1Wrap; Debug.Assert( colObjWrap.getCollisionShape().isCompound() ); btCompoundShape compoundShape = (btCompoundShape)( colObjWrap.getCollisionShape() ); ///btCompoundShape might have changed: ////make sure the internal child collision algorithm caches are still valid if( compoundShape.getUpdateRevision() != m_compoundShapeRevision ) { ///clear and update all removeChildAlgorithms(); preallocateChildAlgorithms( body0Wrap, body1Wrap ); m_compoundShapeRevision = compoundShape.getUpdateRevision(); } if( m_childCollisionAlgorithms.Count == 0 ) return; btDbvt tree = compoundShape.getDynamicAabbTree(); //use a dynamic aabb tree to cull potential child-overlaps btCompoundLeafCallback callback = BulletGlobals.CompoundLeafCallbackPool.Get(); callback.Initialize( colObjWrap, otherObjWrap, m_dispatcher, dispatchInfo, resultOut, m_childCollisionAlgorithms.InternalArray, m_sharedManifold); ///we need to refresh all contact manifolds ///note that we should actually recursively traverse all children, btCompoundShape can nested more then 1 level deep ///so we should add a 'refreshManifolds' in the btCollisionAlgorithm { int i; btManifoldArray manifoldArray = new btManifoldArray(); for( i = 0; i < m_childCollisionAlgorithms.Count; i++ ) { if( m_childCollisionAlgorithms[i] != null ) { m_childCollisionAlgorithms[i].getAllContactManifolds( manifoldArray ); for( int m = 0; m < manifoldArray.Count; m++ ) { if( manifoldArray[m].m_cachedPoints > 0 ) { resultOut.setPersistentManifold( manifoldArray[m] ); resultOut.refreshContactPoints(); resultOut.setPersistentManifold( null );//??necessary? } } manifoldArray.Count = ( 0 ); } } } if( tree != null ) { btVector3 localAabbMin, localAabbMax; btTransform otherInCompoundSpace; if( m_isSwapped ) body1Transform.inverseTimes(ref body0Transform, out otherInCompoundSpace); else body0Transform.inverseTimes( ref body1Transform, out otherInCompoundSpace ); otherObjWrap.getCollisionShape().getAabb( ref otherInCompoundSpace, out localAabbMin, out localAabbMax ); btDbvt.btDbvtVolume bounds = btDbvt.btDbvtVolume.FromMM( ref localAabbMin, ref localAabbMax ); //process all children, that overlap with the given AABB bounds btDbvt.CollideTV( tree.m_root, ref bounds, callback ); } else { //iterate over all children, perform an AABB check inside ProcessChildShape int numChildren = m_childCollisionAlgorithms.Count; int i; for( i = 0; i < numChildren; i++ ) { callback.ProcessChildShape( compoundShape.getChildShape( i ), i ); } } { //iterate over all children, perform an AABB check inside ProcessChildShape int numChildren = m_childCollisionAlgorithms.Count; int i; //btManifoldArray manifoldArray; btCollisionShape childShape = null; //btITransform orgTrans; btTransform newChildWorldTrans; btVector3 aabbMin0, aabbMax0, aabbMin1, aabbMax1; for( i = 0; i < numChildren; i++ ) { if( m_childCollisionAlgorithms[i] != null ) { childShape = compoundShape.getChildShape( i ); //if not longer overlapping, remove the algorithm //orgTrans = colObjWrap.m_worldTransform; //btTransform childTrans = compoundShape.getChildTransform( i ); ( ( m_isSwapped ) ? body1Transform : body0Transform ).Apply( ref compoundShape.m_children.InternalArray[i].m_transform, out newChildWorldTrans ); //perform an AABB check first childShape.getAabb( ref newChildWorldTrans, out aabbMin0, out aabbMax0 ); if( m_isSwapped ) otherObjWrap.m_shape.getAabb( ref body0Transform, out aabbMin1, out aabbMax1 ); else otherObjWrap.m_shape.getAabb( ref body1Transform, out aabbMin1, out aabbMax1 ); if( !btAabbUtil.TestAabbAgainstAabb2( ref aabbMin0, ref aabbMax0, ref aabbMin1, ref aabbMax1 ) ) { //m_childCollisionAlgorithms[i].~btCollisionAlgorithm(); m_dispatcher.freeCollisionAlgorithm( m_childCollisionAlgorithms[i] ); m_childCollisionAlgorithms[i] = null; } } } } }
// // Convex-Convex collision algorithm // internal override void processCollision( btCollisionObjectWrapper body0Wrap , ref btTransform body0Transform , btCollisionObjectWrapper body1Wrap , ref btTransform body1Transform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { if( m_manifoldPtr == null ) { //swapped? m_manifoldPtr = m_dispatcher.getNewManifold( body0Wrap.m_collisionObject, body1Wrap.m_collisionObject ); m_ownManifold = true; } resultOut.setPersistentManifold( m_manifoldPtr ); //comment-out next line to test multi-contact generation //resultOut.getPersistentManifold().clearManifold(); btConvexShape min0 = (btConvexShape)body0Wrap.getCollisionShape(); btConvexShape min1 = (btConvexShape)body1Wrap.getCollisionShape(); btVector3 normalOnB; btVector3 pointOnBWorld; #if !BT_DISABLE_CAPSULE_CAPSULE_COLLIDER if( ( min0.getShapeType() == BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE ) && ( min1.getShapeType() == BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE ) ) { btCapsuleShape capsuleA = (btCapsuleShape)min0; btCapsuleShape capsuleB = (btCapsuleShape)min1; // btVector3 localScalingA = capsuleA.getLocalScaling(); // btVector3 localScalingB = capsuleB.getLocalScaling(); double threshold = m_manifoldPtr.getContactBreakingThreshold(); double dist = capsuleCapsuleDistance( out normalOnB, out pointOnBWorld , capsuleA.getHalfHeight(), capsuleA.getRadius() , capsuleB.getHalfHeight(), capsuleB.getRadius() , capsuleA.getUpAxis(), capsuleB.getUpAxis() , ref body0Wrap.m_collisionObject.m_worldTransform, ref body1Wrap.m_collisionObject.m_worldTransform, threshold ); if( dist < threshold ) { Debug.Assert( normalOnB.length2() >= ( btScalar.SIMD_EPSILON * btScalar.SIMD_EPSILON ) ); resultOut.addContactPoint( ref normalOnB, ref pointOnBWorld, dist ); } resultOut.refreshContactPoints(); return; } #endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER #if USE_SEPDISTANCE_UTIL2 if (dispatchInfo.m_useConvexConservativeDistanceUtil) { m_sepDistance.updateSeparatingDistance(body0.getWorldTransform(),body1.getWorldTransform()); } if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0) #endif //USE_SEPDISTANCE_UTIL2 { btGjkPairDetector.ClosestPointInput input = BulletGlobals.ClosestPointInputPool.Get(); input.Initialize(); btGjkPairDetector gjkPairDetector = BulletGlobals.GjkPairDetectorPool.Get(); gjkPairDetector.Initialize( min0, min1, m_simplexSolver, m_pdSolver ); //TODO: if (dispatchInfo.m_useContinuous) gjkPairDetector.setMinkowskiA( min0 ); gjkPairDetector.setMinkowskiB( min1 ); #if USE_SEPDISTANCE_UTIL2 if (dispatchInfo.m_useConvexConservativeDistanceUtil) { input.m_maximumDistanceSquared = BT_LARGE_FLOAT; } else #endif //USE_SEPDISTANCE_UTIL2 { //if (dispatchInfo.m_convexMaxDistanceUseCPT) //{ // input.m_maximumDistanceSquared = min0.getMargin() + min1.getMargin() + m_manifoldPtr.getContactProcessingThreshold(); //} else //{ input.m_maximumDistanceSquared = min0.getMargin() + min1.getMargin() + m_manifoldPtr.getContactBreakingThreshold(); // } input.m_maximumDistanceSquared *= input.m_maximumDistanceSquared; } input.m_transformA = body0Transform; input.m_transformB = body1Transform; #if USE_SEPDISTANCE_UTIL2 double sepDist = 0; if (dispatchInfo.m_useConvexConservativeDistanceUtil) { sepDist = gjkPairDetector.getCachedSeparatingDistance(); if (sepDist>SIMD_EPSILON) { sepDist += dispatchInfo.m_convexConservativeDistanceThreshold; //now perturbe directions to get multiple contact points } } #endif //USE_SEPDISTANCE_UTIL2 if( min0.isPolyhedral() && min1.isPolyhedral() ) { btDummyResult dummy = new btDummyResult(); ///btBoxShape is an exception: its vertices are created WITH margin so don't subtract it double min0Margin = min0.getShapeType() == BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE ? 0 : min0.getMargin(); double min1Margin = min1.getShapeType() == BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE ? 0 : min1.getMargin(); btWithoutMarginResult withoutMargin = new btWithoutMarginResult( resultOut, min0Margin, min1Margin ); btPolyhedralConvexShape polyhedronA = (btPolyhedralConvexShape)min0; btPolyhedralConvexShape polyhedronB = (btPolyhedralConvexShape)min1; if( polyhedronA.getConvexPolyhedron() != null && polyhedronB.getConvexPolyhedron() != null ) { double threshold = m_manifoldPtr.getContactBreakingThreshold(); double minDist = -1e30f; btVector3 sepNormalWorldSpace; bool foundSepAxis = true; if( dispatchInfo.m_enableSatConvex ) { foundSepAxis = btPolyhedralContactClipping.findSeparatingAxis( polyhedronA.getConvexPolyhedron(), polyhedronB.getConvexPolyhedron(), ref body0Wrap.m_collisionObject.m_worldTransform, ref body1Wrap.m_collisionObject.m_worldTransform, out sepNormalWorldSpace, resultOut ); } else { #if ZERO_MARGIN gjkPairDetector.setIgnoreMargin(true); gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); #else gjkPairDetector.getClosestPoints( input, withoutMargin, dispatchInfo.m_debugDraw ); //gjkPairDetector.getClosestPoints(input,dummy,dispatchInfo.m_debugDraw); #endif //ZERO_MARGIN //double l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); //if (l2>SIMD_EPSILON) { sepNormalWorldSpace = withoutMargin.m_reportedNormalOnWorld;//gjkPairDetector.getCachedSeparatingAxis()*(1/l2); //minDist = -1e30f;//gjkPairDetector.getCachedSeparatingDistance(); minDist = withoutMargin.m_reportedDistance;//gjkPairDetector.getCachedSeparatingDistance()+min0.getMargin()+min1.getMargin(); #if ZERO_MARGIN foundSepAxis = true;//gjkPairDetector.getCachedSeparatingDistance()<0; #else foundSepAxis = withoutMargin.m_foundResult && minDist < 0;//-(min0.getMargin()+min1.getMargin()); #endif } } if( foundSepAxis ) { // Console.WriteLine("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.x,sepNormalWorldSpace.y,sepNormalWorldSpace.z); btPolyhedralContactClipping.clipHullAgainstHull( ref sepNormalWorldSpace, polyhedronA.getConvexPolyhedron(), polyhedronB.getConvexPolyhedron(), ref body0Wrap.m_collisionObject.m_worldTransform, ref body1Wrap.m_collisionObject.m_worldTransform , minDist - threshold, threshold, resultOut ); } if( m_ownManifold ) { resultOut.refreshContactPoints(); } BulletGlobals.ClosestPointInputPool.Free( input ); BulletGlobals.GjkPairDetectorPool.Free( gjkPairDetector ); return; } else { //we can also deal with convex versus triangle (without connectivity data) if( polyhedronA.getConvexPolyhedron() != null && polyhedronB.getShapeType() == BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE ) { btVertexArray vertices = new btVertexArray(); btTriangleShape tri = (btTriangleShape)polyhedronB; btVector3 tmp; body1Transform.Apply( ref tri.m_vertices1, out tmp ); vertices.Add( ref tmp ); body1Transform.Apply( ref tri.m_vertices2, out tmp ); vertices.Add( ref tmp ); body1Transform.Apply( ref tri.m_vertices3, out tmp ); vertices.Add( ref tmp ); //tri.initializePolyhedralFeatures(); double threshold = m_manifoldPtr.getContactBreakingThreshold(); btVector3 sepNormalWorldSpace; double minDist = -btScalar.BT_LARGE_FLOAT; double maxDist = threshold; bool foundSepAxis = false; if( false ) { polyhedronB.initializePolyhedralFeatures(); foundSepAxis = btPolyhedralContactClipping.findSeparatingAxis( polyhedronA.getConvexPolyhedron(), polyhedronB.getConvexPolyhedron(), ref body0Wrap.m_collisionObject.m_worldTransform, ref body1Wrap.m_collisionObject.m_worldTransform, out sepNormalWorldSpace, resultOut ); // Console.WriteLine("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.x,sepNormalWorldSpace.y,sepNormalWorldSpace.z); btPolyhedralContactClipping.clipFaceAgainstHull( ref sepNormalWorldSpace , polyhedronA.getConvexPolyhedron(), ref body0Wrap.m_collisionObject.m_worldTransform, vertices, minDist - threshold, maxDist, resultOut ); } else { #if ZERO_MARGIN gjkPairDetector.setIgnoreMargin(true); gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); #else gjkPairDetector.getClosestPoints( input, dummy, dispatchInfo.m_debugDraw ); #endif//ZERO_MARGIN double l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); if( l2 > btScalar.SIMD_EPSILON ) { gjkPairDetector.getCachedSeparatingAxis().Mult( ( 1 / l2 ), out sepNormalWorldSpace ); //minDist = gjkPairDetector.getCachedSeparatingDistance(); //maxDist = threshold; minDist = gjkPairDetector.getCachedSeparatingDistance() - min0.getMargin() - min1.getMargin(); //foundSepAxis = true; btPolyhedralContactClipping.clipFaceAgainstHull( ref sepNormalWorldSpace , polyhedronA.getConvexPolyhedron(), ref body0Wrap.m_collisionObject.m_worldTransform, vertices, minDist - threshold, maxDist, resultOut ); } else { //sepNormalWorldSpace = btVector3.Zero; } } if( m_ownManifold ) { resultOut.refreshContactPoints(); } BulletGlobals.ClosestPointInputPool.Free( input ); BulletGlobals.GjkPairDetectorPool.Free( gjkPairDetector ); return; } } } gjkPairDetector.getClosestPoints( input, resultOut, dispatchInfo.m_debugDraw ); //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points if( m_numPerturbationIterations != 0 && resultOut.m_manifoldPtr.m_cachedPoints < m_minimumPointsPerturbationThreshold ) { int i; btVector3 v0, v1; btVector3 sepNormalWorldSpace; double l2 = gjkPairDetector.getCachedSeparatingAxis().length2(); if( l2 > btScalar.SIMD_EPSILON ) { gjkPairDetector.getCachedSeparatingAxis().Mult( ( 1 / l2 ), out sepNormalWorldSpace ); btVector3.btPlaneSpace1( ref sepNormalWorldSpace, out v0, out v1 ); bool perturbeA = true; double angleLimit = 0.125f * btScalar.SIMD_PI; double perturbeAngle; double radiusA = min0.getAngularMotionDisc(); double radiusB = min1.getAngularMotionDisc(); if( radiusA < radiusB ) { perturbeAngle = btPersistentManifold.gContactBreakingThreshold / radiusA; perturbeA = true; } else { perturbeAngle = btPersistentManifold.gContactBreakingThreshold / radiusB; perturbeA = false; } if( perturbeAngle > angleLimit ) perturbeAngle = angleLimit; btTransform unPerturbedTransform; if( perturbeA ) { unPerturbedTransform = input.m_transformA; } else { unPerturbedTransform = input.m_transformB; } for( i = 0; i < m_numPerturbationIterations; i++ ) { if( v0.length2() > btScalar.SIMD_EPSILON ) { btQuaternion perturbeRot = new btQuaternion( ref v0, perturbeAngle ); double iterationAngle = i * ( btScalar.SIMD_2_PI / (double)( m_numPerturbationIterations ) ); btQuaternion rotq = new btQuaternion( ref sepNormalWorldSpace, iterationAngle ); if( perturbeA ) { btQuaternion tmpq; btQuaternion tmpq2; rotq.inverse( out tmpq ); btQuaternion.Mult( ref tmpq, ref perturbeRot, out tmpq2 ); btQuaternion.Mult( ref tmpq2, ref rotq, out tmpq ); btMatrix3x3 m = new btMatrix3x3( ref tmpq ); btMatrix3x3 m2; body0Transform.getBasis( out m2 ); btMatrix3x3 m3; btMatrix3x3.Mult( ref m, ref m2, out m3 ); input.m_transformA.setBasis( ref m3 ); input.m_transformB = body1Transform; #if DEBUG_CONTACTS dispatchInfo.m_debugDraw.drawTransform(input.m_transformA,10.0); #endif //DEBUG_CONTACTS } else { btQuaternion tmpq; btQuaternion tmpq2; rotq.inverse( out tmpq ); btQuaternion.Mult( ref tmpq, ref perturbeRot, out tmpq2 ); btQuaternion.Mult( ref tmpq2, ref rotq, out tmpq ); btMatrix3x3 m = new btMatrix3x3( ref tmpq ); btMatrix3x3 m2; body1Transform.getBasis( out m2 ); btMatrix3x3 m3; btMatrix3x3.Mult( ref m, ref m2, out m3 ); input.m_transformA = body0Transform; input.m_transformB.setBasis( ref m3 ); #if DEBUG_CONTACTS dispatchInfo.m_debugDraw.drawTransform(input.m_transformB,10.0); #endif } btPerturbedContactResult perturbedResultOut = BulletGlobals.PerturbedContactResultPool.Get(); if( perturbeA ) perturbedResultOut.Initialize( resultOut , ref input.m_transformA, ref input.m_transformB , ref input.m_transformA , perturbeA , dispatchInfo.m_debugDraw ); else perturbedResultOut.Initialize( resultOut , ref input.m_transformA, ref input.m_transformB , ref input.m_transformB , perturbeA , dispatchInfo.m_debugDraw ); gjkPairDetector.getClosestPoints( input, perturbedResultOut, dispatchInfo.m_debugDraw ); BulletGlobals.PerturbedContactResultPool.Free( perturbedResultOut ); } } } } #if USE_SEPDISTANCE_UTIL2 if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON)) { m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0.getWorldTransform(),body1.getWorldTransform()); } #endif //USE_SEPDISTANCE_UTIL2 BulletGlobals.ClosestPointInputPool.Free( input ); BulletGlobals.GjkPairDetectorPool.Free( gjkPairDetector ); } if( m_ownManifold ) { resultOut.refreshContactPoints(); } }
internal override void processCollision( btCollisionObjectWrapper body0Wrap , ref btTransform body0Transform , btCollisionObjectWrapper body1Wrap , ref btTransform body1Transform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { //(void)dispatchInfo; if( m_manifoldPtr == null ) return; resultOut.setPersistentManifold( m_manifoldPtr ); btSphereShape sphere0 = (btSphereShape)body0Wrap.getCollisionShape(); btSphereShape sphere1 = (btSphereShape)body1Wrap.getCollisionShape(); btVector3 diff; body0Wrap.m_collisionObject.m_worldTransform.m_origin.Sub( ref body1Wrap.m_collisionObject.m_worldTransform.m_origin, out diff ); double len = diff.length(); double radius0 = sphere0.getRadius(); double radius1 = sphere1.getRadius(); #if CLEAR_MANIFOLD m_manifoldPtr.clearManifold(); //don't do this, it disables warmstarting #endif ///iff distance positive, don't generate a new contact if( len > ( radius0 + radius1 ) ) { #if !CLEAR_MANIFOLD resultOut.refreshContactPoints(); #endif //CLEAR_MANIFOLD return; } ///distance (negative means penetration) double dist = len - ( radius0 + radius1 ); btVector3 normalOnSurfaceB = btVector3.xAxis; if( len > btScalar.SIMD_EPSILON ) { normalOnSurfaceB = diff / len; } ///point on A (worldspace) ///btVector3 pos0 = col0.getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB; ///point on B (worldspace) btVector3 pos1; body1Wrap.m_collisionObject.m_worldTransform.m_origin.AddScale( ref normalOnSurfaceB, radius1, out pos1 ); /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut.addContactPoint( ref normalOnSurfaceB, ref pos1, dist ); #if !CLEAR_MANIFOLD resultOut.refreshContactPoints(); #endif //CLEAR_MANIFOLD }
internal override void processCollision( btCollisionObjectWrapper body0Wrap , ref btTransform body0Transform , btCollisionObjectWrapper body1Wrap , ref btTransform body1Transform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { btCollisionObjectWrapper col0ObjWrap = body0Wrap; btCollisionObjectWrapper col1ObjWrap = body1Wrap; Debug.Assert( col0ObjWrap.getCollisionShape().isCompound() ); Debug.Assert( col1ObjWrap.getCollisionShape().isCompound() ); btCompoundShape compoundShape0 = (btCompoundShape)( col0ObjWrap.getCollisionShape() ); btCompoundShape compoundShape1 = (btCompoundShape)( col1ObjWrap.getCollisionShape() ); btDbvt tree0 = compoundShape0.getDynamicAabbTree(); btDbvt tree1 = compoundShape1.getDynamicAabbTree(); if( tree0 == null || tree1 == null ) { base.processCollision( body0Wrap, ref body0Transform, body1Wrap, ref body1Transform, dispatchInfo, resultOut ); return; } ///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(); } ///we need to refresh all contact manifolds ///note that we should actually recursively traverse all children, btCompoundShape can nested more then 1 level deep ///so we should add a 'refreshManifolds' in the btCollisionAlgorithm { int i; btManifoldArray manifoldArray = new btManifoldArray(); btSimplePairArray pairs = m_childCollisionAlgorithmCache.getOverlappingPairArray(); for( i = 0; i < pairs.Count; i++ ) { if( pairs[i].m_userPointer != null ) { btCollisionAlgorithm algo = (btCollisionAlgorithm)pairs[i].m_userPointer; algo.getAllContactManifolds( manifoldArray ); for( int m = 0; m < manifoldArray.Count; m++ ) { if( manifoldArray[m].m_cachedPoints != 0 ) { resultOut.setPersistentManifold( manifoldArray[m] ); resultOut.refreshContactPoints(); resultOut.setPersistentManifold( null ); } } manifoldArray.Count =( 0 ); } } } btCompoundCompoundLeafCallback callback = new btCompoundCompoundLeafCallback ( col0ObjWrap, col1ObjWrap,this.m_dispatcher, dispatchInfo, resultOut, this.m_childCollisionAlgorithmCache, m_sharedManifold); btTransform xform; body0Transform.inverseTimes( ref body1Transform, out xform ); MycollideTT( tree0.m_root, tree1.m_root, ref xform, callback ); //Console.WriteLine("#compound-compound child/leaf overlap =%d \r",callback.m_numOverlapPairs); //remove non-overlapping child pairs { Debug.Assert( m_removePairs.Count == 0 ); //iterate over all children, perform an AABB check inside ProcessChildShape btSimplePairArray pairs = m_childCollisionAlgorithmCache.getOverlappingPairArray(); int i; //btManifoldArray manifoldArray; btVector3 aabbMin0, aabbMax0, aabbMin1, aabbMax1; for( i = 0; i < pairs.Count; i++ ) { if( pairs[i].m_userPointer != null ) { btCollisionAlgorithm algo = (btCollisionAlgorithm)pairs[i].m_userPointer; { btCollisionShape childShape0 = null; btTransform newChildWorldTrans0; //btTransform orgInterpolationTrans0; childShape0 = compoundShape0.getChildShape( pairs[i].m_indexA ); //orgInterpolationTrans0 = col0ObjWrap.m_worldTransform; btTransform childTrans0 = compoundShape0.getChildTransform( pairs[i].m_indexA ); body0Transform.Apply( ref childTrans0, out newChildWorldTrans0 ); childShape0.getAabb( ref newChildWorldTrans0, out aabbMin0, out aabbMax0 ); } { btCollisionShape childShape1 = null; btTransform newChildWorldTrans1; childShape1 = compoundShape1.getChildShape( pairs[i].m_indexB ); btTransform childTrans1 = compoundShape1.getChildTransform( pairs[i].m_indexB ); body1Transform.Apply( ref childTrans1, out newChildWorldTrans1 ); childShape1.getAabb( ref newChildWorldTrans1, out aabbMin1, out aabbMax1 ); } if( !btAabbUtil.TestAabbAgainstAabb2( ref aabbMin0, ref aabbMax0, ref aabbMin1, ref aabbMax1 ) ) { //algo.~btCollisionAlgorithm(); m_dispatcher.freeCollisionAlgorithm( algo ); m_removePairs.Add( new btSimplePair( pairs[i].m_indexA, pairs[i].m_indexB ) ); } } } for( i = 0; i < m_removePairs.Count; i++ ) { m_childCollisionAlgorithmCache.removeOverlappingPair( m_removePairs[i].m_indexA, m_removePairs[i].m_indexB ); } m_removePairs.Clear(); } }
internal override void processCollision( btCollisionObjectWrapper col0Wrap , ref btTransform body0Transform , btCollisionObjectWrapper col1Wrap , ref btTransform body1Transform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { if( m_manifoldPtr == null ) return; btCollisionObjectWrapper sphereObjWrap = m_swapped ? col1Wrap : col0Wrap; btCollisionObjectWrapper triObjWrap = m_swapped ? col0Wrap : col1Wrap; btSphereShape sphere = (btSphereShape)sphereObjWrap.getCollisionShape(); btTriangleShape triangle = (btTriangleShape)triObjWrap.getCollisionShape(); /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut.setPersistentManifold( m_manifoldPtr ); SphereTriangleDetector detector = BulletGlobals.SphereTriangleDetectorPool.Get(); detector.Initialize( sphere, triangle, m_manifoldPtr.getContactBreakingThreshold()); btDiscreteCollisionDetectorInterface.ClosestPointInput input = BulletGlobals.ClosestPointInputPool.Get(); input.m_maximumDistanceSquared = btScalar.BT_LARGE_FLOAT;///@todo: tighter bounds if( m_swapped ) { input.m_transformA = body1Transform; input.m_transformB = body0Transform; } else { input.m_transformA = body0Transform; input.m_transformB = body1Transform; } bool swapResults = m_swapped; detector.getClosestPoints( input, resultOut, dispatchInfo.m_debugDraw, swapResults ); BulletGlobals.ClosestPointInputPool.Free( input ); BulletGlobals.SphereTriangleDetectorPool.Free( detector ); if( m_ownManifold ) resultOut.refreshContactPoints(); }
void collideSingleContact( bool usePertube, ref btQuaternion perturbeRot , btCollisionObjectWrapper convexObjWrap , ref btTransform convexTransform , btCollisionObjectWrapper planeObjWrap , ref btTransform planeTransform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut , ref btVector3 planeNormal, double planeConstant ) { //btCollisionObjectWrapper convexObjWrap = m_swapped ? body1Wrap : body0Wrap; //btCollisionObjectWrapper planeObjWrap = m_swapped ? body0Wrap : body1Wrap; btConvexShape convexShape = (btConvexShape)convexObjWrap.getCollisionShape(); btStaticPlaneShape planeShape = (btStaticPlaneShape)planeObjWrap.getCollisionShape(); bool hasCollision = false; //planeNormal = planeShape.getPlaneNormal().Copy( out planeNormal ); //double planeConstant = planeShape.getPlaneConstant(); btTransform convexWorldTransform = convexTransform; //btTransform planeWorldTransform = planeObjWrap.m_worldTransform; btTransform convexInPlaneTrans; planeTransform.inverseTimes( ref convexWorldTransform, out convexInPlaneTrans ); if( usePertube ) { //now perturbe the convex-world transform btMatrix3x3 perturbeMat = new btMatrix3x3( ref perturbeRot ); btMatrix3x3 tmpPerturbe; convexWorldTransform.m_basis.Apply( ref perturbeMat, out tmpPerturbe ); convexWorldTransform.m_basis = tmpPerturbe; //convexWorldTransform.getBasis() *= btMatrix3x3( perturbeRot ); } btTransform planeInConvex; convexTransform.inverseTimes( ref planeObjWrap.m_collisionObject.m_worldTransform, out planeInConvex ); btVector3 tmp, tmp2; planeNormal.Invert( out tmp ); planeInConvex.m_basis.Apply( ref tmp, out tmp2 ); btVector3 vtx; convexShape.localGetSupportingVertex( ref tmp2, out vtx ); btVector3 vtxInPlane; convexInPlaneTrans.Apply( ref vtx, out vtxInPlane ); double distance = ( planeNormal.dot( ref vtxInPlane ) - planeConstant ); btVector3 vtxInPlaneProjected; vtxInPlane.AddScale( ref planeNormal, -distance, out vtxInPlaneProjected ); btVector3 vtxInPlaneWorld; planeTransform.Apply( ref vtxInPlaneProjected, out vtxInPlaneWorld ); hasCollision = distance < m_manifoldPtr.getContactBreakingThreshold(); resultOut.setPersistentManifold( m_manifoldPtr ); if( hasCollision ) { /// report a contact. internally this will be kept persistent, and contact reduction is done btVector3 normalOnSurfaceB; planeTransform.m_basis.Apply( ref planeNormal, out normalOnSurfaceB ); btScalar.Dbg( "Convex plane adds point " + normalOnSurfaceB + " " + vtxInPlaneWorld + " " + distance.ToString( "g17" ) ); resultOut.addContactPoint( ref normalOnSurfaceB, ref vtxInPlaneWorld, distance ); } }
internal override void processCollision( btCollisionObjectWrapper body0Wrap , ref btTransform body0Transform , btCollisionObjectWrapper body1Wrap , ref btTransform body1Transform , btDispatcherInfo dispatchInfo, btManifoldResult resultOut ) { btCollisionObjectWrapper convexBodyWrap = m_isSwapped ? body1Wrap : body0Wrap; btCollisionObjectWrapper triBodyWrap = m_isSwapped ? body0Wrap : body1Wrap; if( triBodyWrap.getCollisionShape().isConcave() ) { btConcaveShape concaveShape = (btConcaveShape)triBodyWrap.getCollisionShape(); if( convexBodyWrap.getCollisionShape().isConvex() ) { double collisionMarginTriangle = concaveShape.getMargin(); resultOut.setPersistentManifold( m_btConvexTriangleCallback.m_manifoldPtr ); if( m_isSwapped ) m_btConvexTriangleCallback.setTimeStepAndCounters( collisionMarginTriangle, dispatchInfo , convexBodyWrap, ref body1Transform , triBodyWrap, ref body0Transform , resultOut ); else m_btConvexTriangleCallback.setTimeStepAndCounters( collisionMarginTriangle, dispatchInfo , convexBodyWrap, ref body0Transform , triBodyWrap, ref body1Transform , resultOut ); m_btConvexTriangleCallback.m_manifoldPtr.setBodies( convexBodyWrap.m_collisionObject, triBodyWrap.m_collisionObject ); concaveShape.processAllTriangles( m_btConvexTriangleCallback, ref m_btConvexTriangleCallback.m_aabbMin, ref m_btConvexTriangleCallback.m_aabbMax ); resultOut.refreshContactPoints(); m_btConvexTriangleCallback.clearWrapperData(); } } }