//Point-Of-View Ray Casting collision detection for Boxes public List<Contact> ProjectPOVRay(Box box, float RayLength) { List<Contact> Contacts = new List<Contact>(); Vector3 sideOffset = Vector3.Normalize(Vector3.Cross(this.Velocity, new Vector3(0, 1, 0))); Vector3 side1 = this.Position - sideOffset; Vector3 side2 = this.Position + sideOffset; Vector3[] vertices = box.GetVertices(); Vector3[] normals = box.GetNormals(); float[] Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(((box.Position + (normals[i] * box.Size / 2) - side1)), normals[i]) / Vector3.Dot(this.velocity, normals[i]); } //The number of faces whose normals are not pointing away from the sphere. int PositiveCount = 0; List<int> indices = new List<int>(); //Find shortest distance to Box Face int shortestIndex = -1; //Obtain list of faces whose normals are not pointing away from he sphere and the distance between the sphere and the closest box face for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= RayLength) { indices.Add(i); PositiveCount++; if (shortestIndex == -1) { shortestIndex = i; } else { if (Distances[shortestIndex] > Distances[i]) { shortestIndex = i; } } } else { Distances[i] = -1; } } else { Distances[i] = -1; } } //Test For Left Ray //Don't collide if many positives are return, false positive if (PositiveCount > 0) { foreach (int index in indices) { //Check for validity with point intersecting the box Vector3 RayPoint = side1 + velocity / velocity.Length() * Distances[index]; Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) min.X = vertices[i].X; if (min.Y > vertices[i].Y) min.Y = vertices[i].Y; if (min.Z > vertices[i].Z) min.Z = vertices[i].Z; if (max.X < vertices[i].X) max.X = vertices[i].X; if (max.Y < vertices[i].Y) max.Y = vertices[i].Y; if (max.Z < vertices[i].Z) max.Z = vertices[i].Z; } double dSquared = 0; if (RayPoint.X < min.X) { dSquared += (float)Math.Pow((RayPoint.X - min.X), 2); } else if (RayPoint.X > max.X) { dSquared += (float)Math.Pow((RayPoint.X - max.X), 2); } if (RayPoint.Y < min.Y) { dSquared += (float)Math.Pow((RayPoint.Y - min.Y), 2); } else if (RayPoint.Y > max.Y) { dSquared += (float)Math.Pow((RayPoint.Y - max.Y), 2); } if (RayPoint.Z < min.Z) { dSquared += (float)Math.Pow((RayPoint.Z - min.Z), 2); } else if (RayPoint.Z > max.Z) { dSquared += (float)Math.Pow((RayPoint.Z - max.Z), 2); } if (dSquared <= 0.01) { Contact contact = new Contact(); contact.ContactType = CollisionType.POVRay; contact.RayCollided = RayCollisionResult.Left; contact.ContactNormal = -velocity / Velocity.Length(); contact.ContactPoint = RayPoint; contact.DeepestPoint = side1 + velocity / Velocity.Length() * RayLength; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); //Compute contact angle if (PositiveCount == 1) { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } else { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } //Angle should never be higher than 90 degrees. if (contact.ContactAngle > Math.PI / 2) { contact.ContactAngle = (float)Math.PI - contact.ContactAngle; } Contacts.Add(contact); break; } } } Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(((box.Position + (normals[i] * box.Size / 2) - side2)), normals[i]) / Vector3.Dot(this.velocity, normals[i]); } //The number of faces whose normals are not pointing away from the sphere. PositiveCount = 0; indices = new List<int>(); //Obtain list of faces whose normals are not pointing away from he sphere and the distance between the sphere and the closest box face shortestIndex = 0; for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= RayLength) { indices.Add(i); PositiveCount++; if (shortestIndex == -1) { shortestIndex = i; } else { if (Distances[shortestIndex] > Distances[i]) { shortestIndex = i; } } } else { Distances[i] = -1; } } else { Distances[i] = -1; } } //Test For Right Ray //Don't collide if many positives are return, false positive if (PositiveCount > 0) { foreach (int index in indices) { //Check for validity with point intersecting the box Vector3 RayPoint = side2 + velocity / velocity.Length() * Distances[index]; Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) min.X = vertices[i].X; if (min.Y > vertices[i].Y) min.Y = vertices[i].Y; if (min.Z > vertices[i].Z) min.Z = vertices[i].Z; if (max.X < vertices[i].X) max.X = vertices[i].X; if (max.Y < vertices[i].Y) max.Y = vertices[i].Y; if (max.Z < vertices[i].Z) max.Z = vertices[i].Z; } double dSquared = 0; if (RayPoint.X < min.X) { dSquared += (float)Math.Pow((RayPoint.X - min.X), 2); } else if (RayPoint.X > max.X) { dSquared += (float)Math.Pow((RayPoint.X - max.X), 2); } if (RayPoint.Y < min.Y) { dSquared += (float)Math.Pow((RayPoint.Y - min.Y), 2); } else if (RayPoint.Y > max.Y) { dSquared += (float)Math.Pow((RayPoint.Y - max.Y), 2); } if (RayPoint.Z < min.Z) { dSquared += (float)Math.Pow((RayPoint.Z - min.Z), 2); } else if (RayPoint.Z > max.Z) { dSquared += (float)Math.Pow((RayPoint.Z - max.Z), 2); } if (dSquared <= 0.01) { Contact contact = new Contact(); contact.ContactType = CollisionType.POVRay; contact.RayCollided = RayCollisionResult.Right; contact.ContactNormal = -velocity / Velocity.Length(); contact.ContactPoint = RayPoint; contact.DeepestPoint = side2 + velocity / Velocity.Length() * RayLength; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); //Compute contact angle if (PositiveCount == 1) { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } else { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } //Angle should never be higher than 90 degrees. if (contact.ContactAngle > Math.PI / 2) { contact.ContactAngle = (float)Math.PI - contact.ContactAngle; } Contacts.Add(contact); break; } } } //If contacts exist, collisions were found else return nothing if (Contacts.Count > 0) { return Contacts; } else { return null; } }
//Point-Of-View Ray Casting collision detection for Boxes public List <Contact> ProjectPOVRay(Box box, float RayLength) { List <Contact> Contacts = new List <Contact>(); Vector3 sideOffset = Vector3.Normalize(Vector3.Cross(this.Velocity, new Vector3(0, 1, 0))); Vector3 side1 = this.Position - sideOffset; Vector3 side2 = this.Position + sideOffset; Vector3[] vertices = box.GetVertices(); Vector3[] normals = box.GetNormals(); float[] Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(((box.Position + (normals[i] * box.Size / 2) - side1)), normals[i]) / Vector3.Dot(this.velocity, normals[i]); } //The number of faces whose normals are not pointing away from the sphere. int PositiveCount = 0; List <int> indices = new List <int>(); //Find shortest distance to Box Face int shortestIndex = -1; //Obtain list of faces whose normals are not pointing away from he sphere and the distance between the sphere and the closest box face for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= RayLength) { indices.Add(i); PositiveCount++; if (shortestIndex == -1) { shortestIndex = i; } else { if (Distances[shortestIndex] > Distances[i]) { shortestIndex = i; } } } else { Distances[i] = -1; } } else { Distances[i] = -1; } } //Test For Left Ray //Don't collide if many positives are return, false positive if (PositiveCount > 0) { foreach (int index in indices) { //Check for validity with point intersecting the box Vector3 RayPoint = side1 + velocity / velocity.Length() * Distances[index]; Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) { min.X = vertices[i].X; } if (min.Y > vertices[i].Y) { min.Y = vertices[i].Y; } if (min.Z > vertices[i].Z) { min.Z = vertices[i].Z; } if (max.X < vertices[i].X) { max.X = vertices[i].X; } if (max.Y < vertices[i].Y) { max.Y = vertices[i].Y; } if (max.Z < vertices[i].Z) { max.Z = vertices[i].Z; } } double dSquared = 0; if (RayPoint.X < min.X) { dSquared += (float)Math.Pow((RayPoint.X - min.X), 2); } else if (RayPoint.X > max.X) { dSquared += (float)Math.Pow((RayPoint.X - max.X), 2); } if (RayPoint.Y < min.Y) { dSquared += (float)Math.Pow((RayPoint.Y - min.Y), 2); } else if (RayPoint.Y > max.Y) { dSquared += (float)Math.Pow((RayPoint.Y - max.Y), 2); } if (RayPoint.Z < min.Z) { dSquared += (float)Math.Pow((RayPoint.Z - min.Z), 2); } else if (RayPoint.Z > max.Z) { dSquared += (float)Math.Pow((RayPoint.Z - max.Z), 2); } if (dSquared <= 0.01) { Contact contact = new Contact(); contact.ContactType = CollisionType.POVRay; contact.RayCollided = RayCollisionResult.Left; contact.ContactNormal = -velocity / Velocity.Length(); contact.ContactPoint = RayPoint; contact.DeepestPoint = side1 + velocity / Velocity.Length() * RayLength; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); //Compute contact angle if (PositiveCount == 1) { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } else { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } //Angle should never be higher than 90 degrees. if (contact.ContactAngle > Math.PI / 2) { contact.ContactAngle = (float)Math.PI - contact.ContactAngle; } Contacts.Add(contact); break; } } } Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(((box.Position + (normals[i] * box.Size / 2) - side2)), normals[i]) / Vector3.Dot(this.velocity, normals[i]); } //The number of faces whose normals are not pointing away from the sphere. PositiveCount = 0; indices = new List <int>(); //Obtain list of faces whose normals are not pointing away from he sphere and the distance between the sphere and the closest box face shortestIndex = 0; for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= RayLength) { indices.Add(i); PositiveCount++; if (shortestIndex == -1) { shortestIndex = i; } else { if (Distances[shortestIndex] > Distances[i]) { shortestIndex = i; } } } else { Distances[i] = -1; } } else { Distances[i] = -1; } } //Test For Right Ray //Don't collide if many positives are return, false positive if (PositiveCount > 0) { foreach (int index in indices) { //Check for validity with point intersecting the box Vector3 RayPoint = side2 + velocity / velocity.Length() * Distances[index]; Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) { min.X = vertices[i].X; } if (min.Y > vertices[i].Y) { min.Y = vertices[i].Y; } if (min.Z > vertices[i].Z) { min.Z = vertices[i].Z; } if (max.X < vertices[i].X) { max.X = vertices[i].X; } if (max.Y < vertices[i].Y) { max.Y = vertices[i].Y; } if (max.Z < vertices[i].Z) { max.Z = vertices[i].Z; } } double dSquared = 0; if (RayPoint.X < min.X) { dSquared += (float)Math.Pow((RayPoint.X - min.X), 2); } else if (RayPoint.X > max.X) { dSquared += (float)Math.Pow((RayPoint.X - max.X), 2); } if (RayPoint.Y < min.Y) { dSquared += (float)Math.Pow((RayPoint.Y - min.Y), 2); } else if (RayPoint.Y > max.Y) { dSquared += (float)Math.Pow((RayPoint.Y - max.Y), 2); } if (RayPoint.Z < min.Z) { dSquared += (float)Math.Pow((RayPoint.Z - min.Z), 2); } else if (RayPoint.Z > max.Z) { dSquared += (float)Math.Pow((RayPoint.Z - max.Z), 2); } if (dSquared <= 0.01) { Contact contact = new Contact(); contact.ContactType = CollisionType.POVRay; contact.RayCollided = RayCollisionResult.Right; contact.ContactNormal = -velocity / Velocity.Length(); contact.ContactPoint = RayPoint; contact.DeepestPoint = side2 + velocity / Velocity.Length() * RayLength; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); //Compute contact angle if (PositiveCount == 1) { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } else { float scalar = Vector3.Dot(normals[shortestIndex], velocity / velocity.Length()); contact.ContactAngle = (float)Math.Acos(scalar); } //Angle should never be higher than 90 degrees. if (contact.ContactAngle > Math.PI / 2) { contact.ContactAngle = (float)Math.PI - contact.ContactAngle; } Contacts.Add(contact); break; } } } //If contacts exist, collisions were found else return nothing if (Contacts.Count > 0) { return(Contacts); } else { return(null); } }
//Sphere --> Box Collision Detection and Contact Info generation //Returns null if no collision, a contact object if a collision occurs protected Contact Collides(Sphere sphere, Box box) { Contact contact = new Contact(); Vector3[] vertices = box.GetVertices(); //Implementation based on pages 644-645 of Geometric Tools for Computer Graphics [Philip J. Schneider & David H. Eberly, Morgan Kaufmann] //Make sure the sphere is touching the box before continuing //Distance from sphere to each of the box vertices float[] VertexDistances = new float[8]; //Compute distance for (int i = 0; i < vertices.Length; i++) { VertexDistances[i] = (vertices[i] - sphere.Position).Length(); } //Obtain Minimum and Maximum values for X,Y,Z Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) min.X = vertices[i].X; if (min.Y > vertices[i].Y) min.Y = vertices[i].Y; if (min.Z > vertices[i].Z) min.Z = vertices[i].Z; if (max.X < vertices[i].X) max.X = vertices[i].X; if (max.Y < vertices[i].Y) max.Y = vertices[i].Y; if (max.Z < vertices[i].Z) max.Z = vertices[i].Z; } //Test for collision double dSquared = 0; if (sphere.Position.X < min.X) { dSquared += (float)Math.Pow((sphere.Position.X - min.X), 2); } else if (sphere.Position.X > max.X) { dSquared += (float)Math.Pow((sphere.Position.X - max.X), 2); } if (sphere.Position.Y < min.Y) { dSquared += (float)Math.Pow((sphere.Position.Y - min.Y), 2); } else if (sphere.Position.Y > max.Y) { dSquared += (float)Math.Pow((sphere.Position.Y - max.Y), 2); } if (sphere.Position.Z < min.Z) { dSquared += (float)Math.Pow((sphere.Position.Z - min.Z), 2); } else if (sphere.Position.Z > max.Z) { float test = sphere.Position.Z - max.Z; dSquared += (float)Math.Pow((sphere.Position.Z - max.Z), 2); } if (dSquared <= Math.Pow(sphere.Radius, 2)) { #region Vertex-Face foreach (Vector3 vertex in vertices) { float Distance = (sphere.Position - vertex).Length(); if (Distance <= sphere.Radius) { Vector3 midline = vertex - sphere.Position; contact.ContactType = CollisionType.VertexFace; contact.ContactNormal = -midline / midline.Length(); contact.ContactPoint = vertex;// sphere.position + (midline * sphere.Radius) / midline.Length(); contact.DeepestPoint = sphere.Position + (midline * sphere.Radius) / midline.Length(); contact.PenetrationDepth = ((vertex - contact.DeepestPoint)).Length(); return contact; } } #endregion #region Face-Face Vector3[] normals = box.GetNormals(); float[] Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(normals[i], sphere.Position - (box.Position + (normals[i] * box.Size / 2))) / normals[i].Length(); } int index = 0; //The number of faces whose normals are not pointing away from the sphere. int PositiveCount = 0; for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= sphere.Radius) { PositiveCount++; } if (Distances[index] > Distances[i] || Distances[index] < 0) { index = i; } } } if (Distances[index] <= sphere.Radius && PositiveCount == 1) { contact = new Contact(); contact.ContactType = CollisionType.FaceFace; contact.ContactNormal = normals[index]; contact.PenetrationDepth = sphere.Radius - Distances[index]; //+ contact.ContactPoint = sphere.Position - contact.ContactNormal * VertexDistances[index]; contact.DeepestPoint = sphere.Position - contact.ContactNormal * (sphere.Radius); return contact; } #endregion #region Edge-Face float[] PointDistances = new float[12]; Vector3[,] VertexPair = new Vector3[12, 2]; //Front Vertices Vector3 x0 = sphere.Position; Vector3 x1 = VertexPair[0, 0] = vertices[0]; Vector3 x2 = VertexPair[0, 1] = vertices[1]; PointDistances[0] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[1, 0] = vertices[1]; x2 = VertexPair[1, 1] = vertices[3]; PointDistances[1] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[2, 0] = vertices[3]; x2 = VertexPair[2, 1] = vertices[2]; PointDistances[2] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[3, 0] = vertices[2]; x2 = VertexPair[3, 1] = vertices[0]; PointDistances[3] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); //Back Vertices x1 = VertexPair[4, 0] = vertices[4]; x2 = VertexPair[4, 1] = vertices[5]; PointDistances[4] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[5, 0] = vertices[5]; x2 = VertexPair[5, 1] = vertices[7]; PointDistances[5] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[6, 0] = vertices[7]; x2 = VertexPair[6, 1] = vertices[6]; PointDistances[6] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[7, 0] = vertices[6]; x2 = VertexPair[7, 1] = vertices[4]; PointDistances[7] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); //Side Vertices x1 = VertexPair[8, 0] = vertices[0]; x2 = VertexPair[8, 1] = vertices[4]; PointDistances[8] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[9, 0] = vertices[1]; x2 = VertexPair[9, 1] = vertices[5]; PointDistances[9] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[10, 0] = vertices[2]; x2 = VertexPair[10, 1] = vertices[6]; PointDistances[10] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[11, 0] = vertices[3]; x2 = VertexPair[11, 1] = vertices[7]; PointDistances[11] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); index = 0; for (int i = 0; i < PointDistances.Length; i++) { if (PointDistances[index] > PointDistances[i]) { index = i; } } if (PointDistances[index] < sphere.Radius) { x1 = VertexPair[index, 0]; x2 = VertexPair[index, 1]; //Required to compute point on the line float t = -Vector3.Dot((x1 - x0), (x2 - x1)) / (x2 - x1).LengthSquared(); Vector3 LinePoint = new Vector3(x1.X + (x2.X - x1.X) * t, x1.Y + (x2.Y - x1.Y) * t, x1.Z + (x2.Z - x1.Z) * t); contact.ContactType = CollisionType.EdgeFace; contact.ContactNormal = Vector3.Normalize(x0 - LinePoint); contact.ContactPoint = LinePoint; contact.DeepestPoint = x0 - contact.ContactNormal / contact.ContactNormal.Length() * sphere.Radius; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); return contact; } #endregion } //No Contact found... return null; }
//Detects sphere--> box collision very well but provides no details for contact info generation /*protected bool Collides(Sphere sphere, Box box) * { * Vector3[] vertices = box.GetVertices(); * * //Implementation based on pages 644-645 of Geometric Tools for Computer Graphics [Philip J. Schneider & David H. Eberly, Morgan Kaufmann] * float[] Distances = new float[8]; * * for (int i = 0; i < vertices.Length; i++) * { * Distances[i] = (vertices[i] - sphere.Position).Length(); * } * * Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); * Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); * * for (int i = 0; i < vertices.Length; i++) * { * if (min.X > vertices[i].X) * min.X = vertices[i].X; * * if (min.Y > vertices[i].Y) * min.Y = vertices[i].Y; * * if (min.Z > vertices[i].Z) * min.Z = vertices[i].Z; * * if (max.X < vertices[i].X) * max.X = vertices[i].X; * * if (max.Y < vertices[i].Y) * max.Y = vertices[i].Y; * * if (max.Z < vertices[i].Z) * max.Z = vertices[i].Z; * } * * double dSquared = 0; * * if (sphere.Position.X < min.X) * { * dSquared += (float)Math.Pow((sphere.Position.X - min.X), 2); * } * else if (sphere.Position.X > max.X) * { * dSquared += (float)Math.Pow((sphere.Position.X - max.X), 2); * } * * if (sphere.Position.Y < min.Y) * { * dSquared += (float)Math.Pow((sphere.Position.Y - min.Y), 2); * } * else if (sphere.Position.Y > max.Y) * { * dSquared += (float)Math.Pow((sphere.Position.Y - max.Y), 2); * } * * if (sphere.Position.Z < min.Z) * { * dSquared += (float)Math.Pow((sphere.Position.Z - min.Z), 2); * } * else if (sphere.Position.Z > max.Z) * { * float test = sphere.Position.Z - max.Z; * dSquared += (float)Math.Pow((sphere.Position.Z - max.Z), 2); * } * * if (dSquared <= Math.Pow(sphere.Radius, 2)) * { * return true; * } * else * { * return false; * } * }*/ #endregion //Sphere --> Box Collision Detection and Contact Info generation //Returns null if no collision, a contact object if a collision occurs protected Contact Collides(Sphere sphere, Box box) { Contact contact = new Contact(); Vector3[] vertices = box.GetVertices(); //Implementation based on pages 644-645 of Geometric Tools for Computer Graphics [Philip J. Schneider & David H. Eberly, Morgan Kaufmann] //Make sure the sphere is touching the box before continuing //Distance from sphere to each of the box vertices float[] VertexDistances = new float[8]; //Compute distance for (int i = 0; i < vertices.Length; i++) { VertexDistances[i] = (vertices[i] - sphere.Position).Length(); } //Obtain Minimum and Maximum values for X,Y,Z Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) { min.X = vertices[i].X; } if (min.Y > vertices[i].Y) { min.Y = vertices[i].Y; } if (min.Z > vertices[i].Z) { min.Z = vertices[i].Z; } if (max.X < vertices[i].X) { max.X = vertices[i].X; } if (max.Y < vertices[i].Y) { max.Y = vertices[i].Y; } if (max.Z < vertices[i].Z) { max.Z = vertices[i].Z; } } //Test for collision double dSquared = 0; if (sphere.Position.X < min.X) { dSquared += (float)Math.Pow((sphere.Position.X - min.X), 2); } else if (sphere.Position.X > max.X) { dSquared += (float)Math.Pow((sphere.Position.X - max.X), 2); } if (sphere.Position.Y < min.Y) { dSquared += (float)Math.Pow((sphere.Position.Y - min.Y), 2); } else if (sphere.Position.Y > max.Y) { dSquared += (float)Math.Pow((sphere.Position.Y - max.Y), 2); } if (sphere.Position.Z < min.Z) { dSquared += (float)Math.Pow((sphere.Position.Z - min.Z), 2); } else if (sphere.Position.Z > max.Z) { float test = sphere.Position.Z - max.Z; dSquared += (float)Math.Pow((sphere.Position.Z - max.Z), 2); } if (dSquared <= Math.Pow(sphere.Radius, 2)) { #region Vertex-Face foreach (Vector3 vertex in vertices) { float Distance = (sphere.Position - vertex).Length(); if (Distance <= sphere.Radius) { Vector3 midline = vertex - sphere.Position; contact.ContactType = CollisionType.VertexFace; contact.ContactNormal = -midline / midline.Length(); contact.ContactPoint = vertex;// sphere.position + (midline * sphere.Radius) / midline.Length(); contact.DeepestPoint = sphere.Position + (midline * sphere.Radius) / midline.Length(); contact.PenetrationDepth = ((vertex - contact.DeepestPoint)).Length(); return(contact); } } #endregion #region Face-Face Vector3[] normals = box.GetNormals(); float[] Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(normals[i], sphere.Position - (box.Position + (normals[i] * box.Size / 2))) / normals[i].Length(); } int index = 0; //The number of faces whose normals are not pointing away from the sphere. int PositiveCount = 0; for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= sphere.Radius) { PositiveCount++; } if (Distances[index] > Distances[i] || Distances[index] < 0) { index = i; } } } if (Distances[index] <= sphere.Radius && PositiveCount == 1) { contact = new Contact(); contact.ContactType = CollisionType.FaceFace; contact.ContactNormal = normals[index]; contact.PenetrationDepth = sphere.Radius - Distances[index]; //+ contact.ContactPoint = sphere.Position - contact.ContactNormal * VertexDistances[index]; contact.DeepestPoint = sphere.Position - contact.ContactNormal * (sphere.Radius); return(contact); } #endregion #region Edge-Face float[] PointDistances = new float[12]; Vector3[,] VertexPair = new Vector3[12, 2]; //Front Vertices Vector3 x0 = sphere.Position; Vector3 x1 = VertexPair[0, 0] = vertices[0]; Vector3 x2 = VertexPair[0, 1] = vertices[1]; PointDistances[0] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[1, 0] = vertices[1]; x2 = VertexPair[1, 1] = vertices[3]; PointDistances[1] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[2, 0] = vertices[3]; x2 = VertexPair[2, 1] = vertices[2]; PointDistances[2] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[3, 0] = vertices[2]; x2 = VertexPair[3, 1] = vertices[0]; PointDistances[3] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); //Back Vertices x1 = VertexPair[4, 0] = vertices[4]; x2 = VertexPair[4, 1] = vertices[5]; PointDistances[4] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[5, 0] = vertices[5]; x2 = VertexPair[5, 1] = vertices[7]; PointDistances[5] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[6, 0] = vertices[7]; x2 = VertexPair[6, 1] = vertices[6]; PointDistances[6] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[7, 0] = vertices[6]; x2 = VertexPair[7, 1] = vertices[4]; PointDistances[7] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); //Side Vertices x1 = VertexPair[8, 0] = vertices[0]; x2 = VertexPair[8, 1] = vertices[4]; PointDistances[8] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[9, 0] = vertices[1]; x2 = VertexPair[9, 1] = vertices[5]; PointDistances[9] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[10, 0] = vertices[2]; x2 = VertexPair[10, 1] = vertices[6]; PointDistances[10] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[11, 0] = vertices[3]; x2 = VertexPair[11, 1] = vertices[7]; PointDistances[11] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); index = 0; for (int i = 0; i < PointDistances.Length; i++) { if (PointDistances[index] > PointDistances[i]) { index = i; } } if (PointDistances[index] < sphere.Radius) { x1 = VertexPair[index, 0]; x2 = VertexPair[index, 1]; //Required to compute point on the line float t = -Vector3.Dot((x1 - x0), (x2 - x1)) / (x2 - x1).LengthSquared(); Vector3 LinePoint = new Vector3(x1.X + (x2.X - x1.X) * t, x1.Y + (x2.Y - x1.Y) * t, x1.Z + (x2.Z - x1.Z) * t); contact.ContactType = CollisionType.EdgeFace; contact.ContactNormal = Vector3.Normalize(x0 - LinePoint); contact.ContactPoint = LinePoint; contact.DeepestPoint = x0 - contact.ContactNormal / contact.ContactNormal.Length() * sphere.Radius; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); return(contact); } #endregion } //No Contact found... return(null); }