/// <summary> /// CollDetectCapsulseStaticMeshSweep /// </summary> /// <param name="oldCapsule"></param> /// <param name="newCapsule"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectCapsulseStaticMeshSweep(Capsule oldCapsule, Capsule newCapsule, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // really use a swept test - or overlap? Vector3 delta = newCapsule.Position - oldCapsule.Position; if (delta.LengthSquared < (0.25f * newCapsule.Radius * newCapsule.Radius)) { CollDetectCapsuleStaticMeshOverlap(oldCapsule, newCapsule, mesh, info, collTolerance, collisionFunctor); } else { float capsuleLen = oldCapsule.Length; float capsuleRadius = oldCapsule.Radius; int nSpheres = 2 + (int)(capsuleLen / (2.0f * oldCapsule.Radius)); for (int iSphere = 0; iSphere < nSpheres; ++iSphere) { float offset = ((float)iSphere) * capsuleLen / ((float)nSpheres - 1.0f); BoundingSphere oldSphere = new BoundingSphere(oldCapsule.Position + oldCapsule.Orientation.Backward() * offset, capsuleRadius); BoundingSphere newSphere = new BoundingSphere(newCapsule.Position + newCapsule.Orientation.Backward() * offset, capsuleRadius); CollDetectSphereStaticMesh.CollDetectSphereStaticMeshSweep(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor); } } }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule0 = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule; Capsule newCapsule0 = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule; Segment oldSeg0 = new Segment(oldCapsule0.Position, oldCapsule0.Length * oldCapsule0.Orientation.Backward); Segment newSeg0 = new Segment(newCapsule0.Position, newCapsule0.Length * newCapsule0.Orientation.Backward); Capsule oldCapsule1 = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Capsule; Capsule newCapsule1 = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Capsule; Segment oldSeg1 = new Segment(oldCapsule1.Position, oldCapsule1.Length * oldCapsule1.Orientation.Backward); Segment newSeg1 = new Segment(newCapsule1.Position, newCapsule1.Length * newCapsule1.Orientation.Backward); float radSum = newCapsule0.Radius + newCapsule1.Radius; float oldt0, oldt1; float newt0, newt1; float oldDistSq = Distance.SegmentSegmentDistanceSq(out oldt0, out oldt1, oldSeg0, oldSeg1); float newDistSq = Distance.SegmentSegmentDistanceSq(out newt0, out newt1, newSeg0, newSeg1); if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance))) { Vector3 pos0 = oldSeg0.GetPoint(oldt0); Vector3 pos1 = oldSeg1.GetPoint(oldt1); Vector3 delta = pos0 - pos1; float dist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radSum - dist; if (dist > JiggleMath.Epsilon) { delta /= dist; } else { // todo - make this not random delta = Vector3.TransformNormal(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360)))); } Vector3 worldPos = pos1 + (oldCapsule1.Radius - 0.5f * depth) * delta; #if WINDOWS_PHONE this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref delta, this.collInfo, 1); #else unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1); } #endif } }
/// <summary> /// CollDetectBoxStaticMeshOverlap /// </summary> /// <param name="oldBox"></param> /// <param name="newBox"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> /// <returns>bool</returns> private static bool CollDetectBoxStaticMeshOverlap(Box oldBox, Box newBox, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { float boxRadius = newBox.GetBoundingRadiusAroundCentre(); #region REFERENCE: Vector3 boxCentre = newBox.GetCentre(); Vector3 boxCentre; newBox.GetCentre(out boxCentre); // Deano need to trasnform the box center into mesh space Matrix invTransformMatrix = mesh.InverseTransformMatrix; Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre); #endregion BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddBox(newBox, ref bb); bool collision = false; int[] potTriArray = IntStackAlloc(); // aabox is done in mesh space and handles the mesh transform correctly int numTriangles = mesh.GetTrianglesIntersectingtAABox(potTriArray, MaxLocalStackTris, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potTriArray[iTriangle]); // quick early test is done in mesh space float dist = meshTriangle.Plane.DotCoordinate(boxCentre); // BEN-BUG-FIX: Fixed by chaning 0.0F to -boxRadius. if (dist > boxRadius || dist < -boxRadius) { continue; } if (DoOverlapBoxTriangleTest( oldBox, newBox, ref meshTriangle, mesh, ref info, collTolerance, collisionFunctor)) { collision = true; } } FreeStackAlloc(potTriArray); return(collision); }
private void CollDetectOverlap(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh, ref info, collTolerance, collisionFunctor); }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere; Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere; JigLibX.Geometry.Plane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JigLibX.Geometry.Plane; JigLibX.Geometry.Plane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JigLibX.Geometry.Plane; Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix; Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix; Vector3 oldSpherePos = Vector3.Transform(oldSphere.Position, oldPlaneInvTransform); Vector3 newSpherePos = Vector3.Transform(newSphere.Position, newPlaneInvTransform); // consider it a contact if either old or new are touching float oldDist = Distance.PointPlaneDistance(oldSpherePos, oldPlane); float newDist = Distance.PointPlaneDistance(newSpherePos, newPlane); if (System.Math.Min(newDist, oldDist) > collTolerance + newSphere.Radius) { return; } // collision - record depth using the old values float oldDepth = oldSphere.Radius - oldDist; // calc the world position based on the old position(s) Vector3 worldPos = oldSphere.Position - oldSphere.Radius * oldPlane.Normal; #if WINDOWS_PHONE this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, this.collInfo, 1); #else unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, &collInfo, 1); } #endif }
/// <summary> /// CollDetectSweep /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectSweep(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule; Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule; // todo - proper swept test // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; CollDetectCapsulseStaticMeshSweep(oldCapsule, newCapsule, mesh, info, collTolerance, collisionFunctor); }
private unsafe void Init(CollDetectInfo info, Vector3 dirToBody0, SmallCollPointInfo *pointInfos, int numPointInfos) { this.SkinInfo = info; this.dirToBody0 = dirToBody0; int ID0 = info.Skin0.GetMaterialID(info.IndexPrim0); int ID1 = info.Skin1.GetMaterialID(info.IndexPrim1); MaterialTable matTable = info.Skin0.CollisionSystem.MaterialTable; if (ID0 == (int)MaterialTable.MaterialID.UserDefined || (int)ID1 == (int)MaterialTable.MaterialID.UserDefined) { MaterialProperties prop0, prop1; if (ID0 == (int)MaterialTable.MaterialID.UserDefined) { prop0 = info.Skin0.GetMaterialProperties(info.IndexPrim0); } else { prop0 = matTable.GetMaterialProperties(ID0); } if (ID1 == (int)MaterialTable.MaterialID.UserDefined) { prop1 = info.Skin1.GetMaterialProperties(info.IndexPrim1); } else { prop1 = matTable.GetMaterialProperties(ID1); } MatPairProperties.Restitution = prop0.Elasticity * prop1.Elasticity; MatPairProperties.StaticFriction = prop0.StaticRoughness * prop1.StaticRoughness; MatPairProperties.DynamicFriction = prop0.DynamicRoughness * prop1.DynamicRoughness; } else { MatPairProperties = matTable.GetPairProperties(ID0, ID1); } numPointInfos = (numPointInfos > MaxCollisionPoints) ? MaxCollisionPoints : numPointInfos; NumCollPts = 0; for (int i = 0; i < numPointInfos; ++i) { if (freePtInfos.Count == 0) { freePtInfos.Push(new CollPointInfo()); } this.PointInfo[NumCollPts] = freePtInfos.Pop(); this.PointInfo[NumCollPts++].Init(ref pointInfos[i]); } }
public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule0 = (Capsule)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Capsule newCapsule0 = (Capsule)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); Segment oldSeg0 = new Segment(oldCapsule0.Position, oldCapsule0.Length * oldCapsule0.Orientation.Backward); Segment newSeg0 = new Segment(newCapsule0.Position, newCapsule0.Length * newCapsule0.Orientation.Backward); Capsule oldCapsule1 = (Capsule)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); Capsule newCapsule1 = (Capsule)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); Segment oldSeg1 = new Segment(oldCapsule1.Position, oldCapsule1.Length * oldCapsule1.Orientation.Backward); Segment newSeg1 = new Segment(newCapsule1.Position, newCapsule1.Length * newCapsule1.Orientation.Backward); float radSum = newCapsule0.Radius + newCapsule1.Radius; float oldt0, oldt1; float newt0, newt1; float oldDistSq = Distance.SegmentSegmentDistanceSq(out oldt0, out oldt1, oldSeg0, oldSeg1); float newDistSq = Distance.SegmentSegmentDistanceSq(out newt0, out newt1, newSeg0, newSeg1); if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance))) { Vector3 pos0 = oldSeg0.GetPoint(oldt0); Vector3 pos1 = oldSeg1.GetPoint(oldt1); Vector3 delta = pos0 - pos1; float dist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radSum - dist; if (dist > JiggleMath.Epsilon) { delta /= dist; } else { // todo - make this not random delta = Vector3.Transform(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360)))); } Vector3 worldPos = pos1 + (oldCapsule1.Radius - 0.5f * depth) * delta; unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1); } } }
/// <summary> /// DetectCollisions /// </summary> /// <param name="body"></param> /// <param name="collisionFunctor"></param> /// <param name="collisionPredicate"></param> /// <param name="collTolerance"></param> public override void DetectCollisions(JigLibX.Physics.Body body, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance) { if (!body.IsActive) { return; } CollDetectInfo info = new CollDetectInfo(); info.Skin0 = body.CollisionSkin; if (info.Skin0 == null) { return; } active_.Clear(); testing_.Clear(); Extract(info.Skin0.WorldBoundingBox.Min, info.Skin0.WorldBoundingBox.Max, active_); for (int j = 0, m = info.Skin0.NumPrimitives; j != m; ++j) { testing_.Add(info.Skin0.GetPrimitiveNewWorld(j)); } int nBodyPrims = testing_.Count; for (int i = 0, n = active_.Count; i != n; ++i) { info.Skin1 = active_[i]; if (info.Skin0 != info.Skin1 && (collisionPredicate == null || collisionPredicate.ConsiderSkinPair(info.Skin0, info.Skin1))) { int nPrim1 = info.Skin1.NumPrimitives; second_.Clear(); for (int k = 0; k != nPrim1; ++k) { second_.Add(info.Skin1.GetPrimitiveNewWorld(k)); } for (info.IndexPrim0 = 0; info.IndexPrim0 != nBodyPrims; ++info.IndexPrim0) { for (info.IndexPrim1 = 0; info.IndexPrim1 != nPrim1; ++info.IndexPrim1) { DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type, info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type); if (f != null) { f.CollDetect(info, collTolerance, collisionFunctor); } } } } } }
public static unsafe CollisionInfo GetCollisionInfo(CollDetectInfo info, Vector3 dirToBody0, SmallCollPointInfo *pointInfos, int numCollPts) { if (freeInfos.Count == 0) { freeInfos.Push(new CollisionInfo()); } var collInfo = freeInfos.Pop(); collInfo.Init(info, dirToBody0, pointInfos, numCollPts); return(collInfo); }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere0 = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Sphere newSphere0 = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); Sphere oldSphere1 = (Sphere)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); Sphere newSphere1 = (Sphere)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); Vector3 oldDelta = oldSphere0.Position - oldSphere1.Position; Vector3 newDelta = newSphere0.Position - oldSphere1.Position; float oldDistSq = oldDelta.LengthSquared(); float newDistSq = newDelta.LengthSquared(); float radSum = newSphere0.Radius + newSphere1.Radius; if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance))) { float oldDist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radSum - oldDist; if (oldDist > JiggleMath.Epsilon) { oldDelta /= oldDist; } else { // TODO - make this not random...! oldDelta = Vector3.TransformNormal(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360)))); } Vector3 worldPos = oldSphere1.Position + (oldSphere1.Radius - 0.5f * depth) * oldDelta; #if WINDOWS_PHONE this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref oldDelta, this.collInfo, 1); #else unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref oldDelta, &collInfo, 1); } #endif } }
/// <summary> /// CollDetectOverlap /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectOverlap(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // todo - proper swept test Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere; Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere; BoundingSphere oldBSphere = new BoundingSphere(oldSphere.Position, oldSphere.Radius); BoundingSphere newBSphere = new BoundingSphere(newSphere.Position, newSphere.Radius); // todo - proper swept test // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; CollDetectSphereStaticMeshOverlap(oldBSphere, newBSphere, mesh, info, collTolerance, collisionFunctor); }
/// <summary> /// CollDetect /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { CollDetectInfo info = infoOrig; if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere; Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere; Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap; Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap; float newDist; Vector3 normal; newHeightmap.GetHeightAndNormal(out newDist, out normal, newSphere.Position); if (newDist < collTolerance + newSphere.Radius) { float oldDist = oldHeightmap.GetHeight(oldSphere.Position); float depth = oldSphere.Radius - oldDist; // calc the world position when it just hit Vector3 oldPt = oldSphere.Position - oldSphere.Radius * normal; #if WINDOWS_PHONE ptInfo[0] = new SmallCollPointInfo(oldPt - body0Pos, oldPt - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref normal, ptInfo, 1); #else unsafe { SmallCollPointInfo ptInfo = new SmallCollPointInfo(oldPt - body0Pos, oldPt - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref normal, &ptInfo, 1); } #endif } }
/// <summary> /// CollisionInfos will be given out from a pool. If more than /// MaxCollisionPoints are passed in, the input positions will /// be silently truncated! /// </summary> /// <param name="info"></param> /// <param name="dirToBody0"></param> /// <param name="pointInfos"></param> /// <param name="numCollPts"></param> /// <returns>CollisionInfo</returns> public static CollisionInfo GetCollisionInfo(CollDetectInfo info, Vector3 dirToBody0, SmallCollPointInfo[] pointInfos, int numCollPts) { if (freeInfos.Count == 0) { freeInfos.Push(new CollisionInfo()); } CollisionInfo collInfo = freeInfos.Pop();//[freeInfos.Count - 1]; collInfo.Init(info, dirToBody0, pointInfos, numCollPts); //freeInfos.RemoveAt(freeInfos.Count - 1); return(collInfo); }
/// <summary> /// /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Sphere newSphere = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); JigLibX.Geometry.Plane oldPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); JigLibX.Geometry.Plane newPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix; Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix; Vector3 oldSpherePos = Vector3.Transform(oldSphere.Position, oldPlaneInvTransform); Vector3 newSpherePos = Vector3.Transform(newSphere.Position, newPlaneInvTransform); // consider it a contact if either old or new are touching float oldDist = Distance.PointPlaneDistance(oldSpherePos, oldPlane); float newDist = Distance.PointPlaneDistance(newSpherePos, newPlane); if (System.Math.Min(newDist, oldDist) > collTolerance + newSphere.Radius) return; // collision - record depth using the old values float oldDepth = oldSphere.Radius - oldDist; // calc the world position based on the old position(s) Vector3 worldPos = oldSphere.Position - oldSphere.Radius * oldPlane.Normal; unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, &collInfo, 1); } }
/// <summary> /// Detect BoxStaticMesh Collisions. /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } if (info.Skin0.CollisionSystem != null && info.Skin0.CollisionSystem.UseSweepTests) CollDetectSweep(ref info, collTolerance, collisionFunctor); else CollDetectOverlap(ref info, collTolerance, collisionFunctor); }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere0 = (Sphere) info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Sphere newSphere0 = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); Sphere oldSphere1 = (Sphere)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); Sphere newSphere1 = (Sphere)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); Vector3 oldDelta = oldSphere0.Position - oldSphere1.Position; Vector3 newDelta = newSphere0.Position - oldSphere1.Position; float oldDistSq = oldDelta.LengthSquared; float newDistSq = newDelta.LengthSquared; float radSum = newSphere0.Radius + newSphere1.Radius; if (System.Math.Min(oldDistSq, newDistSq) < ((radSum + collTolerance) * (radSum + collTolerance))) { float oldDist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radSum - oldDist; if (oldDist > JiggleMath.Epsilon) { oldDelta /= oldDist; } else { // TODO - make this not random...! oldDelta = Vector3Extensions.TransformNormal(Vector3Extensions.Backward, Matrix4.CreateFromAxisAngle(Vector3Extensions.Up, OpenTKHelper.ToRadians(random.Next(360)))); } Vector3 worldPos = oldSphere1.Position + (oldSphere1.Radius - 0.5f * depth) * oldDelta; unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref oldDelta, &collInfo, 1); } } }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // get the skins in the order that we're expecting if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } if((info.Skin0.CollisionSystem != null) && info.Skin0.CollisionSystem.UseSweepTests) CollDetectSweep(info, collTolerance, collisionFunctor); else CollDetectOverlap(info, collTolerance, collisionFunctor); }
/// <summary> /// /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { CollDetectInfo info = infoOrig; if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere = (Sphere)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Sphere newSphere = (Sphere)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); Heightmap oldHeightmap = (Heightmap)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); Heightmap newHeightmap = (Heightmap)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); float newDist; Vector3 normal; newHeightmap.GetHeightAndNormal(out newDist, out normal,newSphere.Position); if (newDist < collTolerance + newSphere.Radius) { float oldDist = oldHeightmap.GetHeight(oldSphere.Position); float depth = oldSphere.Radius - oldDist; // calc the world position when it just hit Vector3 oldPt = oldSphere.Position - oldSphere.Radius * normal; unsafe { SmallCollPointInfo ptInfo = new SmallCollPointInfo(oldPt - body0Pos, oldPt - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref normal, &ptInfo, 1); } } }
public override void DetectCollisions(Body body, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance) { if (!body.IsActive) { return; } CollDetectInfo info = new CollDetectInfo(); info.Skin0 = body.CollisionSkin; //?! if (info.Skin0 == null) { return; } int bodyPrimitves = info.Skin0.NumPrimitives; int numSkins = skins.Count; for (int skin = 0; skin < numSkins; ++skin) { info.Skin1 = skins[skin]; if ((info.Skin0 != info.Skin1) && CheckCollidables(info.Skin0, info.Skin1)) { int primitives = info.Skin1.NumPrimitives; for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitves; ++info.IndexPrim0) { for (info.IndexPrim1 = 0; info.IndexPrim1 < primitives; ++info.IndexPrim1) { DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type, info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type); if (f != null) { f.CollDetect(info, collTolerance, collisionFunctor); } } } } } }
/// <summary> /// Detect BoxStaticMesh Collisions. /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } if (info.Skin0.CollisionSystem != null && info.Skin0.CollisionSystem.UseSweepTests) { CollDetectSweep(ref info, collTolerance, collisionFunctor); } else { CollDetectOverlap(ref info, collTolerance, collisionFunctor); } }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // get the skins in the order that we're expecting if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } if ((info.Skin0.CollisionSystem != null) && info.Skin0.CollisionSystem.UseSweepTests) { CollDetectSweep(info, collTolerance, collisionFunctor); } else { CollDetectOverlap(info, collTolerance, collisionFunctor); } }
/// <summary> /// DoOverlapBoxTriangleTest /// </summary> /// <param name="oldBox"></param> /// <param name="newBox"></param> /// <param name="triangle"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> /// <returns>bool</returns> private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Matrix4 dirs0 = newBox.Orientation; #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2))); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0); mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1); mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2); // Deano move tri into world space Matrix4 transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); Triangle tri = new Triangle(ref triVec0, ref triVec1, ref triVec2); #endregion #region REFERENCE Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0)); Vector3 pt0; Vector3 pt1; tri.GetPoint(0, out pt0); tri.GetPoint(1, out pt1); Vector3 triEdge0; Vector3.Subtract(ref pt1, ref pt0, out triEdge0); #endregion #region REFERENCE Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1)); Vector3 pt2; tri.GetPoint(2, out pt2); Vector3 triEdge1; Vector3.Subtract(ref pt2, ref pt1, out triEdge1); #endregion #region REFERENCE Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2)); Vector3 triEdge2; Vector3.Subtract(ref pt0, ref pt2, out triEdge2); #endregion triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); // BEN-OPTIMISATION: Replaced loops with code that requires no looping. // The new code is faster, has less allocations and math especially // since the method returns as soon as it finds a non-overlapping axis, // i.e. Before irreleveat allocations occur. #region "Old (less efficient) code" /*Vector3 triNormal = triangle.Plane.Normal; * * // the 15 potential separating axes * const int numAxes = 13; * Vector3[] axes = new Vector3[numAxes]; * * axes[0] = triNormal; * axes[1] = dirs0.Right; * axes[2] = dirs0.Up; * axes[3] = dirs0.Backward; * Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]); * Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]); * Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]); * Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]); * Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]); * Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]); * Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]); * Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]); * Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]); * * // the overlap depths along each axis * float[] overlapDepths = new float[numAxes]; * * // see if the boxes are separate along any axis, and if not keep a * // record of the depths along each axis * int i; * for (i = 0; i < numAxes; ++i) * { * overlapDepths[i] = 1.0f; * if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance)) * return false; * } * * // The box overlap, find the separation depth closest to 0. * float minDepth = float.MaxValue; * int minAxis = -1; * * for (i = 0; i < numAxes; ++i) * { * // If we can't normalise the axis, skip it * float l2 = axes[i].LengthSquared; * if (l2 < JiggleMath.Epsilon) * continue; * * // Normalise the separation axis and the depth * float invl = 1.0f / (float)System.Math.Sqrt(l2); * axes[i] *= invl; * overlapDepths[i] *= invl; * * // If this axis is the minimum, select it * if (overlapDepths[i] < minDepth) * { * minDepth = overlapDepths[i]; * minAxis = i; * } * } * * if (minAxis == -1) * return false; * * // Make sure the axis is facing towards the 0th box. * // if not, invert it * Vector3 D = newBox.GetCentre() - tri.Centre; * Vector3 N = axes[minAxis]; * float depth = overlapDepths[minAxis];*/ #endregion #region "Optimised code" Vector3 triNormal = triangle.Plane.Normal; Vector3 right = dirs0.Right(); Vector3 up = dirs0.Up(); Vector3 backward = dirs0.Backward(); float testDepth; if (Disjoint(out testDepth, ref triNormal, newBox, ref tri, collTolerance)) { return(false); } float depth = testDepth; Vector3 N = triNormal; if (Disjoint(out testDepth, ref right, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = right; } if (Disjoint(out testDepth, ref up, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = up; } if (Disjoint(out testDepth, ref backward, newBox, ref tri, collTolerance)) { return(false); } if (testDepth < depth) { depth = testDepth; N = backward; } Vector3 axis; Vector3.Cross(ref right, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) { return(false); } testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } /*if (N == Vector3.Zero) * return (false);*/ Vector3 D = newBox.GetCentre() - tri.Centre; N.Normalize(); int i; #endregion if (Vector3.Dot(D, N) < 0.0f) { N *= -1; } Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; List <Vector3> pts = new List <Vector3>(); //pts.Clear(); const float combinationDist = 0.05f; GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist); // adjust the depth #region REFERENCE: Vector3 delta = boxNewPos - boxOldPos; Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N); float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion unsafe { // report collisions int numPts = pts.Count; #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { if (numPts > 0) { if (numPts >= MaxLocalStackSCPI) { numPts = MaxLocalStackSCPI - 1; } // adjust positions for (i = 0; i < numPts; ++i) { // BEN-OPTIMISATION: Reused existing SmallCollPointInfo and inlined vector substraction. collPts[i].R0.X = pts[i].X - boxNewPos.X; collPts[i].R0.Y = pts[i].Y - boxNewPos.Y; collPts[i].R0.Z = pts[i].Z - boxNewPos.Z; collPts[i].R1.X = pts[i].X - meshPos.X; collPts[i].R1.Y = pts[i].Y - meshPos.Y; collPts[i].R1.Z = pts[i].Z - meshPos.Z; collPts[i].InitialPenetration = oldDepth; } collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts); #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(true); } else { #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(false); } } } }
/// <summary> /// CollDetect /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { // get the skins in the order that we're expectiing CollDetectInfo info = infoOrig; if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule; Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule; Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward()); Segment newSeg = new Segment(newCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward()); float radius = oldCapsule.Radius; Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box; Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box; float oldSegT; float oldBoxT0, oldBoxT1, oldBoxT2; float oldDistSq = Distance.SegmentBoxDistanceSq(out oldSegT, out oldBoxT0, out oldBoxT1, out oldBoxT2, oldSeg, oldBox); float newSegT; float newBoxT0, newBoxT1, newBoxT2; float newDistSq = Distance.SegmentBoxDistanceSq(out newSegT, out newBoxT0, out newBoxT1, out newBoxT2, newSeg, newBox); if (OpenTKHelper.Min(oldDistSq, newDistSq) < ((radius + collTolerance) * (radius + collTolerance))) { Vector3 segPos = oldSeg.GetPoint(oldSegT); Vector3 boxPos = oldBox.GetCentre() + oldBoxT0 * oldBox.Orientation.Right() + oldBoxT1 * oldBox.Orientation.Up() + oldBoxT2 * oldBox.Orientation.Backward(); float dist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radius - dist; Vector3 dir; if (dist > JiggleMath.Epsilon) { dir = segPos - boxPos; JiggleMath.NormalizeSafe(ref dir); } else if ((segPos - oldBox.GetCentre()).LengthSquared > JiggleMath.Epsilon) { dir = segPos - oldBox.GetCentre(); JiggleMath.NormalizeSafe(ref dir); } else { // todo - make this not random dir = Vector3.Transform(Vector3Extensions.Backward, Matrix4.CreateFromAxisAngle(Vector3Extensions.Up, OpenTKHelper.ToRadians(random.Next(360)))); } unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(boxPos - body0Pos, boxPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1); } } }
/// <summary> /// CollisionInfos will be given out from a pool. If more than /// MaxCollisionPoints are passed in, the input positions will /// be silently truncated! /// </summary> /// <param name="info"></param> /// <param name="dirToBody0"></param> /// <param name="pointInfos"></param> /// <param name="numPointInfos"></param> /// <returns></returns> public static unsafe CollisionInfo GetCollisionInfo(CollDetectInfo info, Vector3 dirToBody0, SmallCollPointInfo* pointInfos, int numCollPts) { if (freeInfos.Count == 0) freeInfos.Push(new CollisionInfo()); CollisionInfo collInfo = freeInfos.Pop();//[freeInfos.Count - 1]; collInfo.Init(info, dirToBody0, pointInfos, numCollPts); //freeInfos.RemoveAt(freeInfos.Count - 1); return collInfo; }
/// <summary> /// CollDetectSphereStaticMeshOverlap /// </summary> /// <param name="oldSphere"></param> /// <param name="newSphere"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public static void CollDetectSphereStaticMeshOverlap(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float sphereTolR = collTolerance + newSphere.Radius; float sphereTolR2 = sphereTolR * sphereTolR; SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); int[] potTriArray = IntStackAlloc(); int numCollPts = 0; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddSphere(newSphere, ref bb); int numTriangles = mesh.GetTrianglesIntersectingtAABox(potTriArray, MaxLocalStackTris, ref bb); // Deano : get the spheres centers in triangle mesh space Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix); Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potTriArray[iTriangle]); float distToCentre = meshTriangle.Plane.DotCoordinate(newSphereCen); // BEN-BUG-FIX: Replaced 0.0f with -sphereTolR. if (distToCentre < -sphereTolR || distToCentre > sphereTolR) { continue; } int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2)); float s, t; float newD2 = Distance.PointTriangleDistanceSq(out s, out t, newSphereCen, triangle); if (newD2 < sphereTolR2) { // have overlap - but actually report the old intersection float oldD2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle); float dist = (float)System.Math.Sqrt((float)oldD2); float depth = oldSphere.Radius - dist; Vector3 triPointSTNorm = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref triPointSTNorm); Vector3 collisionN = (dist > float.Epsilon) ? triPointSTNorm : triangle.Normal; // since impulse get applied at the old position Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reuse existing collPts. collPtArray[numCollPts].R0 = pt - body0Pos; collPtArray[numCollPts].R1 = pt - body1Pos; collPtArray[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPtArray, numCollPts); } FreeStackAlloc(potTriArray); FreeStackAlloc(collPtArray); }
/// <summary> /// CollDetect /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { CollDetectInfo info = infoOrig; // get the skins in the order that we're expecting if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere; Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere; Capsule oldCapsule = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Capsule; Capsule newCapsule = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Capsule; Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward); Segment newSeg = new Segment(oldCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward); float radSum = newCapsule.Radius + newSphere.Radius; float oldt, newt; float oldDistSq = Distance.PointSegmentDistanceSq(out oldt, oldSphere.Position, oldSeg); float newDistSq = Distance.PointSegmentDistanceSq(out newt, newSphere.Position, newSeg); if (MathHelper.Min(oldDistSq, newDistSq) < (radSum + collTolerance) * (radSum + collTolerance)) { Vector3 segPos = oldSeg.GetPoint(oldt); Vector3 delta = oldSphere.Position - segPos; float dist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radSum - dist; if (dist > JiggleMath.Epsilon) { delta /= dist; } else { // todo - make this not random delta = Vector3.TransformNormal(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360)))); } Vector3 worldPos = segPos + ((oldCapsule.Radius - 0.5f * depth) * delta); #if WINDOWS_PHONE this.collInfo[0] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref delta, this.collInfo, 1); #else unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref delta, &collInfo, 1); } #endif } }
/// <summary> /// CollDetectSweep /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectSweep(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // todo - proper swept test // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; Vector3 oldCentre; oldBox.GetCentre(out oldCentre); Vector3 newCentre; newBox.GetCentre(out newCentre); Vector3 delta; Vector3.Subtract(ref newCentre, ref oldCentre, out delta); float boxMinLen = 0.5f * System.Math.Min(newBox.SideLengths.X, System.Math.Min(newBox.SideLengths.Y, newBox.SideLengths.Z)); int nPositions = 1 + (int)(delta.Length / boxMinLen); // limit the max positions... if (nPositions > 50) { System.Diagnostics.Debug.WriteLine("Warning - clamping max positions in swept box test"); nPositions = 50; } if (nPositions == 1) { CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh,ref info, collTolerance, collisionFunctor); } else { BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddBox(oldBox, ref bb); BoundingBoxHelper.AddBox(newBox, ref bb); unsafe { #if USE_STACKALLOC int* potentialTriangles = stackalloc int[MaxLocalStackTris]; { #else int[] potTriArray = IntStackAlloc(); fixed( int* potentialTriangles = potTriArray) { #endif int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); if (numTriangles > 0) { for (int i = 0; i <= nPositions; ++i) { float frac = ((float)i) / nPositions; Vector3 centre; Vector3.Multiply(ref delta, frac, out centre); Vector3.Add(ref centre, ref oldCentre, out centre); Matrix4 orient = Matrix4Extensions.Add(Matrix4Extensions.Multiply(oldBox.Orientation, 1.0f - frac), Matrix4Extensions.Multiply(newBox.Orientation, frac)); Box box = new Box(centre - 0.5f * Vector3Extensions.TransformNormal(newBox.SideLengths, orient), orient, newBox.SideLengths); // ideally we'd break if we get one collision... but that stops us getting multiple collisions // when we enter a corner (two walls meeting) - can let us pass through CollDetectBoxStaticMeshOverlap(oldBox, box, mesh, ref info, collTolerance, collisionFunctor); } } #if USE_STACKALLOC } #else } FreeStackAlloc(potTriArray); #endif } } }
private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Matrix dirs0 = newBox.Orientation; #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2))); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0); mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1); mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2); // Deano move tri into world space Matrix transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); Triangle tri = new Triangle(ref triVec0, ref triVec1, ref triVec2); #endregion #region qqfx Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0)); Vector3 pt0; Vector3 pt1; tri.GetPoint(0, out pt0); tri.GetPoint(1, out pt1); Vector3 triEdge0; Vector3.Subtract(ref pt1, ref pt1, out triEdge0); #endregion #region qqfx Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1)); Vector3 pt2; tri.GetPoint(2, out pt2); Vector3 triEdge1; Vector3.Subtract(ref pt2, ref pt1, out triEdge1); #endregion #region qqfx Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2)); Vector3 triEdge2; Vector3.Subtract(ref pt0, ref pt2, out triEdge2); #endregion triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); Vector3 triNormal = triangle.Plane.Normal; // the 15 potential separating axes const int numAxes = 13; Vector3[] axes = new Vector3[numAxes]; axes[0] = triNormal; axes[1] = dirs0.Right; axes[2] = dirs0.Up; axes[3] = dirs0.Backward; Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]); Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]); Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]); Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]); Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]); Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]); Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]); Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]); Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]); // the overlap depths along each axis float[] overlapDepths = new float[numAxes]; // see if the boxes are separate along any axis, and if not keep a // record of the depths along each axis int i; for (i = 0; i < numAxes; ++i) { overlapDepths[i] = 1.0f; if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance)) { return(false); } } // The box overlap, find the separation depth closest to 0. float minDepth = float.MaxValue; int minAxis = -1; for (i = 0; i < numAxes; ++i) { // If we can't normalise the axis, skip it float l2 = axes[i].LengthSquared(); if (l2 < JiggleMath.Epsilon) { continue; } // Normalise the separation axis and the depth float invl = 1.0f / (float)System.Math.Sqrt(l2); axes[i] *= invl; overlapDepths[i] *= invl; // If this axis is the minimum, select it if (overlapDepths[i] < minDepth) { minDepth = overlapDepths[i]; minAxis = i; } } if (minAxis == -1) { return(false); } // Make sure the axis is facing towards the 0th box. // if not, invert it Vector3 D = newBox.GetCentre() - tri.Centre; Vector3 N = axes[minAxis]; float depth = overlapDepths[minAxis]; if (Vector3.Dot(D, N) < 0.0f) { N *= -1; } Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; List <Vector3> pts = new List <Vector3>(); //pts.Clear(); const float combinationDist = 0.05f; GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist); // adjust the depth #region REFERENCE: Vector3 delta = boxNewPos - boxOldPos; Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N); float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion unsafe { // report collisions int numPts = pts.Count; #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { if (numPts > 0) { if (numPts >= MaxLocalStackSCPI) { numPts = MaxLocalStackSCPI - 1; } // adjust positions for (i = 0; i < numPts; ++i) { collPts[i] = new SmallCollPointInfo(pts[i] - boxNewPos, pts[i] - meshPos, oldDepth); } collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts); #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(true); } else { #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return(false); } } } }
/// <summary> /// CollDetectCapsuleStaticMeshOverlap /// </summary> /// <param name="oldCapsule"></param> /// <param name="newCapsule"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectCapsuleStaticMeshOverlap(Capsule oldCapsule, Capsule newCapsule, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float capsuleTolR = collTolerance + newCapsule.Radius; float capsuleTolR2 = capsuleTolR * capsuleTolR; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddCapsule(newCapsule, ref bb); unsafe { #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int* potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed (int* potentialTriangles = potTriArray) { #endif int numCollPts = 0; int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); Vector3 capsuleStart = newCapsule.Position; Vector3 capsuleEnd = newCapsule.GetEnd(); Matrix4 meshInvTransform = mesh.InverseTransformMatrix; Vector3 meshSpaceCapsuleStart = Vector3.Transform(capsuleStart, meshInvTransform); Vector3 meshSpaceCapsuleEnd = Vector3.Transform(capsuleEnd, meshInvTransform); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); // we do the plane test using the capsule in mesh space float distToStart = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleStart); float distToEnd = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleEnd); // BEN-BUG-FIX: Fixed by replacing 0.0F with -capsuleTolR. if ((distToStart > capsuleTolR && distToEnd > capsuleTolR) || (distToStart < -capsuleTolR && distToEnd < -capsuleTolR)) continue; // we now transform the triangle into world space (we could keep leave the mesh alone // but at this point 3 vector transforms is probably not a major slow down) int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; mesh.GetVertex(i0, out triVec0); mesh.GetVertex(i1, out triVec1); mesh.GetVertex(i2, out triVec2); // Deano move tri into world space Matrix4 transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); Triangle triangle = new Triangle(ref triVec0, ref triVec1, ref triVec2); Segment seg = new Segment(capsuleStart, capsuleEnd - capsuleStart); float tS, tT0, tT1; float d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, seg, triangle); if (d2 < capsuleTolR2) { Vector3 oldCapsuleStart = oldCapsule.Position; Vector3 oldCapsuleEnd = oldCapsule.GetEnd(); Segment oldSeg = new Segment(oldCapsuleStart, oldCapsuleEnd - oldCapsuleStart); d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, oldSeg, triangle); // report result from old position float dist = (float)System.Math.Sqrt(d2); float depth = oldCapsule.Radius - dist; Vector3 pt = triangle.GetPoint(tT0, tT1); Vector3 collisionN = (d2 > JiggleMath.Epsilon) ? JiggleMath.NormalizeSafe(oldSeg.GetPoint(tS) - pt) : meshTriangle.Plane.Normal; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reused existing collPts. collPts[numCollPts].R0 = pt - body0Pos; collPts[numCollPts].R1 = pt - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } #if USE_STACKALLOC } } #else } FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { CollDetectInfo info = infoOrig; if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule; Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule; Heightmap oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Heightmap; Heightmap newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Heightmap; unsafe { #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) #endif { int numCollPts = 0; Vector3 averageNormal = Vector3.Zero; // the start { float oldDist, newDist; Vector3 normal; oldHeightmap.GetHeightAndNormal(out oldDist, out normal, oldCapsule.Position); newHeightmap.GetHeightAndNormal(out newDist, out normal, newCapsule.Position); if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius) { float oldDepth = oldCapsule.Radius - oldDist; // calc the world position based on the old position(s) Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * normal; if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); } averageNormal += normal; } } // the end { Vector3 oldEnd = oldCapsule.GetEnd(); Vector3 newEnd = newCapsule.GetEnd(); float oldDist, newDist; Vector3 normal; oldHeightmap.GetHeightAndNormal(out oldDist, out normal, oldEnd); newHeightmap.GetHeightAndNormal(out newDist, out normal, newEnd); if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius) { float oldDepth = oldCapsule.Radius - oldDist; // calc the world position based on the old position(s) Vector3 worldPos = oldEnd - oldCapsule.Radius * normal; if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); } averageNormal += normal; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref averageNormal); collisionFunctor.CollisionNotify(ref info, ref averageNormal, collPts, numCollPts); } } #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// Detect BoxBox Collisions. /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Box box0 = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; Box box1 = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box; Box oldBox0 = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box oldBox1 = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box; Matrix dirs0 = box0.Orientation; Matrix dirs1 = box1.Orientation; seperatingAxes[0] = dirs0.Right; seperatingAxes[1] = dirs0.Up; seperatingAxes[2] = dirs0.Backward; seperatingAxes[3] = dirs1.Right; seperatingAxes[4] = dirs1.Up; seperatingAxes[5] = dirs1.Backward; Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[3], out seperatingAxes[6]); Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[4], out seperatingAxes[7]); Vector3.Cross(ref seperatingAxes[0], ref seperatingAxes[5], out seperatingAxes[8]); Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[3], out seperatingAxes[9]); Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[4], out seperatingAxes[10]); Vector3.Cross(ref seperatingAxes[1], ref seperatingAxes[5], out seperatingAxes[11]); Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[3], out seperatingAxes[12]); Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[4], out seperatingAxes[13]); Vector3.Cross(ref seperatingAxes[2], ref seperatingAxes[5], out seperatingAxes[14]); // see if the boxes are separate along any axis, and if not keep a // record of the depths along each axis int i; for (i = 0; i < 15; ++i) { // If we can't normalise the axis, skip it float l2 = seperatingAxes[i].LengthSquared(); if (l2 < JiggleMath.Epsilon) { continue; } overlapDepth[i] = float.MaxValue; if (Disjoint(out overlapDepth[i], ref seperatingAxes[i], box0, box1, collTolerance)) { return; } } // The box overlap, find the seperation depth closest to 0. float minDepth = float.MaxValue; int minAxis = -1; for (i = 0; i < 15; ++i) { // If we can't normalise the axis, skip it float l2 = seperatingAxes[i].LengthSquared(); if (l2 < JiggleMath.Epsilon) { continue; } // Normalise the separation axis and depth float invl = 1.0f / (float)System.Math.Sqrt(l2); seperatingAxes[i] *= invl; overlapDepth[i] *= invl; // If this axis is the minmum, select it if (overlapDepth[i] < minDepth) { minDepth = overlapDepth[i]; minAxis = i; } } if (minAxis == -1) { return; } // Make sure the axis is facing towards the 0th box. // if not, invert it Vector3 D = box1.GetCentre() - box0.GetCentre(); Vector3 N = seperatingAxes[minAxis]; float depth = overlapDepth[minAxis]; if (Vector3.Dot(D, N) > 0.0f) { N *= -1.0f; } float minA = MathHelper.Min(box0.SideLengths.X, MathHelper.Min(box0.SideLengths.Y, box0.SideLengths.Z)); float minB = MathHelper.Min(box1.SideLengths.X, MathHelper.Min(box1.SideLengths.Y, box1.SideLengths.Z)); float combinationDist = 0.05f * MathHelper.Min(minA, minB); // the contact points bool contactPointsFromOld = true; contactPts.Clear(); if (depth > -JiggleMath.Epsilon) { GetBoxBoxIntersectionPoints(contactPts, oldBox0, oldBox1, combinationDist, collTolerance); } int numPts = contactPts.Count; if (numPts == 0) { contactPointsFromOld = false; GetBoxBoxIntersectionPoints(contactPts, box0, box1, combinationDist, collTolerance); } numPts = contactPts.Count; Vector3 body0OldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1OldPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; Vector3 body0NewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 body1NewPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.Position : Vector3.Zero; #region REFERENCE: Vector3 bodyDelta = body0NewPos - body0OldPos - body1NewPos + body1OldPos; Vector3 bodyDelta; Vector3.Subtract(ref body0NewPos, ref body0OldPos, out bodyDelta); Vector3.Subtract(ref bodyDelta, ref body1NewPos, out bodyDelta); Vector3.Add(ref bodyDelta, ref body1OldPos, out bodyDelta); #endregion #region REFERENCE: float bodyDeltaLen = Vector3.Dot(bodyDelta,N); float bodyDeltaLen; Vector3.Dot(ref bodyDelta, ref N, out bodyDeltaLen); #endregion float oldDepth = depth + bodyDeltaLen; unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { int numCollPts = 0; Vector3 SATPoint; switch (minAxis) { // Box0 face, Box1 corner collision case 0: case 1: case 2: { // Get the lowest point on the box1 along box1 normal GetSupportPoint(out SATPoint, box1, -N); break; } // We have a Box2 corner/Box1 face collision case 3: case 4: case 5: { // Find with vertex on the triangle collided GetSupportPoint(out SATPoint, box0, N); break; } // We have an edge/edge collision case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: { { // Retrieve which edges collided. i = minAxis - 6; int ia = i / 3; int ib = i - ia * 3; // find two P0, P1 point on both edges. Vector3 P0, P1; GetSupportPoint(out P0, box0, N); GetSupportPoint(out P1, box1, -N); // Find the edge intersection. // plane along N and F, and passing through PB Vector3 box0Orient, box1Orient; JiggleUnsafe.Get(ref box0.transform.Orientation, ia, out box0Orient); JiggleUnsafe.Get(ref box1.transform.Orientation, ib, out box1Orient); #region REFERENCE: Vector3 planeNormal = Vector3.Cross(N, box1Orient[ib]); Vector3 planeNormal; Vector3.Cross(ref N, ref box1Orient, out planeNormal); #endregion #region REFERENCE: float planeD = Vector3.Dot(planeNormal, P1); float planeD; Vector3.Dot(ref planeNormal, ref P1, out planeD); #endregion // find the intersection t, where Pintersection = P0 + t*box edge dir #region REFERENCE: float div = Vector3.Dot(box0Orient, planeNormal); float div; Vector3.Dot(ref box0Orient, ref planeNormal, out div); #endregion // plane and ray colinear, skip the intersection. if (System.Math.Abs(div) < JiggleMath.Epsilon) { return; } float t = (planeD - Vector3.Dot(P0, planeNormal)) / div; // point on edge of box0 #region REFERENCE: P0 += box0Orient * t; P0 = Vector3.Add(Vector3.Multiply(box0Orient, t), P0); #endregion #region REFERENCE: SATPoint = (P0 + (0.5f * depth) * N); Vector3.Multiply(ref N, 0.5f * depth, out SATPoint); Vector3.Add(ref SATPoint, ref P0, out SATPoint); #endregion } break; } default: throw new Exception("Impossible switch"); } // distribute the depth according to the distance to the SAT point if (numPts > 0) { float minDist = float.MaxValue; float maxDist = float.MinValue; for (i = 0; i < numPts; ++i) { float dist = Distance.PointPointDistance(contactPts[i].Pos, SATPoint); if (dist < minDist) { minDist = dist; } if (dist > maxDist) { maxDist = dist; } } if (maxDist < minDist + JiggleMath.Epsilon) { maxDist = minDist + JiggleMath.Epsilon; } // got some intersection points for (i = 0; i < numPts; ++i) { float minDepthScale = 0.0f; float dist = Distance.PointPointDistance(contactPts[i].Pos, SATPoint); float depthDiv = System.Math.Max(JiggleMath.Epsilon, maxDist - minDist); float depthScale = (dist - minDist) / depthDiv; depth = (1.0f - depthScale) * oldDepth + minDepthScale * depthScale * oldDepth; if (contactPointsFromOld) { if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(contactPts[i].Pos - body0OldPos, contactPts[i].Pos - body1OldPos, depth); } } else { if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(contactPts[i].Pos - body0NewPos, contactPts[i].Pos - body1NewPos, depth); } } } } else { #region REFERENCE: collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth)); //collPts.Add(new CollPointInfo(SATPoint - body0NewPos, SATPoint - body1NewPos, oldDepth)); Vector3 cp0; Vector3.Subtract(ref SATPoint, ref body0NewPos, out cp0); Vector3 cp1; Vector3.Subtract(ref SATPoint, ref body1NewPos, out cp1); if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(ref cp0, ref cp1, oldDepth); } #endregion } // report Collisions collisionFunctor.CollisionNotify(ref info, ref N, collPts, numCollPts); } #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif } }
public override void DetectCollisions(Body body, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance) { if (!body.IsActive) return; CollDetectInfo info = new CollDetectInfo(); info.Skin0 = body.CollisionSkin; if (info.Skin0 == null) return; int bodyPrimitives = info.Skin0.NumPrimitives; int numSkins = skins.Count; for (int skin = 0; skin < numSkins; ++skin) { info.Skin1 = skins[skin]; if ((info.Skin0 != info.Skin1) && CheckCollidables(info.Skin0, info.Skin1)) { int primitives = info.Skin1.NumPrimitives; for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0) { for (info.IndexPrim1 = 0; info.IndexPrim1 < primitives; ++info.IndexPrim1) { DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type, info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type); if (f != null) f.CollDetect(info, collTolerance, collisionFunctor); } } } } }
public override void DetectAllCollisions(List<Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance) { int numBodies = bodies.Count; CollDetectInfo info = new CollDetectInfo(); for (int iBody = 0; iBody < numBodies; ++iBody) { Body body = bodies[iBody]; if (!body.IsActive) continue; info.Skin0 = body.CollisionSkin; if (info.Skin0 == null) continue; tempGridLists.Clear(); GetListsToCheck(tempGridLists, info.Skin0); for (int iList = tempGridLists.Count; iList-- != 0; ) { // first one is a placeholder; GridEntry entry = tempGridLists[iList]; for (entry = entry.Next; entry != null; entry = entry.Next) { info.Skin1 = entry.Skin; if (info.Skin1 == info.Skin0) continue; // CHANGE if (info.Skin1 == null) continue; bool skinSleeping = true; if ((info.Skin1.Owner != null) && (info.Skin1.Owner.IsActive)) skinSleeping = false; // only do one per pair if ((skinSleeping == false) && (info.Skin1.ID < info.Skin0.ID)) continue; if ((collisionPredicate != null) && (!collisionPredicate.ConsiderSkinPair(info.Skin0, info.Skin1))) continue; // basic bbox test if (BoundingBoxHelper.OverlapTest(ref info.Skin1.WorldBoundingBox, ref info.Skin0.WorldBoundingBox, collTolerance)) { if (CheckCollidables(info.Skin0, info.Skin1)) { int bodyPrimitives = info.Skin0.NumPrimitives; int primitves = info.Skin1.NumPrimitives; for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0) { for (info.IndexPrim1 = 0; info.IndexPrim1 < primitves; ++info.IndexPrim1) { DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type, info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type); if (f != null) f.CollDetect(info, collTolerance, collisionFunctor); } } } // check collidables } // overlapt test }// loop over entries } // loop over lists } // loop over bodies }
public static void CollDetectSphereStaticMeshOverlap(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float sphereTolR = collTolerance + newSphere.Radius; float sphereTolR2 = sphereTolR * sphereTolR; unsafe { #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int* potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed( int* potentialTriangles = potTriArray) { #endif int numCollPts = 0; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddSphere(newSphere, ref bb); int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); // Deano : get the spheres centers in triangle mesh space Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix); Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); float distToCentre = meshTriangle.Plane.DotCoordinate(newSphereCen); if (distToCentre <= 0.0f) continue; if (distToCentre >= sphereTolR) continue; int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2)); float s, t; float newD2 = Distance.PointTriangleDistanceSq(out s, out t, newSphereCen, triangle); if (newD2 < sphereTolR2) { // have overlap - but actually report the old intersection float oldD2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle); float dist = (float)System.Math.Sqrt((float)oldD2); float depth = oldSphere.Radius - dist; Vector3 triPointSTNorm = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref triPointSTNorm); Vector3 collisionN = (dist > float.Epsilon) ? triPointSTNorm : triangle.Normal; // since impulse get applied at the old position Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(pt - body0Pos, pt - body1Pos, depth); } collNormal += collisionN; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } #if USE_STACKALLOC } } #else FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); } #endif } }
public override void DetectAllCollisions(List <Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance) { int numSkins = skins.Count; int numBodies = bodies.Count; CollDetectInfo info = new CollDetectInfo(); for (int ibody = 0; ibody < numBodies; ++ibody) { Body body = bodies[ibody]; if (!body.IsActive) { continue; } info.Skin0 = body.CollisionSkin; if (info.Skin0 == null) { continue; } for (int skin = 0; skin < numSkins; ++skin) { info.Skin1 = skins[skin]; if (info.Skin0 == info.Skin1) { continue; } // CHANGE if (info.Skin1 == null) { continue; } bool skinSleeping = true; if (info.Skin1.Owner != null && info.Skin1.Owner.IsActive) { skinSleeping = false; } if ((skinSleeping == false) && (info.Skin1.ID < info.Skin0.ID)) { continue; } if ((collisionPredicate != null) && collisionPredicate.ConsiderSkinPair(info.Skin0, info.Skin1) == false) { continue; } // basic bbox test if (BoundingBoxHelper.OverlapTest(ref info.Skin0.WorldBoundingBox, ref info.Skin1.WorldBoundingBox, collTolerance)) { if (CheckCollidables(info.Skin0, info.Skin1)) { int bodyPrimitives = info.Skin0.NumPrimitives; int primitves = info.Skin1.NumPrimitives; for (info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0) { for (info.IndexPrim1 = 0; info.IndexPrim1 < primitves; ++info.IndexPrim1) { DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type, info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type); if (f != null) { f.CollDetect(info, collTolerance, collisionFunctor); } } } } } // overlapt test } // loop over skins } // loop over bodies } // void
/// <summary> /// CollDetectCapsuleStaticMeshOverlap /// </summary> /// <param name="oldCapsule"></param> /// <param name="newCapsule"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectCapsuleStaticMeshOverlap(Capsule oldCapsule, Capsule newCapsule, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float capsuleTolR = collTolerance + newCapsule.Radius; float capsuleTolR2 = capsuleTolR * capsuleTolR; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddCapsule(newCapsule, ref bb); unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int *potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed(int *potentialTriangles = potTriArray) { #endif int numCollPts = 0; int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); Vector3 capsuleStart = newCapsule.Position; Vector3 capsuleEnd = newCapsule.GetEnd(); Matrix meshInvTransform = mesh.InverseTransformMatrix; Vector3 meshSpaceCapsuleStart = Vector3.Transform(capsuleStart, meshInvTransform); Vector3 meshSpaceCapsuleEnd = Vector3.Transform(capsuleEnd, meshInvTransform); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); // we do the plane test using the capsule in mesh space float distToStart = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleStart); float distToEnd = meshTriangle.Plane.DotCoordinate(meshSpaceCapsuleEnd); // BEN-BUG-FIX: Fixed by replacing 0.0F with -capsuleTolR. if ((distToStart > capsuleTolR && distToEnd > capsuleTolR) || (distToStart < -capsuleTolR && distToEnd < -capsuleTolR)) { continue; } // we now transform the triangle into world space (we could keep leave the mesh alone // but at this point 3 vector transforms is probably not a major slow down) int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; mesh.GetVertex(i0, out triVec0); mesh.GetVertex(i1, out triVec1); mesh.GetVertex(i2, out triVec2); // Deano move tri into world space Matrix transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); Triangle triangle = new Triangle(ref triVec0, ref triVec1, ref triVec2); Segment seg = new Segment(capsuleStart, capsuleEnd - capsuleStart); float tS, tT0, tT1; float d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, seg, triangle); if (d2 < capsuleTolR2) { Vector3 oldCapsuleStart = oldCapsule.Position; Vector3 oldCapsuleEnd = oldCapsule.GetEnd(); Segment oldSeg = new Segment(oldCapsuleStart, oldCapsuleEnd - oldCapsuleStart); d2 = Distance.SegmentTriangleDistanceSq(out tS, out tT0, out tT1, oldSeg, triangle); // report result from old position float dist = (float)System.Math.Sqrt(d2); float depth = oldCapsule.Radius - dist; Vector3 pt = triangle.GetPoint(tT0, tT1); Vector3 collisionN = (d2 > JiggleMath.Epsilon) ? JiggleMath.NormalizeSafe(oldSeg.GetPoint(tS) - pt) : meshTriangle.Plane.Normal; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reused existing collPts. collPts[numCollPts].R0 = pt - body0Pos; collPts[numCollPts].R1 = pt - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } #if USE_STACKALLOC } } #else } FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule = (Capsule)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Capsule newCapsule = (Capsule)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); JigLibX.Geometry.Plane oldPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); JigLibX.Geometry.Plane newPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix; Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix; unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { int numCollPts = 0; // the start { Vector3 oldCapsuleStartPos = Vector3.Transform(oldCapsule.Position, oldPlaneInvTransform); Vector3 newCapsuleStartPos = Vector3.Transform(newCapsule.Position, newPlaneInvTransform); float oldDist = Distance.PointPlaneDistance(oldCapsuleStartPos, oldPlane); float newDist = Distance.PointPlaneDistance(newCapsuleStartPos, newPlane); if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius) { float oldDepth = oldCapsule.Radius - oldDist; // calc the world position based on the old position8(s) Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * oldPlane.Normal; collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); } } // the end { Vector3 oldCapsuleEndPos = Vector3.Transform(oldCapsule.GetEnd(), oldPlaneInvTransform); Vector3 newCapsuleEndPos = Vector3.Transform(newCapsule.GetEnd(), newPlaneInvTransform); float oldDist = Distance.PointPlaneDistance(oldCapsuleEndPos, oldPlane); float newDist = Distance.PointPlaneDistance(newCapsuleEndPos, newPlane); if (System.Math.Min(newDist, oldDist) < collTolerance + newCapsule.Radius) { float oldDepth = oldCapsule.Radius - oldDist; // calc the world position based on the old position(s) Vector3 worldPos = oldCapsule.GetEnd() - oldCapsule.Radius * oldPlane.Normal; collPts[numCollPts++] = new SmallCollPointInfo(worldPos - body0Pos, worldPos - body1Pos, oldDepth); } if (numCollPts > 0) { collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts); } } } #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// CollDetect /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { // get the skins in the order that we're expectiing CollDetectInfo info = infoOrig; if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule; Capsule newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule; Segment oldSeg = new Segment(oldCapsule.Position, oldCapsule.Length * oldCapsule.Orientation.Backward); Segment newSeg = new Segment(newCapsule.Position, newCapsule.Length * newCapsule.Orientation.Backward); float radius = oldCapsule.Radius; Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box; Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box; float oldSegT; float oldBoxT0, oldBoxT1, oldBoxT2; float oldDistSq = Distance.SegmentBoxDistanceSq(out oldSegT, out oldBoxT0, out oldBoxT1, out oldBoxT2,oldSeg, oldBox); float newSegT; float newBoxT0, newBoxT1, newBoxT2; float newDistSq = Distance.SegmentBoxDistanceSq(out newSegT, out newBoxT0, out newBoxT1, out newBoxT2,newSeg, newBox); if (MathHelper.Min(oldDistSq, newDistSq) < ((radius + collTolerance) * (radius + collTolerance))) { Vector3 segPos = oldSeg.GetPoint(oldSegT); Vector3 boxPos = oldBox.GetCentre() + oldBoxT0 * oldBox.Orientation.Right + oldBoxT1 * oldBox.Orientation.Up + oldBoxT2 * oldBox.Orientation.Backward; float dist = (float)System.Math.Sqrt((float)oldDistSq); float depth = radius - dist; Vector3 dir; if (dist > JiggleMath.Epsilon) { dir = segPos - boxPos; JiggleMath.NormalizeSafe(ref dir); } else if ((segPos - oldBox.GetCentre()).LengthSquared() > JiggleMath.Epsilon) { dir = segPos - oldBox.GetCentre(); JiggleMath.NormalizeSafe(ref dir); } else { // todo - make this not random dir = Vector3.Transform(Vector3.Backward, Matrix.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(random.Next(360)))); } unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(boxPos - body0Pos, boxPos - body1Pos, depth); collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1); } } }
private void CollDetectSweep(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // todo - proper swept test Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere; Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere; BoundingSphere oldBSphere = new BoundingSphere(oldSphere.Position, oldSphere.Radius); BoundingSphere newBSphere = new BoundingSphere(newSphere.Position, newSphere.Radius); // todo - proper swept test // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; CollDetectSphereStaticMeshSweep(oldBSphere, newBSphere, mesh, info, collTolerance, collisionFunctor); }
/// <summary> /// /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public abstract void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor);
private void CollDetectSweep(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // todo - proper swept test // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; Vector3 oldCentre; oldBox.GetCentre(out oldCentre); Vector3 newCentre; newBox.GetCentre(out newCentre); Vector3 delta; Vector3.Subtract(ref newCentre, ref oldCentre, out delta); float boxMinLen = 0.5f * System.Math.Min(newBox.SideLengths.X, System.Math.Min(newBox.SideLengths.Y, newBox.SideLengths.Z)); int nPositions = 1 + (int)(delta.Length() / boxMinLen); // limit the max positions... if (nPositions > 50) { System.Diagnostics.Debug.WriteLine("Warning - clamping max positions in swept box test"); nPositions = 50; } if (nPositions == 1) { CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh, ref info, collTolerance, collisionFunctor); } else { BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddBox(oldBox, ref bb); BoundingBoxHelper.AddBox(newBox, ref bb); unsafe { #if USE_STACKALLOC int *potentialTriangles = stackalloc int[MaxLocalStackTris]; { #else int[] potTriArray = IntStackAlloc(); fixed(int *potentialTriangles = potTriArray) { #endif int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); if (numTriangles > 0) { for (int i = 0; i <= nPositions; ++i) { float frac = ((float)i) / nPositions; Vector3 centre; Vector3.Multiply(ref delta, frac, out centre); Vector3.Add(ref centre, ref oldCentre, out centre); Matrix orient = Matrix.Add(Matrix.Multiply(oldBox.Orientation, 1.0f - frac), Matrix.Multiply(newBox.Orientation, frac)); Box box = new Box(centre - 0.5f * Vector3.Transform(newBox.SideLengths, orient), orient, newBox.SideLengths); // ideally we'd break if we get one collision... but that stops us getting multiple collisions // when we enter a corner (two walls meeting) - can let us pass through CollDetectBoxStaticMeshOverlap(oldBox, box, mesh, ref info, collTolerance, collisionFunctor); } } #if USE_STACKALLOC } #else } FreeStackAlloc(potTriArray); #endif } } }
/// <summary> /// Skins are passed back because there maybe more than one skin /// per body, and the user can always get the body from the skin. /// </summary> /// <param name="collDetectInfo"></param> /// <param name="dirToBody0"></param> /// <param name="pointInfos"></param> public unsafe abstract void CollisionNotify(ref CollDetectInfo collDetectInfo, ref Vector3 dirToBody0, SmallCollPointInfo* pointInfos, int numCollPts);
/// <summary> /// Detect BoxPlane Collisions. /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; JPlane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JPlane; JPlane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JPlane; Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix; Vector3 newBoxCen = Vector3.Transform(newBox.GetCentre(), newPlaneInvTransform); // quick check float centreDist = Distance.PointPlaneDistance(newBoxCen, newPlane); if (centreDist > collTolerance + newBox.GetBoundingRadiusAroundCentre()) { return; } Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix; Vector3[] newPts; newBox.GetCornerPoints(out newPts); Vector3[] oldPts; oldBox.GetCornerPoints(out oldPts); unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) #endif { int numCollPts = 0; for (int i = 0; i < 8; ++i) { Vector3.Transform(ref oldPts[i], ref oldPlaneInvTransform, out oldTransPts[i]); Vector3.Transform(ref newPts[i], ref newPlaneInvTransform, out newPts[i]); float oldDepth = -Distance.PointPlaneDistance(ref oldTransPts[i], oldPlane); float newDepth = -Distance.PointPlaneDistance(ref newPts[i], newPlane); if (MathHelper.Max(oldDepth, newDepth) > -collTolerance) { if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Now reuses instead of reallocating. collPts[numCollPts].R0 = oldPts[i] - body0Pos; collPts[numCollPts].R1 = oldPts[i] - body1Pos; collPts[numCollPts++].InitialPenetration = oldDepth; } } } if (numCollPts > 0) { collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts); } } #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// CollDetect /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper swept test Capsule oldCapsule = (Capsule)info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0); Capsule newCapsule = (Capsule)info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0); JigLibX.Geometry.Plane oldPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1); JigLibX.Geometry.Plane newPlane = (JigLibX.Geometry.Plane)info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1); Matrix newPlaneInvTransform = newPlane.InverseTransformMatrix; Matrix oldPlaneInvTransform = oldPlane.InverseTransformMatrix; unsafe { #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) #endif { int numCollPts = 0; // the start { Vector3 oldCapsuleStartPos = Vector3.Transform(oldCapsule.Position, oldPlaneInvTransform); Vector3 newCapsuleStartPos = Vector3.Transform(newCapsule.Position, newPlaneInvTransform); float oldDist = Distance.PointPlaneDistance(oldCapsuleStartPos, oldPlane); float newDist = Distance.PointPlaneDistance(newCapsuleStartPos, newPlane); if (MathHelper.Min(newDist, oldDist) < collTolerance + newCapsule.Radius) { float oldDepth = oldCapsule.Radius - oldDist; // calc the world position based on the old position8(s) Vector3 worldPos = oldCapsule.Position - oldCapsule.Radius * oldPlane.Normal; // BEN-OPTIMISATION: Now reuses existing collPts instead of reallocating. collPts[numCollPts].R0 = worldPos - body0Pos; collPts[numCollPts].R1 = worldPos - body1Pos; collPts[numCollPts++].InitialPenetration = oldDepth; } } // the end { Vector3 oldCapsuleEndPos = Vector3.Transform(oldCapsule.GetEnd(), oldPlaneInvTransform); Vector3 newCapsuleEndPos = Vector3.Transform(newCapsule.GetEnd(), newPlaneInvTransform); float oldDist = Distance.PointPlaneDistance(oldCapsuleEndPos, oldPlane); float newDist = Distance.PointPlaneDistance(newCapsuleEndPos, newPlane); if (System.Math.Min(newDist, oldDist) < collTolerance + newCapsule.Radius) { float oldDepth = oldCapsule.Radius - oldDist; // calc the world position based on the old position(s) Vector3 worldPos = oldCapsule.GetEnd() - oldCapsule.Radius * oldPlane.Normal; // BEN-OPTIMISATION: Now reuses existing collPts instead of reallocating. collPts[numCollPts].R0 = worldPos - body0Pos; collPts[numCollPts].R1 = worldPos - body1Pos; collPts[numCollPts++].InitialPenetration = oldDepth; } if (numCollPts > 0) { collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts); } } } #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif } }
/// <summary> /// CollDetect /// </summary> /// <param name="infoOrig"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo infoOrig, float collTolerance, CollisionFunctor collisionFunctor) { // get the skins in the order that we're expecting CollDetectInfo info = infoOrig; if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; // todo - proper sweep test Sphere oldSphere = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Sphere; Sphere newSphere = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Sphere; Box oldBox = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as Box; Box newBox = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as Box; Vector3 oldBoxPoint; Vector3 newBoxPoint; float oldDist = oldBox.GetDistanceToPoint(out oldBoxPoint, oldSphere.Position); float newDist = newBox.GetDistanceToPoint(out newBoxPoint, newSphere.Position); // normally point will be outside float oldDepth = oldSphere.Radius - oldDist; float newDepth = newSphere.Radius - newDist; if (System.Math.Max(oldDepth, newDepth) > -collTolerance) { Vector3 dir; if (oldDist < -JiggleMath.Epsilon) { dir = oldBoxPoint - oldSphere.Position - oldBoxPoint; JiggleMath.NormalizeSafe(ref dir); } else if (oldDist > JiggleMath.Epsilon) { dir = oldSphere.Position - oldBoxPoint; JiggleMath.NormalizeSafe(ref dir); } else { dir = oldSphere.Position - oldBox.GetCentre(); JiggleMath.NormalizeSafe(ref dir); } unsafe { SmallCollPointInfo collInfo = new SmallCollPointInfo(oldBoxPoint - body0Pos, oldBoxPoint - body1Pos, oldDepth); collisionFunctor.CollisionNotify(ref info, ref dir, &collInfo, 1); } } #endregion }
/// <summary> /// Detect BoxPlane Collisions. /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == this.Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; JPlane oldPlane = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as JPlane; JPlane newPlane = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as JPlane; Matrix4 newPlaneInvTransform = newPlane.InverseTransformMatrix; Vector3 newBoxCen = Vector3.Transform(newBox.GetCentre(), newPlaneInvTransform); // quick check float centreDist = Distance.PointPlaneDistance(newBoxCen, newPlane); if (centreDist > collTolerance + newBox.GetBoundingRadiusAroundCentre()) return; Matrix4 oldPlaneInvTransform = oldPlane.InverseTransformMatrix; Vector3[] newPts; newBox.GetCornerPoints(out newPts); Vector3[] oldPts; oldBox.GetCornerPoints(out oldPts); unsafe { #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) #endif { int numCollPts = 0; for (int i = 0; i < 8; ++i) { Vector3.Transform(ref oldPts[i], ref oldPlaneInvTransform, out oldTransPts[i]); Vector3.Transform(ref newPts[i], ref newPlaneInvTransform, out newPts[i]); float oldDepth = -Distance.PointPlaneDistance(ref oldTransPts[i], oldPlane); float newDepth = -Distance.PointPlaneDistance(ref newPts[i], newPlane); if (OpenTKHelper.Max(oldDepth, newDepth) > -collTolerance) { if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Now reuses instead of reallocating. collPts[numCollPts].R0 = oldPts[i] - body0Pos; collPts[numCollPts].R1 = oldPts[i] - body1Pos; collPts[numCollPts++].InitialPenetration = oldDepth; } } } if (numCollPts > 0) { collisionFunctor.CollisionNotify(ref info, ref oldPlane.normal, collPts, numCollPts); } } #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif } }
private unsafe void Init(CollDetectInfo info, Vector3 dirToBody0, SmallCollPointInfo* pointInfos, int numPointInfos) { this.SkinInfo = info; this.dirToBody0 = dirToBody0; int ID0 = info.Skin0.GetMaterialID(info.IndexPrim0); int ID1 = info.Skin1.GetMaterialID(info.IndexPrim1); MaterialTable matTable = info.Skin0.CollisionSystem.MaterialTable; if (ID0 == (int)MaterialTable.MaterialID.UserDefined || (int)ID1 == (int)MaterialTable.MaterialID.UserDefined) { MaterialProperties prop0 = info.Skin0.GetMaterialProperties(info.IndexPrim0); MaterialProperties prop1 = info.Skin1.GetMaterialProperties(info.IndexPrim1); MatPairProperties.Restitution = prop0.Elasticity * prop1.Elasticity; MatPairProperties.StaticFriction = prop0.StaticRoughness * prop1.StaticRoughness; MatPairProperties.DynamicFriction = prop0.DynamicRoughness * prop1.DynamicRoughness; } else { MatPairProperties = matTable.GetPairProperties(ID0, ID1); } numPointInfos = (numPointInfos > MaxCollisionPoints) ? MaxCollisionPoints : numPointInfos; NumCollPts = 0; for (int i = 0; i < numPointInfos; ++i) { if (freePtInfos.Count == 0) { freePtInfos.Push(new CollPointInfo()); } this.PointInfo[NumCollPts] = freePtInfos.Pop(); this.PointInfo[NumCollPts++].Init( ref pointInfos[i] ); } }
public unsafe override void CollisionNotify( ref CollDetectInfo collDetectInfo, ref Vector3 dirToBody0, SmallCollPointInfo* pointInfos, int numCollPts) { CollisionFunctorEntity.CollisionNotify(ref CollDetectInfoEntity, ref dirToBody0, pointInfos, numCollPts); }
/// <summary> /// Skins are passed back because there maybe more than one skin /// per body, and the user can always get the body from the skin. /// </summary> /// <param name="collDetectInfo"></param> /// <param name="dirToBody0"></param> /// <param name="pointInfos"></param> public unsafe abstract void CollisionNotify(ref CollDetectInfo collDetectInfo, ref Vector3 dirToBody0, SmallCollPointInfo *pointInfos, int numCollPts);
public override void CollDetect(CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { if (info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0).Type == Type1) { CollisionSkin skinSwap = info.Skin0; info.Skin0 = info.Skin1; info.Skin1 = skinSwap; int primSwap = info.IndexPrim0; info.IndexPrim0 = info.IndexPrim1; info.IndexPrim1 = primSwap; } var oldCapsule = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Capsule; var newCapsule = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Capsule; var oldHeightmap = info.Skin1.GetPrimitiveOldWorld(info.IndexPrim1) as CubeHeightmapCollisionShape; var newHeightmap = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as CubeHeightmapCollisionShape; Vector3[] oldPoints = new Vector3[2]; Vector3[] newPoints = new Vector3[2]; oldPoints[0] = oldCapsule.Position; oldPoints[1] = oldCapsule.GetEnd(); newPoints[0] = newCapsule.Position; newPoints[1] = newCapsule.GetEnd(); if (capsuleBoxDetectFunctor == null) { capsuleBoxDetectFunctor = PhysicsSystem.CurrentPhysicsSystem.CollisionSystem.GetCollDetectFunctor( (int) PrimitiveType.Capsule, (int) PrimitiveType.Box); } oldHeightmap.GetMapPositions(oldPoints, oldMapPositions); newHeightmap.GetMapPositions(newPoints, newMapPositions); // TODO: needed ? foreach (var oldMapPosition in oldMapPositions) { if (!newMapPositions.Contains(oldMapPosition)) { newMapPositions.Add(oldMapPosition); } } bool sameHeight = true; float prevHeight = newHeightmap.GetHeight(newMapPositions[0]); for (int i = 1; i < newMapPositions.Count; i++) { if (prevHeight != newHeightmap.GetHeight(newMapPositions[i])) { sameHeight = false; break; } } #region As plane if (sameHeight) { virtualPlaneSkin.SetMaterialProperties(0, info.Skin1.GetMaterialProperties(info.IndexPrim1)); var vcdi = new CollDetectInfo() { Skin0 = info.Skin0, Skin1 = virtualPlaneSkin, IndexPrim0 = info.IndexPrim0, IndexPrim1 = 0 }; virtualCollisionFunctor.CollisionFunctorEntity = collisionFunctor; virtualCollisionFunctor.CollDetectInfoEntity = info; var oldPlane = virtualPlaneSkin.GetPrimitiveOldWorld(0) as JPlane; var newPlane = virtualPlaneSkin.GetPrimitiveNewWorld(0) as JPlane; oldHeightmap.PrepareVirtualPlane(newMapPositions[0], oldPlane); newHeightmap.PrepareVirtualPlane(newMapPositions[0], newPlane); if (capsulePlaneDetectFunctor == null) { var collisionSystem = PhysicsSystem.CurrentPhysicsSystem.CollisionSystem; capsulePlaneDetectFunctor = collisionSystem.GetCollDetectFunctor( (int) PrimitiveType.Capsule, (int) PrimitiveType.Plane); } virtualCollisionFunctor.CollisionFunctorEntity = collisionFunctor; virtualCollisionFunctor.CollDetectInfoEntity = info; capsulePlaneDetectFunctor.CollDetect(vcdi, collTolerance, virtualCollisionFunctor); return; } #endregion #region As boxes virtualBoxSkin.SetMaterialProperties(0, info.Skin1.GetMaterialProperties(info.IndexPrim1)); CollDetectInfo virtualCollDetectInfo = new CollDetectInfo() { Skin0 = info.Skin0, Skin1 = virtualBoxSkin, IndexPrim0 = info.IndexPrim0, IndexPrim1 = 0 }; virtualCollisionFunctor.CollisionFunctorEntity = collisionFunctor; virtualCollisionFunctor.CollDetectInfoEntity = info; foreach (var newMapPosition in newMapPositions) { var oldPrimitive = virtualBoxSkin.GetPrimitiveOldWorld(0) as Box; var newPrimitive = virtualBoxSkin.GetPrimitiveNewWorld(0) as Box; oldHeightmap.PrepareVirtualBox(newMapPosition, oldPrimitive); newHeightmap.PrepareVirtualBox(newMapPosition, newPrimitive); capsuleBoxDetectFunctor.CollDetect(virtualCollDetectInfo, collTolerance, virtualCollisionFunctor); } #endregion }
/// <summary> /// DoOverlapBoxTriangleTest /// </summary> /// <param name="oldBox"></param> /// <param name="newBox"></param> /// <param name="triangle"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> /// <returns>bool</returns> private static bool DoOverlapBoxTriangleTest(Box oldBox, Box newBox, ref IndexedTriangle triangle, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { Matrix4 dirs0 = newBox.Orientation; #region REFERENCE: Triangle tri = new Triangle(mesh.GetVertex(triangle.GetVertexIndex(0)),mesh.GetVertex(triangle.GetVertexIndex(1)),mesh.GetVertex(triangle.GetVertexIndex(2))); Vector3 triVec0; Vector3 triVec1; Vector3 triVec2; mesh.GetVertex(triangle.GetVertexIndex(0), out triVec0); mesh.GetVertex(triangle.GetVertexIndex(1), out triVec1); mesh.GetVertex(triangle.GetVertexIndex(2), out triVec2); // Deano move tri into world space Matrix4 transformMatrix = mesh.TransformMatrix; Vector3.Transform(ref triVec0, ref transformMatrix, out triVec0); Vector3.Transform(ref triVec1, ref transformMatrix, out triVec1); Vector3.Transform(ref triVec2, ref transformMatrix, out triVec2); Triangle tri = new Triangle(ref triVec0,ref triVec1,ref triVec2); #endregion #region REFERENCE Vector3 triEdge0 = (tri.GetPoint(1) - tri.GetPoint(0)); Vector3 pt0; Vector3 pt1; tri.GetPoint(0, out pt0); tri.GetPoint(1, out pt1); Vector3 triEdge0; Vector3.Subtract(ref pt1, ref pt0, out triEdge0); #endregion #region REFERENCE Vector3 triEdge1 = (tri.GetPoint(2) - tri.GetPoint(1)); Vector3 pt2; tri.GetPoint(2, out pt2); Vector3 triEdge1; Vector3.Subtract(ref pt2, ref pt1, out triEdge1); #endregion #region REFERENCE Vector3 triEdge2 = (tri.GetPoint(0) - tri.GetPoint(2)); Vector3 triEdge2; Vector3.Subtract(ref pt0, ref pt2, out triEdge2); #endregion triEdge0.Normalize(); triEdge1.Normalize(); triEdge2.Normalize(); // BEN-OPTIMISATION: Replaced loops with code that requires no looping. // The new code is faster, has less allocations and math especially // since the method returns as soon as it finds a non-overlapping axis, // i.e. Before irreleveat allocations occur. #region "Old (less efficient) code" /*Vector3 triNormal = triangle.Plane.Normal; // the 15 potential separating axes const int numAxes = 13; Vector3[] axes = new Vector3[numAxes]; axes[0] = triNormal; axes[1] = dirs0.Right; axes[2] = dirs0.Up; axes[3] = dirs0.Backward; Vector3.Cross(ref axes[1], ref triEdge0, out axes[4]); Vector3.Cross(ref axes[1], ref triEdge1, out axes[5]); Vector3.Cross(ref axes[1], ref triEdge2, out axes[6]); Vector3.Cross(ref axes[2], ref triEdge0, out axes[7]); Vector3.Cross(ref axes[2], ref triEdge1, out axes[8]); Vector3.Cross(ref axes[2], ref triEdge2, out axes[9]); Vector3.Cross(ref axes[3], ref triEdge0, out axes[10]); Vector3.Cross(ref axes[3], ref triEdge1, out axes[11]); Vector3.Cross(ref axes[3], ref triEdge2, out axes[12]); // the overlap depths along each axis float[] overlapDepths = new float[numAxes]; // see if the boxes are separate along any axis, and if not keep a // record of the depths along each axis int i; for (i = 0; i < numAxes; ++i) { overlapDepths[i] = 1.0f; if (Disjoint(out overlapDepths[i], axes[i], newBox, tri, collTolerance)) return false; } // The box overlap, find the separation depth closest to 0. float minDepth = float.MaxValue; int minAxis = -1; for (i = 0; i < numAxes; ++i) { // If we can't normalise the axis, skip it float l2 = axes[i].LengthSquared; if (l2 < JiggleMath.Epsilon) continue; // Normalise the separation axis and the depth float invl = 1.0f / (float)System.Math.Sqrt(l2); axes[i] *= invl; overlapDepths[i] *= invl; // If this axis is the minimum, select it if (overlapDepths[i] < minDepth) { minDepth = overlapDepths[i]; minAxis = i; } } if (minAxis == -1) return false; // Make sure the axis is facing towards the 0th box. // if not, invert it Vector3 D = newBox.GetCentre() - tri.Centre; Vector3 N = axes[minAxis]; float depth = overlapDepths[minAxis];*/ #endregion #region "Optimised code" Vector3 triNormal = triangle.Plane.Normal; Vector3 right = dirs0.Right(); Vector3 up = dirs0.Up(); Vector3 backward = dirs0.Backward(); float testDepth; if (Disjoint(out testDepth, ref triNormal, newBox, ref tri, collTolerance)) return (false); float depth = testDepth; Vector3 N = triNormal; if (Disjoint(out testDepth, ref right, newBox, ref tri, collTolerance)) return (false); if (testDepth < depth) { depth = testDepth; N = right; } if (Disjoint(out testDepth, ref up, newBox, ref tri, collTolerance)) return (false); if (testDepth < depth) { depth = testDepth; N = up; } if (Disjoint(out testDepth, ref backward, newBox, ref tri, collTolerance)) return (false); if (testDepth < depth) { depth = testDepth; N = backward; } Vector3 axis; Vector3.Cross(ref right, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref right, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref up, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge0, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge1, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } Vector3.Cross(ref backward, ref triEdge2, out axis); if (Disjoint(out testDepth, ref axis, newBox, ref tri, collTolerance)) return (false); testDepth *= 1.0f / (float)System.Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z); if (testDepth < depth) { depth = testDepth; N = axis; } /*if (N == Vector3.Zero) return (false);*/ Vector3 D = newBox.GetCentre() - tri.Centre; N.Normalize(); int i; #endregion if (Vector3.Dot(D, N) < 0.0f) N *= -1; Vector3 boxOldPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 boxNewPos = (info.Skin0.Owner != null) ? info.Skin0.Owner.Position : Vector3.Zero; Vector3 meshPos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; List<Vector3> pts = new List<Vector3>(); //pts.Clear(); const float combinationDist = 0.05f; GetBoxTriangleIntersectionPoints(pts, newBox, tri, depth + combinationDist); // adjust the depth #region REFERENCE: Vector3 delta = boxNewPos - boxOldPos; Vector3 delta; Vector3.Subtract(ref boxNewPos, ref boxOldPos, out delta); #endregion #region REFERENCE: float oldDepth = depth + Vector3.Dot(delta, N); float oldDepth; Vector3.Dot(ref delta, ref N, out oldDepth); oldDepth += depth; #endregion unsafe { // report collisions int numPts = pts.Count; #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) #endif { if (numPts > 0) { if (numPts >= MaxLocalStackSCPI) { numPts = MaxLocalStackSCPI - 1; } // adjust positions for (i = 0; i < numPts; ++i) { // BEN-OPTIMISATION: Reused existing SmallCollPointInfo and inlined vector substraction. collPts[i].R0.X = pts[i].X - boxNewPos.X; collPts[i].R0.Y = pts[i].Y - boxNewPos.Y; collPts[i].R0.Z = pts[i].Z - boxNewPos.Z; collPts[i].R1.X = pts[i].X - meshPos.X; collPts[i].R1.Y = pts[i].Y - meshPos.Y; collPts[i].R1.Z = pts[i].Z - meshPos.Z; collPts[i].InitialPenetration = oldDepth; } collisionFunctor.CollisionNotify(ref info, ref N, collPts, numPts); #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return true; } else { #if !USE_STACKALLOC FreeStackAlloc(collPtArray); #endif return false; } } } }
/// <summary> /// DetectAllCollisions /// </summary> /// <param name="bodies"></param> /// <param name="collisionFunctor"></param> /// <param name="collisionPredicate"></param> /// <param name="collTolerance"></param> public override void DetectAllCollisions(List<Body> bodies, CollisionFunctor collisionFunctor, CollisionSkinPredicate2 collisionPredicate, float collTolerance) { int numSkins = skins.Count; int numBodies = bodies.Count; CollDetectInfo info = new CollDetectInfo(); for (int ibody = 0; ibody < numBodies; ++ibody) { Body body = bodies[ibody]; if(!body.IsActive) continue; info.Skin0 = body.CollisionSkin; if (info.Skin0 == null) continue; for (int skin = 0; skin < numSkins; ++skin) { info.Skin1 = skins[skin]; if (info.Skin0 == info.Skin1) continue; // CHANGE if (info.Skin1 == null) continue; bool skinSleeping = true; if (info.Skin1.Owner != null && info.Skin1.Owner.IsActive) skinSleeping = false; if ((skinSleeping == false) && (info.Skin1.ID < info.Skin0.ID)) continue; if((collisionPredicate != null) && collisionPredicate.ConsiderSkinPair(info.Skin0,info.Skin1) == false) continue; // basic bbox test if(BoundingBoxHelper.OverlapTest(ref info.Skin0.WorldBoundingBox, ref info.Skin1.WorldBoundingBox,collTolerance)) { if (CheckCollidables(info.Skin0,info.Skin1)) { int bodyPrimitives = info.Skin0.NumPrimitives; int primitves = info.Skin1.NumPrimitives; for(info.IndexPrim0 = 0; info.IndexPrim0 < bodyPrimitives; ++info.IndexPrim0) { for (info.IndexPrim1 = 0; info.IndexPrim1 < primitves; ++info.IndexPrim1) { DetectFunctor f = GetCollDetectFunctor(info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0).Type, info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1).Type); if (f != null) f.CollDetect(info, collTolerance, collisionFunctor); } } } } // overlapt test } // loop over skins } // loop over bodies }
/// <summary> /// CollDetectOverlap /// </summary> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> private void CollDetectOverlap(ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // note - mesh is static and its triangles are in world space TriangleMesh mesh = info.Skin1.GetPrimitiveNewWorld(info.IndexPrim1) as TriangleMesh; Box oldBox = info.Skin0.GetPrimitiveOldWorld(info.IndexPrim0) as Box; Box newBox = info.Skin0.GetPrimitiveNewWorld(info.IndexPrim0) as Box; CollDetectBoxStaticMeshOverlap(oldBox, newBox, mesh, ref info, collTolerance, collisionFunctor); }
/// <summary> /// CollDetectSphereStaticMeshSweep /// </summary> /// <param name="oldSphere"></param> /// <param name="newSphere"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> internal static void CollDetectSphereStaticMeshSweep(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // really use a swept test - or overlap? Vector3 delta = newSphere.Center - oldSphere.Center; if (delta.LengthSquared() < (0.25f * newSphere.Radius * newSphere.Radius)) { CollDetectSphereStaticMeshOverlap(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor); } else { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float sphereTolR = collTolerance + oldSphere.Radius; float sphereToR2 = sphereTolR * sphereTolR; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddSphere(oldSphere, ref bb); BoundingBoxHelper.AddSphere(newSphere, ref bb); // get the spheres centers in triangle mesh space Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix); Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix); unsafe { #if USE_STACKALLOC SmallCollPointInfo *collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int *potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed(SmallCollPointInfo *collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed(int *potentialTriangles = potTriArray) { #endif int numCollPts = 0; int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { // first test the old sphere for being on the wrong side IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); float distToCentreOld = meshTriangle.Plane.DotCoordinate(oldSphereCen); if (distToCentreOld <= 0.0f) { continue; } // now test the new sphere for being clear float distToCentreNew = meshTriangle.Plane.DotCoordinate(newSphereCen); if (distToCentreNew > sphereTolR) { continue; } int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2)); // If the old sphere is intersecting, just use that result float s, t; float d2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle); if (d2 < sphereToR2) { float dist = (float)System.Math.Sqrt(d2); float depth = oldSphere.Radius - dist; Vector3 triangleN = triangle.Normal; Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref normSafe); Vector3 collisionN = (dist > float.Epsilon) ? normSafe : triangleN; // since impulse gets applied at the old position Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reuse existing collPts. collPts[numCollPts].R0 = pt - body0Pos; collPts[numCollPts].R1 = pt - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } else if (distToCentreNew < distToCentreOld) { // old sphere is not intersecting - do a sweep, but only if the sphere is moving into the // triangle Vector3 pt, N; // CHECK THIS float depth; if (Intersection.SweptSphereTriangleIntersection(out pt, out N, out depth, oldSphere, newSphere, triangle, distToCentreOld, distToCentreNew, Intersection.EdgesToTest.EdgeAll, Intersection.CornersToTest.CornerAll)) { // collision point etc must be relative to the old position because that's //where the impulses are applied float dist = (float)System.Math.Sqrt(d2); float depth2 = oldSphere.Radius - dist; Vector3 triangleN = triangle.Normal; Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref normSafe); Vector3 collisionN = (dist > JiggleMath.Epsilon) ? normSafe : triangleN; // since impulse gets applied at the old position Vector3 pt2 = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { // BEN-OPTIMISATION: Reuse existing collPts. collPts[numCollPts].R0 = pt2 - body0Pos; collPts[numCollPts].R1 = pt2 - body1Pos; collPts[numCollPts++].InitialPenetration = depth; } collNormal += collisionN; } } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } } #if USE_STACKALLOC } } #else FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); } #endif } }
/// <summary> /// CollDetectBoxStaticMeshOverlap /// </summary> /// <param name="oldBox"></param> /// <param name="newBox"></param> /// <param name="mesh"></param> /// <param name="info"></param> /// <param name="collTolerance"></param> /// <param name="collisionFunctor"></param> /// <returns>bool</returns> private static bool CollDetectBoxStaticMeshOverlap(Box oldBox, Box newBox, TriangleMesh mesh, ref CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { float boxRadius = newBox.GetBoundingRadiusAroundCentre(); #region REFERENCE: Vector3 boxCentre = newBox.GetCentre(); Vector3 boxCentre; newBox.GetCentre(out boxCentre); // Deano need to trasnform the box center into mesh space Matrix4 invTransformMatrix = mesh.InverseTransformMatrix; Vector3.Transform(ref boxCentre, ref invTransformMatrix, out boxCentre); #endregion BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddBox(newBox, ref bb); unsafe { bool collision = false; #if USE_STACKALLOC int* potentialTriangles = stackalloc int[MaxLocalStackTris]; { #else int[] potTriArray = IntStackAlloc(); fixed( int* potentialTriangles = potTriArray) { #endif // aabox is done in mesh space and handles the mesh transform correctly int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); // quick early test is done in mesh space float dist = meshTriangle.Plane.DotCoordinate(boxCentre); // BEN-BUG-FIX: Fixed by chaning 0.0F to -boxRadius. if (dist > boxRadius || dist < -boxRadius) continue; if (DoOverlapBoxTriangleTest( oldBox, newBox, ref meshTriangle, mesh, ref info, collTolerance, collisionFunctor)) { collision = true; } } #if USE_STACKALLOC } #else } FreeStackAlloc(potTriArray); #endif return collision; } }
internal static void CollDetectSphereStaticMeshSweep(BoundingSphere oldSphere, BoundingSphere newSphere, TriangleMesh mesh, CollDetectInfo info, float collTolerance, CollisionFunctor collisionFunctor) { // really use a swept test - or overlap? Vector3 delta = newSphere.Center - oldSphere.Center; if (delta.LengthSquared() < (0.25f * newSphere.Radius * newSphere.Radius)) { CollDetectSphereStaticMeshOverlap(oldSphere, newSphere, mesh, info, collTolerance, collisionFunctor); } else { Vector3 body0Pos = (info.Skin0.Owner != null) ? info.Skin0.Owner.OldPosition : Vector3.Zero; Vector3 body1Pos = (info.Skin1.Owner != null) ? info.Skin1.Owner.OldPosition : Vector3.Zero; float sphereTolR = collTolerance + oldSphere.Radius; float sphereToR2 = sphereTolR * sphereTolR; Vector3 collNormal = Vector3.Zero; BoundingBox bb = BoundingBoxHelper.InitialBox; BoundingBoxHelper.AddSphere(oldSphere, ref bb); BoundingBoxHelper.AddSphere(newSphere, ref bb); // get the spheres centers in triangle mesh space Vector3 newSphereCen = Vector3.Transform(newSphere.Center, mesh.InverseTransformMatrix); Vector3 oldSphereCen = Vector3.Transform(oldSphere.Center, mesh.InverseTransformMatrix); unsafe { #if USE_STACKALLOC SmallCollPointInfo* collPts = stackalloc SmallCollPointInfo[MaxLocalStackSCPI]; int* potentialTriangles = stackalloc int[MaxLocalStackTris]; { { #else SmallCollPointInfo[] collPtArray = SCPIStackAlloc(); fixed (SmallCollPointInfo* collPts = collPtArray) { int[] potTriArray = IntStackAlloc(); fixed( int* potentialTriangles = potTriArray) { #endif int numCollPts = 0; int numTriangles = mesh.GetTrianglesIntersectingtAABox(potentialTriangles, MaxLocalStackTris, ref bb); for (int iTriangle = 0; iTriangle < numTriangles; ++iTriangle) { // first test the old sphere for being on the wrong side IndexedTriangle meshTriangle = mesh.GetTriangle(potentialTriangles[iTriangle]); float distToCentreOld = meshTriangle.Plane.DotCoordinate(oldSphereCen); if (distToCentreOld <= 0.0f) continue; // now test the new sphere for being clear float distToCentreNew = meshTriangle.Plane.DotCoordinate(newSphereCen); if (distToCentreNew > sphereTolR) continue; int i0, i1, i2; meshTriangle.GetVertexIndices(out i0, out i1, out i2); Triangle triangle = new Triangle(mesh.GetVertex(i0), mesh.GetVertex(i1), mesh.GetVertex(i2)); // If the old sphere is intersecting, just use that result float s, t; float d2 = Distance.PointTriangleDistanceSq(out s, out t, oldSphereCen, triangle); if (d2 < sphereToR2) { float dist = (float)System.Math.Sqrt(d2); float depth = oldSphere.Radius - dist; Vector3 triangleN = triangle.Normal; Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref normSafe); Vector3 collisionN = (dist > float.Epsilon) ? normSafe : triangleN; // since impulse gets applied at the old position Vector3 pt = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(pt - body0Pos, pt - body1Pos, depth); } collNormal += collisionN; } else if (distToCentreNew < distToCentreOld) { // old sphere is not intersecting - do a sweep, but only if the sphere is moving into the // triangle Vector3 pt, N; // CHECK THIS float depth; if (Intersection.SweptSphereTriangleIntersection(out pt, out N, out depth, oldSphere, newSphere, triangle, distToCentreOld, distToCentreNew, Intersection.EdgesToTest.EdgeAll, Intersection.CornersToTest.CornerAll)) { // collision point etc must be relative to the old position because that's //where the impulses are applied float dist = (float)System.Math.Sqrt(d2); float depth2 = oldSphere.Radius - dist; Vector3 triangleN = triangle.Normal; Vector3 normSafe = oldSphereCen - triangle.GetPoint(s, t); JiggleMath.NormalizeSafe(ref normSafe); Vector3 collisionN = (dist > JiggleMath.Epsilon) ? normSafe : triangleN; // since impulse gets applied at the old position Vector3 pt2 = oldSphere.Center - oldSphere.Radius * collisionN; if (numCollPts < MaxLocalStackSCPI) { collPts[numCollPts++] = new SmallCollPointInfo(pt2 - body0Pos, pt2 - body1Pos, depth); } collNormal += collisionN; } } } if (numCollPts > 0) { JiggleMath.NormalizeSafe(ref collNormal); collisionFunctor.CollisionNotify(ref info, ref collNormal, collPts, numCollPts); } } #if USE_STACKALLOC } } #else FreeStackAlloc(potTriArray); } FreeStackAlloc(collPtArray); } #endif } }