public override void ClientMoveAndDisplay(GameTime gameTime) { // OPTIONAL: We simply move our ghost objects around (without rotating them.....)============== if (m_ghostObject != null || m_pairCachingGhostObject != null) { rad += 0.005f; // Bad (depends on PC speed) float sinRad = (float)Math.Sin(rad); float cosRad = (float)Math.Cos(rad); if (m_ghostObject != null) { IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y); im._origin = new IndexedVector3(15 * cosRad, 5, -15 * sinRad); m_ghostObject.SetWorldTransform(ref im); } if (m_pairCachingGhostObject != null) { IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y); im._origin = new IndexedVector3(-15 * cosRad, 7, 15 * sinRad); m_pairCachingGhostObject.SetWorldTransform(ref im); } } base.ClientMoveAndDisplay(gameTime); // NEW => Retrives the content from all ghost objects in the world and call ProcessObectsInsideGhostObjects(...) for each ==== if (m_dynamicsWorld != null) { ObjectArray <CollisionObject> objsInsidePairCachingGhostObject = new ObjectArray <CollisionObject>(); // We might want this to be a member variable... ObjectArray <CollisionObject> pObjsInsideGhostObject = null; // We will store a reference of the current array in this pointer ObjectArray <CollisionObject> objs = m_dynamicsWorld.GetCollisionObjectArray(); for (int i = 0, sz = objs.Count; i < sz; i++) { CollisionObject o = objs[i]; GhostObject go = GhostObject.Upcast(o); if (go != null) { objsInsidePairCachingGhostObject.Resize(0); PairCachingGhostObject pgo = go as PairCachingGhostObject; // No upcast functionality... if (pgo != null) { GetCollidingObjectsInsidePairCachingGhostObject((DiscreteDynamicsWorld)m_dynamicsWorld, pgo, objsInsidePairCachingGhostObject); pObjsInsideGhostObject = objsInsidePairCachingGhostObject; } else { pObjsInsideGhostObject = go.GetOverlappingPairs(); // It's better not to try and copy the whole array, but to keep a reference to it! // Side Note: btAlignedObjectArray < btCollisionObject* > objs = go.getOverlappingPairs(); (at the moment) makes my program crash on my system... // Nevermind, that was the wrong way of doing it: btAlignedObjectArray < btCollisionObject* >& objs = go.getOverlappingPairs(); is much better. } // Here pObjsInsideGhostObject should be valid. ProcessObectsInsideGhostObjects(pObjsInsideGhostObject, pgo != null); } } } }
//InplaceSolverIslandCallback operator=(InplaceSolverIslandCallback& other) //{ // Debug.Assert(false); // //(void)other; // return *this; //} public void Setup(ContactSolverInfo solverInfo, ObjectArray <TypedConstraint> sortedConstraints, int numConstraints, IDebugDraw debugDrawer) { Debug.Assert(solverInfo != null); m_solverInfo = solverInfo; m_sortedConstraints = sortedConstraints; m_numConstraints = numConstraints; m_debugDrawer = debugDrawer; m_bodies.Resize(0); m_manifolds.Resize(0); m_constraints.Resize(0); }
public static void Split(ObjectArray <DbvtNode> leaves, ObjectArray <DbvtNode> left, ObjectArray <DbvtNode> right, ref IndexedVector3 org, ref IndexedVector3 axis) { left.Resize(0); right.Resize(0); for (int i = 0, ni = leaves.Count; i < ni; ++i) { if (IndexedVector3.Dot(axis, leaves[i].volume.Center() - org) < 0) { left.Add(leaves[i]); } else { right.Add(leaves[i]); } } }
public static void CollideTTpersistentStack(DbvtNode root0, DbvtNode root1, ICollide collideable) { //CollideTT(root0, root1, collideable); //return; if (root0 != null && root1 != null) { int depth = 1; int treshold = DOUBLE_STACKSIZE - 4; m_stkStack.Resize(DOUBLE_STACKSIZE); m_stkStack[0] = new sStkNN(root0, root1); do { sStkNN p = m_stkStack[--depth]; if (depth > treshold) { m_stkStack.Resize(m_stkStack.Count * 2); treshold = m_stkStack.Count - 4; } if (p.a == p.b) { if (p.a.IsInternal()) { m_stkStack[depth++] = new sStkNN(p.a._children[0], p.a._children[0]); m_stkStack[depth++] = new sStkNN(p.a._children[1], p.a._children[1]); m_stkStack[depth++] = new sStkNN(p.a._children[0], p.a._children[1]); } } else if (DbvtAabbMm.Intersect(ref p.a.volume, ref p.b.volume)) { if (p.a.IsInternal()) { if (p.b.IsInternal()) { m_stkStack[depth++] = new sStkNN(p.a._children[0], p.b._children[0]); m_stkStack[depth++] = new sStkNN(p.a._children[1], p.b._children[0]); m_stkStack[depth++] = new sStkNN(p.a._children[0], p.b._children[1]); m_stkStack[depth++] = new sStkNN(p.a._children[1], p.b._children[1]); } else { m_stkStack[depth++] = new sStkNN(p.a._children[0], p.b); m_stkStack[depth++] = new sStkNN(p.a._children[1], p.b); } } else { if (p.b.IsInternal()) { m_stkStack[depth++] = new sStkNN(p.a, p.b._children[0]); m_stkStack[depth++] = new sStkNN(p.a, p.b._children[1]); } else { collideable.Process(p.a, p.b); } } } } while (depth > 0); } }
public static void CollideTT(DbvtNode root0, DbvtNode root1, ICollide collideable) { CollideTTCount++; Debug.Assert(CollideTTCount < 2); CollideTTStack.Clear(); if (root0 != null && root1 != null) { int depth = 1; int treshold = DOUBLE_STACKSIZE - 4; CollideTTStack[0] = new sStkNN(root0, root1); do { sStkNN p = CollideTTStack[--depth]; if (depth > treshold) { CollideTTStack.Resize(CollideTTStack.Count * 2); treshold = CollideTTStack.Count - 4; } if (p.a == p.b) { if (p.a.IsInternal()) { CollideTTStack[depth++] = new sStkNN(p.a._children[0], p.a._children[0]); CollideTTStack[depth++] = new sStkNN(p.a._children[1], p.a._children[1]); CollideTTStack[depth++] = new sStkNN(p.a._children[0], p.a._children[1]); } } else if (DbvtAabbMm.Intersect(ref p.a.volume, ref p.b.volume)) { if (p.a.IsInternal()) { if (p.b.IsInternal()) { CollideTTStack[depth++] = new sStkNN(p.a._children[0], p.b._children[0]); CollideTTStack[depth++] = new sStkNN(p.a._children[1], p.b._children[0]); CollideTTStack[depth++] = new sStkNN(p.a._children[0], p.b._children[1]); CollideTTStack[depth++] = new sStkNN(p.a._children[1], p.b._children[1]); } else { CollideTTStack[depth++] = new sStkNN(p.a._children[0], p.b); CollideTTStack[depth++] = new sStkNN(p.a._children[1], p.b); } } else { if (p.b.IsInternal()) { CollideTTStack[depth++] = new sStkNN(p.a, p.b._children[0]); CollideTTStack[depth++] = new sStkNN(p.a, p.b._children[1]); } else { collideable.Process(p.a, p.b); } } } } while (depth > 0); } CollideTTCount--; }
///optional method mainly used to generate multiple contact points by clipping polyhedral features (faces/edges) public virtual bool InitializePolyhedralFeatures() { #if USE_CONVEX_HULL_COMPUTER if (m_polyhedron != null) { m_polyhedron = null; } m_polyhedron = new ConvexPolyhedron(); ObjectArray <IndexedVector3> tmpVertices = new ObjectArray <IndexedVector3>(); for (int i = 0; i < GetNumVertices(); i++) { IndexedVector3 newVertex; GetVertex(i, out newVertex); tmpVertices.Add(newVertex); } ConvexHullComputer conv = new ConvexHullComputer(); //conv.compute(&tmpVertices[0].getX(), sizeof(IndexedVector3),tmpVertices.Count,0.0f,0.0f); conv.Compute(tmpVertices, 0, tmpVertices.Count, 0.0f, 0.0f); ObjectArray <IndexedVector3> faceNormals = new ObjectArray <IndexedVector3>(); int numFaces = conv.faces.size(); faceNormals.Resize(numFaces); ConvexHullComputer convexUtil = conv; m_polyhedron.m_faces.Resize(numFaces); int numVertices = convexUtil.vertices.Count; m_polyhedron.m_vertices.Resize(numVertices); for (int p = 0; p < numVertices; p++) { m_polyhedron.m_vertices[p] = convexUtil.vertices[p]; } for (int i = 0; i < numFaces; i++) { int face = convexUtil.faces[i]; //printf("face=%d\n",face); Edge firstEdge = convexUtil.edges[face]; Edge edge = firstEdge; IndexedVector3[] edges = new IndexedVector3[3]; int numEdges = 0; //compute face normals float maxCross2 = 0.0f; int chosenEdge = -1; do { int src = edge.GetSourceVertex(); m_polyhedron.m_faces[i].m_indices.Add(src); int targ = edge.GetTargetVertex(); IndexedVector3 wa = convexUtil.vertices[src]; IndexedVector3 wb = convexUtil.vertices[targ]; IndexedVector3 newEdge = wb - wa; newEdge.Normalize(); if (numEdges < 2) { edges[numEdges++] = newEdge; } edge = edge.GetNextEdgeOfFace(); } while (edge != firstEdge); float planeEq = 1e30f; if (numEdges == 2) { faceNormals[i] = IndexedVector3.Cross(edges[0], edges[1]); faceNormals[i].Normalize(); m_polyhedron.m_faces[i].m_plane[0] = -faceNormals[i].X; m_polyhedron.m_faces[i].m_plane[1] = -faceNormals[i].Y; m_polyhedron.m_faces[i].m_plane[2] = -faceNormals[i].Z; m_polyhedron.m_faces[i].m_plane[3] = planeEq; } else { Debug.Assert(false);//degenerate? faceNormals[i] = IndexedVector3.Zero; } for (int v = 0; v < m_polyhedron.m_faces[i].m_indices.Count; v++) { float eq = IndexedVector3.Dot(m_polyhedron.m_vertices[m_polyhedron.m_faces[i].m_indices[v]], faceNormals[i]); if (planeEq > eq) { planeEq = eq; } } m_polyhedron.m_faces[i].m_plane[3] = planeEq; } if (m_polyhedron.m_faces.Count > 0 && conv.vertices.Count > 0) { for (int f = 0; f < m_polyhedron.m_faces.Count; f++) { IndexedVector3 planeNormal = new IndexedVector3(m_polyhedron.m_faces[f].m_plane[0], m_polyhedron.m_faces[f].m_plane[1], m_polyhedron.m_faces[f].m_plane[2]); float planeEq = m_polyhedron.m_faces[f].m_plane[3]; IndexedVector3 supVec = LocalGetSupportingVertex(-planeNormal); if (IndexedVector3.Dot(supVec, planeNormal) < planeEq) { m_polyhedron.m_faces[f].m_plane[0] *= -1; m_polyhedron.m_faces[f].m_plane[1] *= -1; m_polyhedron.m_faces[f].m_plane[2] *= -1; m_polyhedron.m_faces[f].m_plane[3] *= -1; int numVerts = m_polyhedron.m_faces[f].m_indices.Count; for (int v = 0; v < numVerts / 2; v++) { int temp = m_polyhedron.m_faces[f].m_indices[v]; m_polyhedron.m_faces[f].m_indices[v] = m_polyhedron.m_faces[f].m_indices[numVerts - 1 - v]; m_polyhedron.m_faces[f].m_indices[numVerts - 1 - v] = temp; } } } } m_polyhedron.Initialize(); #endif return(true); }
// Portable static method: prerequisite call: m_dynamicsWorld.getBroadphase().getOverlappingPairCache().setInternalGhostPairCallback(new btGhostPairCallback()); public static void GetCollidingObjectsInsidePairCachingGhostObject(DiscreteDynamicsWorld m_dynamicsWorld, PairCachingGhostObject m_pairCachingGhostObject, ObjectArray<CollisionObject> collisionArrayOut) { bool addOnlyObjectsWithNegativeDistance = true; // With "false" things don't change much, and the code is a bit faster and cleaner... collisionArrayOut.Resize(0); if (m_pairCachingGhostObject == null || m_dynamicsWorld == null) return; //#define USE_PLAIN_COLLISION_WORLD // We dispatch all collision pairs of the ghost object every step (slow) #if USE_PLAIN_COLLISION_WORLD //====================================================================================================== // I thought this line was no longer needed, but it seems to be necessary (and I believe it's an expensive call): m_dynamicsWorld.getDispatcher().dispatchAllCollisionPairs(m_pairCachingGhostObject.getOverlappingPairCache(), m_dynamicsWorld.getDispatchInfo(), m_dynamicsWorld.getDispatcher()); // Maybe the call can be automatically triggered by some other Bullet call (I'm almost sure I could comment it out in another demo I made long ago...) // So by now the general rule is: in real projects, simply comment it out and see if it works! //====================================================================================================== // UPDATE: in dynamic worlds, the line above can be commented out and the broadphase pair can be retrieved through the call to findPair(...) below. // In collision worlds probably the above line is needed only if collision detection for all the bodies hasn't been made... This is something // I'm still not sure of... the general rule is to try to comment out the line above and try to use findPair(...) and see if it works whenever possible.... //====================================================================================================== #endif //USE_PLAIN_COLLISION_WORLD ObjectArray<BroadphasePair> collisionPairs = m_pairCachingGhostObject.GetOverlappingPairCache().GetOverlappingPairArray(); int numObjects = collisionPairs.Count; PersistentManifoldArray m_manifoldArray = new PersistentManifoldArray(); bool added; for (int i = 0; i < numObjects; i++) { m_manifoldArray.Resize(0); #if USE_PLAIN_COLLISION_WORLD const btBroadphasePair& collisionPair = collisionPairs[i]; if (collisionPair.m_algorithm) collisionPair.m_algorithm.getAllContactManifolds(m_manifoldArray); else { // THIS SHOULD NEVER HAPPEN, AND IF IT DOES, PLEASE RE-ENABLE the "call" a few lines above... printf("No collisionPair.m_algorithm - probably m_dynamicsWorld.getDispatcher().dispatchAllCollisionPairs(...) must be missing.\n"); } #else // USE_PLAIN_COLLISION_WORLD BroadphasePair cPair = collisionPairs[i]; //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: BroadphasePair collisionPair = m_dynamicsWorld.GetPairCache().FindPair(cPair.m_pProxy0, cPair.m_pProxy1); if (collisionPair == null) { continue; } if (collisionPair.m_algorithm != null) { collisionPair.m_algorithm.GetAllContactManifolds(m_manifoldArray); } else { // THIS SHOULD NEVER HAPPEN, AND IF IT DOES, PLEASE RE-ENABLE the "call" a few lines above... //printf("No collisionPair.m_algorithm - probably m_dynamicsWorld.getDispatcher().dispatchAllCollisionPairs(...) must be missing.\n"); } #endif //USE_PLAIN_COLLISION_WORLD added = false; for (int j = 0; j < m_manifoldArray.Count; j++) { PersistentManifold manifold = m_manifoldArray[j]; // Here we are in the narrowphase, but can happen that manifold.getNumContacts()==0: if (addOnlyObjectsWithNegativeDistance) { for (int p = 0, numContacts = manifold.GetNumContacts(); p < numContacts; p++) { ManifoldPoint pt = manifold.GetContactPoint(p); if (pt.GetDistance() < 0.0) { // How can I be sure that the colObjs are all distinct ? I use the "added" flag. collisionArrayOut.Add((CollisionObject)(manifold.GetBody0() == m_pairCachingGhostObject ? manifold.GetBody1() : manifold.GetBody0())); added = true; break; } } if (added) { break; } } else if (manifold.GetNumContacts() > 0) { collisionArrayOut.Add((CollisionObject)(manifold.GetBody0() == m_pairCachingGhostObject ? manifold.GetBody1() : manifold.GetBody0())); break; } } } }
public override void ClientMoveAndDisplay(GameTime gameTime) { // OPTIONAL: We simply move our ghost objects around (without rotating them.....)============== if (m_ghostObject != null || m_pairCachingGhostObject != null) { rad+=0.005f; // Bad (depends on PC speed) float sinRad = (float)Math.Sin(rad); float cosRad = (float)Math.Cos(rad); if (m_ghostObject != null) { IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y); im._origin = new IndexedVector3(15*cosRad,5,-15*sinRad); m_ghostObject.SetWorldTransform(ref im); } if (m_pairCachingGhostObject != null) { IndexedMatrix im = IndexedMatrix.CreateFromQuaternion(quatDeg45Y); im._origin = new IndexedVector3(-15*cosRad,7,15*sinRad); m_pairCachingGhostObject.SetWorldTransform(ref im); } } base.ClientMoveAndDisplay(gameTime); // NEW => Retrives the content from all ghost objects in the world and call ProcessObectsInsideGhostObjects(...) for each ==== if (m_dynamicsWorld != null) { ObjectArray < CollisionObject > objsInsidePairCachingGhostObject = new ObjectArray<CollisionObject>(); // We might want this to be a member variable... ObjectArray < CollisionObject > pObjsInsideGhostObject = null; // We will store a reference of the current array in this pointer ObjectArray < CollisionObject > objs = m_dynamicsWorld.GetCollisionObjectArray(); for (int i=0,sz=objs.Count;i<sz;i++) { CollisionObject o = objs[i]; GhostObject go = GhostObject.Upcast(o); if (go != null) { objsInsidePairCachingGhostObject.Resize(0); PairCachingGhostObject pgo = go as PairCachingGhostObject; // No upcast functionality... if (pgo != null) { GetCollidingObjectsInsidePairCachingGhostObject((DiscreteDynamicsWorld)m_dynamicsWorld,pgo,objsInsidePairCachingGhostObject); pObjsInsideGhostObject = objsInsidePairCachingGhostObject; } else { pObjsInsideGhostObject = go.GetOverlappingPairs(); // It's better not to try and copy the whole array, but to keep a reference to it! // Side Note: btAlignedObjectArray < btCollisionObject* > objs = go.getOverlappingPairs(); (at the moment) makes my program crash on my system... // Nevermind, that was the wrong way of doing it: btAlignedObjectArray < btCollisionObject* >& objs = go.getOverlappingPairs(); is much better. } // Here pObjsInsideGhostObject should be valid. ProcessObectsInsideGhostObjects(pObjsInsideGhostObject,pgo != null); } } } }
public static void Split(ObjectArray<DbvtNode> leaves, ObjectArray<DbvtNode> left, ObjectArray<DbvtNode> right, ref IndexedVector3 org, ref IndexedVector3 axis) { left.Resize(0); right.Resize(0); for (int i = 0, ni = leaves.Count; i < ni; ++i) { if (IndexedVector3.Dot(axis, leaves[i].volume.Center() - org) < 0) { left.Add(leaves[i]); } else { right.Add(leaves[i]); } } }
///optional method mainly used to generate multiple contact points by clipping polyhedral features (faces/edges) public virtual bool InitializePolyhedralFeatures() { #if USE_CONVEX_HULL_COMPUTER if (m_polyhedron != null) { m_polyhedron = null; } m_polyhedron = new ConvexPolyhedron(); ObjectArray<IndexedVector3> tmpVertices = new ObjectArray<IndexedVector3>(); for (int i = 0; i < GetNumVertices(); i++) { IndexedVector3 newVertex; GetVertex(i, out newVertex); tmpVertices.Add(newVertex); } ConvexHullComputer conv = new ConvexHullComputer(); //conv.compute(&tmpVertices[0].getX(), sizeof(IndexedVector3),tmpVertices.Count,0.0f,0.0f); conv.Compute(tmpVertices, 0, tmpVertices.Count, 0.0f, 0.0f); ObjectArray<IndexedVector3> faceNormals = new ObjectArray<IndexedVector3>(); int numFaces = conv.faces.size(); faceNormals.Resize(numFaces); ConvexHullComputer convexUtil = conv; m_polyhedron.m_faces.Resize(numFaces); int numVertices = convexUtil.vertices.Count; m_polyhedron.m_vertices.Resize(numVertices); for (int p = 0; p < numVertices; p++) { m_polyhedron.m_vertices[p] = convexUtil.vertices[p]; } for (int i = 0; i < numFaces; i++) { int face = convexUtil.faces[i]; //printf("face=%d\n",face); Edge firstEdge = convexUtil.edges[face]; Edge edge = firstEdge; IndexedVector3[] edges = new IndexedVector3[3]; int numEdges = 0; //compute face normals float maxCross2 = 0.0f; int chosenEdge = -1; do { int src = edge.GetSourceVertex(); m_polyhedron.m_faces[i].m_indices.Add(src); int targ = edge.GetTargetVertex(); IndexedVector3 wa = convexUtil.vertices[src]; IndexedVector3 wb = convexUtil.vertices[targ]; IndexedVector3 newEdge = wb - wa; newEdge.Normalize(); if (numEdges < 2) { edges[numEdges++] = newEdge; } edge = edge.GetNextEdgeOfFace(); } while (edge != firstEdge); float planeEq = 1e30f; if (numEdges == 2) { faceNormals[i] = IndexedVector3.Cross(edges[0], edges[1]); faceNormals[i].Normalize(); m_polyhedron.m_faces[i].m_plane[0] = -faceNormals[i].X; m_polyhedron.m_faces[i].m_plane[1] = -faceNormals[i].Y; m_polyhedron.m_faces[i].m_plane[2] = -faceNormals[i].Z; m_polyhedron.m_faces[i].m_plane[3] = planeEq; } else { Debug.Assert(false);//degenerate? faceNormals[i] = IndexedVector3.Zero; } for (int v = 0; v < m_polyhedron.m_faces[i].m_indices.Count; v++) { float eq = IndexedVector3.Dot(m_polyhedron.m_vertices[m_polyhedron.m_faces[i].m_indices[v]], faceNormals[i]); if (planeEq > eq) { planeEq = eq; } } m_polyhedron.m_faces[i].m_plane[3] = planeEq; } if (m_polyhedron.m_faces.Count > 0 && conv.vertices.Count > 0) { for (int f = 0; f < m_polyhedron.m_faces.Count; f++) { IndexedVector3 planeNormal = new IndexedVector3(m_polyhedron.m_faces[f].m_plane[0], m_polyhedron.m_faces[f].m_plane[1], m_polyhedron.m_faces[f].m_plane[2]); float planeEq = m_polyhedron.m_faces[f].m_plane[3]; IndexedVector3 supVec = LocalGetSupportingVertex(-planeNormal); if (IndexedVector3.Dot(supVec, planeNormal) < planeEq) { m_polyhedron.m_faces[f].m_plane[0] *= -1; m_polyhedron.m_faces[f].m_plane[1] *= -1; m_polyhedron.m_faces[f].m_plane[2] *= -1; m_polyhedron.m_faces[f].m_plane[3] *= -1; int numVerts = m_polyhedron.m_faces[f].m_indices.Count; for (int v = 0; v < numVerts / 2; v++) { int temp = m_polyhedron.m_faces[f].m_indices[v]; m_polyhedron.m_faces[f].m_indices[v] = m_polyhedron.m_faces[f].m_indices[numVerts - 1 - v]; m_polyhedron.m_faces[f].m_indices[numVerts - 1 - v] = temp; } } } } m_polyhedron.Initialize(); #endif return true; }
public virtual void CalculateOverlappingPairs(IDispatcher dispatcher) { if (m_pairCache.HasDeferredRemoval()) { ObjectArray <BroadphasePair> overlappingPairArray = m_pairCache.GetOverlappingPairArray(); //perform a sort, to find duplicates and to sort 'invalid' pairs to the end overlappingPairArray.QuickSort(new BroadphasePairQuickSort()); //overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; BroadphasePair previousPair = new BroadphasePair(); for (int i = 0; i < overlappingPairArray.Count; i++) { BroadphasePair pair = overlappingPairArray[i]; bool isDuplicate = pair.Equals(previousPair); // MAN - not sure if this should be a deep copy or not... previousPair = pair; bool needsRemoval = false; if (!isDuplicate) { ///important to use an AABB test that is consistent with the broadphase bool hasOverlap = TestAabbOverlap(pair.m_pProxy0, pair.m_pProxy1); if (hasOverlap) { needsRemoval = false;//callback.processOverlap(pair); } else { needsRemoval = true; } } else { //remove duplicate needsRemoval = true; //should have no algorithm Debug.Assert(pair.m_algorithm == null); } if (needsRemoval) { m_pairCache.CleanOverlappingPair(pair, dispatcher); // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); // m_overlappingPairArray.pop_back(); pair.m_pProxy0 = null; pair.m_pProxy1 = null; m_invalidPair++; OverlappingPairCacheGlobals.gOverlappingPairs--; } } ///if you don't like to skip the invalid pairs in the array, execute following code: #if CLEAN_INVALID_PAIRS overlappingPairArray.QuickSort(new BroadphasePairQuickSort()); overlappingPairArray.Resize(overlappingPairArray.Count - m_invalidPair); m_invalidPair = 0; #endif//CLEAN_INVALID_PAIRS //printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); } }
// Portable static method: prerequisite call: m_dynamicsWorld.getBroadphase().getOverlappingPairCache().setInternalGhostPairCallback(new btGhostPairCallback()); public static void GetCollidingObjectsInsidePairCachingGhostObject(DiscreteDynamicsWorld m_dynamicsWorld, PairCachingGhostObject m_pairCachingGhostObject, ObjectArray <CollisionObject> collisionArrayOut) { bool addOnlyObjectsWithNegativeDistance = true; // With "false" things don't change much, and the code is a bit faster and cleaner... collisionArrayOut.Resize(0); if (m_pairCachingGhostObject == null || m_dynamicsWorld == null) { return; } //#define USE_PLAIN_COLLISION_WORLD // We dispatch all collision pairs of the ghost object every step (slow) #if USE_PLAIN_COLLISION_WORLD //====================================================================================================== // I thought this line was no longer needed, but it seems to be necessary (and I believe it's an expensive call): m_dynamicsWorld.getDispatcher().dispatchAllCollisionPairs(m_pairCachingGhostObject.getOverlappingPairCache(), m_dynamicsWorld.getDispatchInfo(), m_dynamicsWorld.getDispatcher()); // Maybe the call can be automatically triggered by some other Bullet call (I'm almost sure I could comment it out in another demo I made long ago...) // So by now the general rule is: in real projects, simply comment it out and see if it works! //====================================================================================================== // UPDATE: in dynamic worlds, the line above can be commented out and the broadphase pair can be retrieved through the call to findPair(...) below. // In collision worlds probably the above line is needed only if collision detection for all the bodies hasn't been made... This is something // I'm still not sure of... the general rule is to try to comment out the line above and try to use findPair(...) and see if it works whenever possible.... //====================================================================================================== #endif //USE_PLAIN_COLLISION_WORLD ObjectArray <BroadphasePair> collisionPairs = m_pairCachingGhostObject.GetOverlappingPairCache().GetOverlappingPairArray(); int numObjects = collisionPairs.Count; PersistentManifoldArray m_manifoldArray = new PersistentManifoldArray(); bool added; for (int i = 0; i < numObjects; i++) { m_manifoldArray.Resize(0); #if USE_PLAIN_COLLISION_WORLD const btBroadphasePair& collisionPair = collisionPairs[i]; if (collisionPair.m_algorithm) { collisionPair.m_algorithm.getAllContactManifolds(m_manifoldArray); } else // THIS SHOULD NEVER HAPPEN, AND IF IT DOES, PLEASE RE-ENABLE the "call" a few lines above... { printf("No collisionPair.m_algorithm - probably m_dynamicsWorld.getDispatcher().dispatchAllCollisionPairs(...) must be missing.\n"); } #else // USE_PLAIN_COLLISION_WORLD BroadphasePair cPair = collisionPairs[i]; //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: BroadphasePair collisionPair = m_dynamicsWorld.GetPairCache().FindPair(cPair.m_pProxy0, cPair.m_pProxy1); if (collisionPair == null) { continue; } if (collisionPair.m_algorithm != null) { collisionPair.m_algorithm.GetAllContactManifolds(m_manifoldArray); } else { // THIS SHOULD NEVER HAPPEN, AND IF IT DOES, PLEASE RE-ENABLE the "call" a few lines above... //printf("No collisionPair.m_algorithm - probably m_dynamicsWorld.getDispatcher().dispatchAllCollisionPairs(...) must be missing.\n"); } #endif //USE_PLAIN_COLLISION_WORLD added = false; for (int j = 0; j < m_manifoldArray.Count; j++) { PersistentManifold manifold = m_manifoldArray[j]; // Here we are in the narrowphase, but can happen that manifold.getNumContacts()==0: if (addOnlyObjectsWithNegativeDistance) { for (int p = 0, numContacts = manifold.GetNumContacts(); p < numContacts; p++) { ManifoldPoint pt = manifold.GetContactPoint(p); if (pt.GetDistance() < 0.0) { // How can I be sure that the colObjs are all distinct ? I use the "added" flag. collisionArrayOut.Add((CollisionObject)(manifold.GetBody0() == m_pairCachingGhostObject ? manifold.GetBody1() : manifold.GetBody0())); added = true; break; } } if (added) { break; } } else if (manifold.GetNumContacts() > 0) { collisionArrayOut.Add((CollisionObject)(manifold.GetBody0() == m_pairCachingGhostObject ? manifold.GetBody1() : manifold.GetBody0())); break; } } } }