/// <summary> /// Shows the local rotation axes. This method should be properly be moved to the ModelGeo class /// </summary> /// <param name="m"></param> public static void ShowLocalRotAxes(ModelGeo m) { Vector3 dim = m.Dimensions(); float sc = 1.1f * Math.Min(Math.Min(dim.X, dim.Y), dim.Z); Vector3 p = m.mMatWorld.Translation; AddCircle(p, sc, m.mMatWorldNoScale.Right, Color.Red); AddCircle(p, sc, m.mMatWorldNoScale.Up, Color.Lime); AddCircle(p, sc, m.mMatWorldNoScale.Backward, Color.Blue); }
/// <summary> /// Draw the model as a wireframe. Currently not functional. /// </summary> /// <param name="m"></param> /// <param name="c"></param> static void drawWireFrame(ModelGeo m, Color c) { ModelMeshPart mp; foreach (ModelMesh mesh in m.mModel.Meshes) { // Prepare to receive the vertices of the model v = new VertexPositionColor[mesh.MeshParts[0].NumVertices]; // Request the vertices mesh.MeshParts[0].VertexBuffer.GetData<VertexPositionColor>(v); // Get the points and indices used for the lines indices = new short[mesh.MeshParts[0].IndexBuffer.IndexCount / 2]; mesh.MeshParts[0].IndexBuffer.GetData<short>(indices); // Place the points and indices in their respective buffer buffer VB = new VertexBuffer(thegame.GraphicsDevice, typeof(VertexPositionColor), v.Length, BufferUsage.WriteOnly); VB.SetData<VertexPositionColor>(v); IB = new IndexBuffer(thegame.GraphicsDevice, typeof(short), indices.Length, BufferUsage.WriteOnly); IB.SetData<short>(indices); //BEshader.GraphicsDevice.VertexDeclaration = VD; BEshader.GraphicsDevice.Indices = IB; BEshader.World = m.mMatBones[mesh.ParentBone.Index] * m.mMatWorld; BEshader.CurrentTechnique.Passes[0].Apply(); //BEshader.GraphicsDevice.Vertices[0].SetSource(VB, 0, v.Length * VertexPositionColor.SizeInBytes ); for (int i = 0; i < mesh.MeshParts.Count; i++) { mp = mesh.MeshParts[i]; //BEshader.Begin(); foreach (EffectPass pass in BEshader.CurrentTechnique.Passes) { //pass.Begin(); //BEshader.GraphicsDevice.RenderState.PointSize = 5.0f; BEshader.GraphicsDevice.SetVertexBuffer(VB, mp.VertexOffset); //BEshader.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, mp.BaseVertex, mp.StreamOffset, mp.NumVertices, mp.StartIndex, mp.PrimitiveCount); BEshader.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, mp.StartIndex, mp.VertexOffset, mp.NumVertices, mp.StartIndex, mp.PrimitiveCount); //pass.End(); } //BEshader.End(); } } }
/// <summary> /// Visualizes the BoundingSpheres of a ModelGeo. This method should be properly be moved to the ModelGeo class /// </summary> /// <param name="m"></param> /// <param name="c"></param> public static void ShowBoundingSpheres(ModelGeo m, Color c) { BoundingSphere bs; for (int i = 0; i < m.BoundingSpheres.Count; i++) { bs = m.GetBoundingSphere(i); AddSphere(Matrix.CreateScale(bs.Radius) * Matrix.CreateTranslation(bs.Center), c, false); } }
/// <summary> /// Shows the local axes of a model. This method should be properly be moved to the ModelGeo class /// </summary> /// <param name="m"></param> /// <param name="persistent"></param> public static void ShowLocalAxes(ModelGeo m) { Vector3 dim = m.Dimensions(); float sc = 1.1f * Math.Max(Math.Max(dim.X, dim.Y), dim.Z); Vector3 p = m.mMatWorld.Translation; AddLine(p, p + sc * m.mMatWorldNoScale.Right, Color.Red, false); AddLine(p, p + sc * m.mMatWorldNoScale.Up, Color.Lime, false); AddLine(p, p + sc * m.mMatWorldNoScale.Backward, Color.Blue, false); }
public static void ShowAABB(ModelGeo m, Color c) { BoundingBox boundingBox = new BoundingBox(); Vector3[] vertexs; Matrix M; ModelMesh mesh; //foreach (ModelMesh mesh in m.mModel.Meshes) for (int i = 0; i < m.mModel.Meshes.Count; i++) { mesh = m.mModel.Meshes[i]; // This is the right matrix to localize the bounding sphere, // But it will also squash it accoding the whatever uneven scaling is in the mMatWorld M = m.mMatBones[mesh.ParentBone.Index] * m.mMatWorld; // Prepare to receive the vertices of the model m.GetMeshpartVerticesCOPY(i, 0, out vertexs); Vector3.Transform(vertexs, ref M, vertexs); // We create a new boundingbox for these vertices and merge with what we have so far boundingBox = BoundingBox.CreateFromPoints(vertexs); // Now we need only to add the box to the draw list LineStrips.Add(new LineStripData(boundingBox.GetCorners(), UnitBoxIndices, c, Matrix.Identity, false)); } }
/// <summary> /// Visualizes the BoundingBox of a ModelGeo. This method should be properly be moved to the ModelGeo class /// </summary> /// <param name="m"></param> /// <param name="c"></param> public static void ShowBoundingBox(ModelGeo m, Color c) { LineStrips.Add(new LineStripData(m.BoundingBoxUnscaled.GetCorners(), UnitBoxIndices, c, m.mMatWorld, false)); }
/// <summary> /// Returns true/false based on whether the segment defined by a and b intersects /// the model m's bounding spheres. /// meshInd report the specific mesh being intersected /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="m"></param> /// <returns></returns> public static bool IntersectSegmentBSphere(Vector3 a, Vector3 b, ModelGeo m, out int meshInd) { //BoundingSphere bs; float t = 0; Vector3 q = Vector3.Zero; meshInd = -1; Vector3 norm = Vector3.Normalize(b - a); for (int i = 0; i < m.BoundingSpheres.Count; i++) { if (IntersectRaySphere(a, norm, m.GetBoundingSphere(i), ref t, ref q) && t <= (a - b).Length()) { meshInd = i; CollisionData.NewEvent(i, -1, norm, -norm); //return true; } } //*/ return CollisionData.Event; // false; }
/// <summary> /// Returns true/false based on whether the segment defined by a and b intersects /// the model m's meshes. meshInd report the specific mesh being intersected /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <param name="m"></param> /// <returns></returns> public static bool IntersectSegmentMesh(Vector3 a, Vector3 b, ModelGeo m, out int meshInd) { meshInd = -1; int polyIndex = -1; int meshPartIndex = -1; //return CollisionSegmentMesh(m.mModel, m.mMatWorld, a, b, out meshInd, out meshPartIndex, out polyIndex); return CollisionSegmentMesh(-1, m, a, b, out meshInd, out meshPartIndex, out polyIndex); }
/// <summary> /// Collision between bounding spheres for c1 and c2 /// Andre Berthiaume, 2008 /// </summary> /// <param name="c1"></param> /// <param name="c2"></param> /// <returns>True if a collision is detected, false otherwise.</returns> private static bool CollisionSphereSphere(ModelGeo c1, ModelGeo c2) { BoundingSphere c1BoundingSphere, c2BoundingSphere; for (int i = 0; i < c1.BoundingSpheres.Count; i++) { // Check whether the bounding spheres intersect. c1BoundingSphere = c1.GetBoundingSphere(i); //Monitor.AddMessage("c1: " + c1BoundingSphere.Center); for (int j = 0; j < c2.BoundingSpheres.Count; j++) { c2BoundingSphere = c2.GetBoundingSphere(j); //Monitor.AddMessage("c2: " + c2BoundingSphere.Center); if (c1BoundingSphere.Intersects(c2BoundingSphere)) { //Console.WriteLine("Sphere Sphere col"); n1 = c2BoundingSphere.Center - c1BoundingSphere.Center; n2 = -n1; CollisionData.NewEvent(i, j, n1, n2); //return true; } // Comparison Counter (pedagogical value only) mComparisonCounter++; } } return CollisionData.Event; }
/// <summary> /// Returns wether a models's bounding spheres (of meshes) collides with a terrain /// </summary> /// <param name="c1"></param> /// <param name="t"></param> /// <returns></returns> private static bool CollisionSphereTerrain(ModelGeo c1, Terrain t) { BoundingSphere c1BoundingSphere; //for (int i = 0; i < c1.mModel.Meshes.Count; i++) for (int i = 0; i < c1.BoundingSpheres.Count; i++) { //c1BoundingSphere = c1.mModel.Meshes[i].BoundingSphere; //c1BoundingSphere.Center = Vector3.Transform(c1BoundingSphere.Center, c1.mModel.Bones[i].Transform * c1.mMatWorld); //c1BoundingSphere.Radius *= c1.mMaxScale; c1BoundingSphere = c1.GetBoundingSphere(i); if (c1BoundingSphere.Center.Y - t.GetHeight(c1BoundingSphere.Center) <= c1BoundingSphere.Radius) { n2 = t.GetNormal(c1BoundingSphere.Center); n1 = -n2; CollisionData.NewEvent(i, -1, n1, n2); //return true; } } //Console.WriteLine(c2.mModel.Meshes[0].MeshParts[0]. ); //return false; return CollisionData.Event; }
/// <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> /// 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> /// 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> /// Bounding sphere-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 CollisionMeshBoundingSphere(ModelGeo m1, ModelGeo m2) { for (int i = 0; i < m2.BoundingSpheres.Count; i++) { if (CollisionMeshBoundingSphere(m1, i, m2.GetBoundingSphere(i))) { return true; } } return false; }
/// <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; }