/// <summary> /// Segment-Mesh collision test, used by the mesh-mesh collision test /// Andre Berhtiaume, 2008 /// </summary> /// <param name="m1"></param> /// <param name="segstart"></param> /// <param name="segend"></param> /// <param name="meshIndex"></param> /// <param name="meshPartIndex"></param> /// <param name="polyIndex"></param> /// <returns></returns> private static bool CollisionSegmentMesh(int m1ind, ModelGeo m1, Vector3 segstart, Vector3 segend, out int meshIndex, out int meshPartIndex, out int polyIndex) { meshIndex = -1; polyIndex = -1; meshPartIndex = -1; float u = 0, v = 0, w = 0, t = 0; Vector3 a, b, c; Ray meshSpaceRay = new Ray(); for (int i = 0; i < m1.mModel.Meshes.Count; i++) { ModelMesh mesh = m1.mModel.Meshes[i]; Matrix mat = m1.MeshMat(i); //m1.mMatBones[mesh.ParentBone.Index] * m1.mMatWorld; Matrix inverseSceneTransform = Matrix.Invert(mat); Vector3 rayPosition = Vector3.Transform(segstart, inverseSceneTransform); Vector3 rayDirection = Vector3.TransformNormal(Vector3.Normalize(segend - segstart), inverseSceneTransform); Vector3 locsegstart = rayPosition; Vector3 locsegend = Vector3.Transform(segend, inverseSceneTransform); meshSpaceRay.Position = rayPosition; meshSpaceRay.Direction = rayDirection; //if (mesh.BoundingSphere.Intersects(meshSpaceRay).HasValue == false) //{ // continue; //} List<CollisionUtility.collidingPart> collidingParts = new List<CollisionUtility.collidingPart>(); if (!CollisionUtility.Contains(m1.mModel)) { CollisionUtility.ModelBoundingInfo.Add(CollisionUtility.CalcBoundingBoxes(m1.mModel)); } else { foreach (CollisionUtility.ModelBoundingBoxBuffer mbb in CollisionUtility.modelBoundingInfo) { //Monitor.AddMessage("count " + mbb.MeshList.Count); if (i < mbb.MeshList.Count) // this is a patch: must understand why it's needed { for (int j = 0; j < mbb.MeshList[i].BoundingBoxes.Count; j++) { float? f = meshSpaceRay.Intersects(mbb.MeshList[i].BoundingBoxes[j]); //Monitor.AddMessage("test" + f.HasValue); if (f.HasValue) { CollisionUtility.collidingPart cp; cp.MeshIndex = i; cp.MeshPartIndex = j; cp.Distance = f.Value; collidingParts.Add(cp); } } } } //Monitor.AddMessage( "CP count = " + collidingParts.Count); collidingParts.Sort(); } //Monitor.AddMessage("Col part: " + collidingParts.Count); if (collidingParts.Count == 0) { continue; } //* for (int j = 0; j < collidingParts.Count; j++) { CollisionUtility.collidingPart prt = collidingParts[j]; ModelMeshPart part = mesh.MeshParts[prt.MeshPartIndex]; //*/ /* for (int j = 0; j < mesh.MeshParts.Count; j++) { ModelMeshPart part = mesh.MeshParts[j]; //*/ for (int x = 0; x < part.PrimitiveCount; x++) { a = m1.GetVertex(i, prt.MeshPartIndex, x * 3 + 0); b = m1.GetVertex(i, prt.MeshPartIndex, x * 3 + 1); c = m1.GetVertex(i, prt.MeshPartIndex, x * 3 + 2); if (IntersectSegmentTriangle(locsegstart, locsegend, b, a, c, ref u, ref v, ref w, ref t)) { meshIndex = i; meshPartIndex = prt.MeshPartIndex; polyIndex = x; a = Vector3.Transform(a, mat); b = Vector3.Transform(b, mat); c = Vector3.Transform(c, mat); n2 = Vector3.Cross(a - b, c - b); //n2 = Vector3.Transform(n2, transforms[mesh.ParentBone.Index] * sceneTransform); //Console.WriteLine("Test case:"); //Monitor.AddMessage( "Event: i1 " + m1ind + " i2: " + i + " n1: " + n1 + " n2: " + n2 ); CollisionData.NewEvent(m1ind, i, n1, n2); //Visualize.AddVector( new Vector3(0,2,0), 5* n2, Color.Red); //Monitor.AddMessage("SegmentMesh loop: i1: " + CollisionData.Index1 + " i2: " + CollisionData.Index2 + " n1: " + CollisionData.Normal1 + " n2: " + CollisionData.Normal2); } // Comparison Counter (pedagogical value only) mComparisonCounter++; } } } //return meshIndex != -1 && polyIndex != -1 && meshPartIndex != -1; //return true;// Data.ColEvent(); /* if (CollisionData.Event) Monitor.AddMessage("SegmentMesh: i1: " + CollisionData.Index1 + " i2: " + CollisionData.Index2 + " n1: " + CollisionData.Normal1 + " n2: " + CollisionData.Normal2); //*/ return CollisionData.Event; }
/// <summary> /// Mesh-Mesh collision test /// Andre Berhtiaume, 2008 /// </summary> /// <param name="m1"></param> /// <param name="m2"></param> /// <returns>True if a collision is detected, false otherwise.</returns> private static bool CollisionMeshMesh(ModelGeo m1, ModelGeo m2) { int meshIndex = -1; int polyIndex = -1; int meshPartIndex = -1; //Matrix[] transforms = new Matrix[m1.mModel.Bones.Count]; //m1.mModel.CopyAbsoluteBoneTransformsTo(transforms); for (int i = 0; i < m1.mModel.Meshes.Count; i++) { ModelMesh mesh = m1.mModel.Meshes[i]; Matrix inverseSceneTransform = Matrix.Invert(m1.mMatBones[mesh.ParentBone.Index] * m1.mMatWorld); for (int j = 0; j < mesh.MeshParts.Count; j++) { ModelMeshPart part = mesh.MeshParts[j]; for (int x = 0; x < part.PrimitiveCount; x++) { Matrix mat = m1.mMatBones[mesh.ParentBone.Index] * m1.mMatWorld; Vector3 a = Vector3.Transform(m1.GetVertex(i, j, x * 3 + 0), mat); Vector3 b = Vector3.Transform(m1.GetVertex(i, j, x * 3 + 1), mat); Vector3 c = Vector3.Transform(m1.GetVertex(i, j, x * 3 + 2), mat); n1 = Vector3.Cross((a - b), (c - b)); CollisionSegmentMesh(i, m2, a, b, out meshIndex, out meshPartIndex, out polyIndex); CollisionSegmentMesh(i, m2, b, c, out meshIndex, out meshPartIndex, out polyIndex); CollisionSegmentMesh(i, m2, c, a, out meshIndex, out meshPartIndex, out polyIndex); /* if (CollisionSegmentMesh(m2.mModel, m2.mMatWorld, a, b, out meshIndex, out meshPartIndex, out polyIndex) || CollisionSegmentMesh(m2.mModel, m2.mMatWorld, b, c, out meshIndex, out meshPartIndex, out polyIndex) || CollisionSegmentMesh(m2.mModel, m2.mMatWorld, c, a, out meshIndex, out meshPartIndex, out polyIndex)) { meshIndex = i; meshPartIndex = j; polyIndex = x; //return true; } //*/ } } } //return meshIndex != -1 && polyIndex != -1 && meshPartIndex != -1; return CollisionData.Event; }
/// <summary> /// Returns wether a models's meshes collides with a terrain /// </summary> /// <param name="m1"></param> /// <param name="t"></param> /// <returns></returns> private static bool CollisionMeshTerrain(ModelGeo m1, Terrain t) { int meshIndex = -1; int polyIndex = -1; int meshPartIndex = -1; for (int i = 0; i < m1.mModel.Meshes.Count; i++) { ModelMesh mesh = m1.mModel.Meshes[i]; for (int j = 0; j < mesh.MeshParts.Count; j++) { ModelMeshPart part = mesh.MeshParts[j]; for (int x = 0; x < part.PrimitiveCount; x++) { Matrix mat = m1.mMatBones[mesh.ParentBone.Index] * m1.mMatWorld; Vector3 a = Vector3.Transform(m1.GetVertex(i, j, x * 3 + 0), mat); Vector3 b = Vector3.Transform(m1.GetVertex(i, j, x * 3 + 1), mat); Vector3 c = Vector3.Transform(m1.GetVertex(i, j, x * 3 + 2), mat); if (a.Y < t.GetHeight(a) || b.Y < t.GetHeight(b) || c.Y < t.GetHeight(c)) { meshIndex = i; meshPartIndex = j; polyIndex = x; n1 = Vector3.Cross((a - b), (c - b)); n2 = t.GetNormal(a); CollisionData.NewEvent(i, -1, n1, n2); //return true; } } } } //Console.WriteLine(fClosestPoly); //return meshIndex != -1 && polyIndex != -1 && meshPartIndex != -1; return CollisionData.Event; }
/// <summary> /// Bounding sphere-Mesh collision test /// Andre Berhtiaume, 2008 /// </summary> /// <param name="m1"></param> /// <param name="s"></param> /// <returns>True if a collision is detected, false otherwise.</returns> private static bool CollisionMeshBoundingSphere(ModelGeo m1, int m2ind, BoundingSphere s) { float t = -1; Vector3 q = Vector3.Zero; BoundingSphere bs; for (int i = 0; i < m1.mModel.Meshes.Count; i++) { ModelMesh mesh = m1.mModel.Meshes[i]; Matrix inverseSceneTransform = Matrix.Invert(m1.mMatBones[mesh.ParentBone.Index] * m1.mMatWorld); bs = s; bs.Center = Vector3.Transform(s.Center, inverseSceneTransform); bs.Radius *= 1 / m1.mMinScale; //Monitor.AddMessage("center " + bs.Center + " radius: " + bs.Radius); for (int j = 0; j < mesh.MeshParts.Count; j++) { ModelMeshPart part = mesh.MeshParts[j]; for (int x = 0; x < part.PrimitiveCount; x++) { // Comparison Counter (pedagogical value only mComparisonCounter++; Vector3 a = m1.GetVertex(i, j, x * 3 + 0); Vector3 b = m1.GetVertex(i, j, x * 3 + 1); Vector3 c = m1.GetVertex(i, j, x * 3 + 2); n1 = Vector3.Transform(Vector3.Cross((a - b), (c - b)), m1.mMatWorldRot); if (IntersectRaySphere(a, Vector3.Normalize(b - a), bs, ref t, ref q) && t <= (a - b).Length() //******************* ) { //Console.WriteLine("ab t = " + t + " impact " + q + "from " + a + " and " + b); n2 = Vector3.Transform(q - bs.Center, m1.mMatWorldRot); CollisionData.NewEvent(i, m2ind, n1, n2); //return true; } if (IntersectRaySphere(b, Vector3.Normalize(c - b), bs, ref t, ref q) && t <= (b - c).Length() ) { //Console.WriteLine("bc t = " + t + " impact " + q + "from " + b + " and " + c); n2 = Vector3.Transform(q - bs.Center, m1.mMatWorldRot); CollisionData.NewEvent(i, m2ind, n1, n2); //return true; } if (IntersectRaySphere(c, Vector3.Normalize(a - c), bs, ref t, ref q) && t <= (c - a).Length() ) { //Console.WriteLine("ca t = " + t + " impact " + q + "from " + c + " and " + a); n2 = Vector3.Transform(q - bs.Center, m1.mMatWorldRot); CollisionData.NewEvent(i, m2ind, n1, n2); //return true; } //Monitor.AddMessage("t = " + t); } } } return CollisionData.Event; //false; }