public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector p1, out JVector p2, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = JVector.Zero; JVector r = position1 - position2; JVector w, v; JVector supVertexA; JVector rn, vn; rn = JVector.Negate(r); SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); JVector supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = JVector.Zero; int iter = 0; float distSq = v.LengthSquared(); float epsilon = 0.00001f; while ((distSq > epsilon) && (iter++ < MaxIterations)) { IterationsTaken = iter; vn = JVector.Negate(v); SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, supVertexA, supVertexB); if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); normal = v; } else distSq = 0.0f; } simplexSolver.ComputePoints(out p1, out p2); if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) normal.Normalize(); simplexSolverPool.GiveBack(simplexSolver); return true; }
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref TSMatrix orientation1, ref TSMatrix orientation2, ref TSVector position1, ref TSVector position2, out TSVector p1, out TSVector p2, out TSVector normal) { VoronoiSimplexSolver @new = GJKCollide.simplexSolverPool.GetNew(); @new.Reset(); p1 = (p2 = TSVector.zero); TSVector value = position1 - position2; TSVector tSVector = TSVector.Negate(value); TSVector tSVector2; GJKCollide.SupportMapTransformed(support1, ref orientation1, ref position1, ref tSVector, out tSVector2); TSVector tSVector3; GJKCollide.SupportMapTransformed(support2, ref orientation2, ref position2, ref value, out tSVector3); TSVector tSVector4 = tSVector2 - tSVector3; normal = TSVector.zero; int num = 15; FP x = tSVector4.sqrMagnitude; FP eN = FP.EN5; while (x > eN && num-- != 0) { TSVector tSVector5 = TSVector.Negate(tSVector4); GJKCollide.SupportMapTransformed(support1, ref orientation1, ref position1, ref tSVector5, out tSVector2); GJKCollide.SupportMapTransformed(support2, ref orientation2, ref position2, ref tSVector4, out tSVector3); TSVector w = tSVector2 - tSVector3; bool flag = [email protected](w); if (flag) { @new.AddVertex(w, tSVector2, tSVector3); } bool flag2 = @new.Closest(out tSVector4); if (flag2) { x = tSVector4.sqrMagnitude; normal = tSVector4; } else { x = FP.Zero; } } @new.ComputePoints(out p1, out p2); bool flag3 = normal.sqrMagnitude > TSMath.Epsilon * TSMath.Epsilon; if (flag3) { normal.Normalize(); } GJKCollide.simplexSolverPool.GiveBack(@new); return(true); }
//https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm private bool RayIntersectsTriangle(ISupportMappable support, ref TSMatrix orientation, ref TSMatrix invOrientation, ref TSVector position, ref TSVector origin, ref TSVector direction, out FP fraction, out TSVector normal) { FP EPSILON = FP.EN8; fraction = FP.Zero; normal = TSVector.zero; TriangleMeshShape inTriangle = support as TriangleMeshShape; TSVector[] vertices = inTriangle.Vertices; TSVector vertex0 = vertices[0]; TSVector vertex1 = vertices[1]; TSVector vertex2 = vertices[2]; TSVector edge1, edge2, h, s, q; FP a, f, u, v; edge1 = inTriangle.edge1; edge2 = inTriangle.edge2; h = TSVector.Cross(direction, edge2); a = TSVector.Dot(edge1, h); if (a > -EPSILON && a < EPSILON) { return(false); } f = 1 / a; s = origin - vertex0; u = f * (TSVector.Dot(s, h)); if (u < FP.Zero || u > FP.One) { return(false); } q = TSVector.Cross(s, edge1); v = f * TSVector.Dot(direction, q); if (v < FP.Zero || u + v > FP.One) { return(false); } // At this stage we can compute t to find out where the intersection point is on the line. fraction = f * TSVector.Dot(edge2, q); if (fraction > EPSILON) // ray intersection { return(true); } else // This means that there is a line intersection but not a ray intersection. { return(false); } }
private static void SupportMapTransformed(ISupportMappable support, ref TSMatrix orientation, ref TSVector position, ref TSVector direction, out TSVector result) { result.x = direction.x * orientation.M11 + direction.y * orientation.M12 + direction.z * orientation.M13; result.y = direction.x * orientation.M21 + direction.y * orientation.M22 + direction.z * orientation.M23; result.z = direction.x * orientation.M31 + direction.y * orientation.M32 + direction.z * orientation.M33; support.SupportMapping(ref result, out result); FP y = result.x * orientation.M11 + result.y * orientation.M21 + result.z * orientation.M31; FP y2 = result.x * orientation.M12 + result.y * orientation.M22 + result.z * orientation.M32; FP y3 = result.x * orientation.M13 + result.y * orientation.M23 + result.z * orientation.M33; result.x = position.x + y; result.y = position.y + y2; result.z = position.z + y3; }
/// <summary> /// Checks if given point is within a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="point">The point to check.</param> /// <returns>Returns true if the point is within the shape, otherwise false.</returns> public static bool Pointcast(ISupportMappable support, ref JMatrix orientation,ref JVector position,ref JVector point) { JVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref point, out arbitraryPoint); JVector.Subtract(ref point, ref arbitraryPoint, out arbitraryPoint); JVector r; support.SupportCenter(out r); JVector.Transform(ref r, ref orientation, out r); JVector.Add(ref position, ref r, out r); JVector.Subtract(ref point, ref r, out r); JVector x = point; JVector w, p; float VdotR; JVector v; JVector.Subtract(ref x, ref arbitraryPoint, out v); float dist = v.LengthSquared(); float epsilon = 0.0001f; int maxIter = MaxIterations; VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); while ((dist > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); JVector.Subtract(ref x, ref p, out w); float VdotW = JVector.Dot(ref v, ref w); if (VdotW > 0.0f) { VdotR = JVector.Dot(ref v, ref r); if (VdotR >= -(JMath.Epsilon * JMath.Epsilon)) { simplexSolverPool.GiveBack(simplexSolver); return false; } else simplexSolver.Reset(); } if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, x, p); if (simplexSolver.Closest(out v)) dist = v.LengthSquared(); else dist = 0.0f; } simplexSolverPool.GiveBack(simplexSolver); return true; }
public static void SupportMapTransformed(ISupportMappable support, ref JMatrix orientation, ref JVector position, ref JVector direction, out JVector result) { // THIS IS *THE* HIGH FREQUENCY CODE OF THE COLLLISION PART OF THE ENGINE result.X = ((direction.X * orientation.M11) + (direction.Y * orientation.M12)); result.Y = ((direction.X * orientation.M21) + (direction.Y * orientation.M22)); support.SupportMapping(ref result, out result); float x = ((result.X * orientation.M11) + (result.Y * orientation.M21)); float y = ((result.X * orientation.M12) + (result.Y * orientation.M22)); result.X = position.X + x; result.Y = position.Y + y; }
private static void SupportMapTransformed(ISupportMappable support, ref FPMatrix orientation, ref FPVector position, ref FPVector direction, out FPVector result) { // THIS IS *THE* HIGH FREQUENCY CODE OF THE COLLLISION PART OF THE ENGINE result.x = ((direction.x * orientation.M11) + (direction.y * orientation.M12)) + (direction.z * orientation.M13); result.y = ((direction.x * orientation.M21) + (direction.y * orientation.M22)) + (direction.z * orientation.M23); result.z = ((direction.x * orientation.M31) + (direction.y * orientation.M32)) + (direction.z * orientation.M33); support.SupportMapping(ref result, out result); FP x = ((result.x * orientation.M11) + (result.y * orientation.M21)) + (result.z * orientation.M31); FP y = ((result.x * orientation.M12) + (result.y * orientation.M22)) + (result.z * orientation.M32); FP z = ((result.x * orientation.M13) + (result.y * orientation.M23)) + (result.z * orientation.M33); result.x = position.x + x; result.y = position.y + y; result.z = position.z + z; }
private static void SupportMapTransformed(ISupportMappable support, ref JMatrix orientation, ref JVector position, ref JVector direction, out JVector result) { // THIS IS *THE* HIGH FREQUENCY CODE OF THE COLLLISION PART OF THE ENGINE result.X = ((direction.X * orientation.M11) + (direction.Y * orientation.M12)) + (direction.Z * orientation.M13); result.Y = ((direction.X * orientation.M21) + (direction.Y * orientation.M22)) + (direction.Z * orientation.M23); result.Z = ((direction.X * orientation.M31) + (direction.Y * orientation.M32)) + (direction.Z * orientation.M33); support.SupportMapping(ref result, out result); double x = ((result.X * orientation.M11) + (result.Y * orientation.M21)) + (result.Z * orientation.M31); double y = ((result.X * orientation.M12) + (result.Y * orientation.M22)) + (result.Z * orientation.M32); double z = ((result.X * orientation.M13) + (result.Y * orientation.M23)) + (result.Z * orientation.M33); result.X = position.X + x; result.Y = position.Y + y; result.Z = position.Z + z; }
private static void SupportMapTransformed(ISupportMappable support, ref JMatrix orientation, ref JVector position, ref JVector direction, out JVector result) { //JVector.Transform(ref direction, ref invOrientation, out result); //support.SupportMapping(ref result, out result); //JVector.Transform(ref result, ref orientation, out result); //JVector.Add(ref result, ref position, out result); result.X = ((direction.X * orientation.M11) + (direction.Y * orientation.M12)) + (direction.Z * orientation.M13); result.Y = ((direction.X * orientation.M21) + (direction.Y * orientation.M22)) + (direction.Z * orientation.M23); result.Z = ((direction.X * orientation.M31) + (direction.Y * orientation.M32)) + (direction.Z * orientation.M33); support.SupportMapping(ref result, out result); float x = ((result.X * orientation.M11) + (result.Y * orientation.M21)) + (result.Z * orientation.M31); float y = ((result.X * orientation.M12) + (result.Y * orientation.M22)) + (result.Z * orientation.M32); float z = ((result.X * orientation.M13) + (result.Y * orientation.M23)) + (result.Z * orientation.M33); result.X = position.X + x; result.Y = position.Y + y; result.Z = position.Z + z; }
private static void SupportMapTransformed(ISupportMappable support, ref Matrix3x3 orientation, ref Vector3 position, ref Vector3 direction, out Vector3 result) { //JVector.Transform(ref direction, ref invOrientation, out result); //support.SupportMapping(ref result, out result); //JVector.Transform(ref result, ref orientation, out result); //JVector.Add(ref result, ref position, out result); result.x = ((direction.x * orientation.M11) + (direction.y * orientation.M12)) + (direction.z * orientation.M13); result.y = ((direction.x * orientation.M21) + (direction.y * orientation.M22)) + (direction.z * orientation.M23); result.z = ((direction.x * orientation.M31) + (direction.y * orientation.M32)) + (direction.z * orientation.M33); support.SupportMapping(ref result, out result); float x = ((result.x * orientation.M11) + (result.y * orientation.M21)) + (result.z * orientation.M31); float y = ((result.x * orientation.M12) + (result.y * orientation.M22)) + (result.z * orientation.M32); float z = ((result.x * orientation.M13) + (result.y * orientation.M23)) + (result.z * orientation.M33); result.x = position.x + x; result.y = position.y + y; result.z = position.z + z; }
private static void SupportMapTransformed(ISupportMappable support, ref MatrixD orientation, ref Vector3D position, ref Vector3D direction, out Vector3D result) { //Vector3D.Transform(ref direction, ref invOrientation, out result); //support.SupportMapping(ref result, out result); //Vector3D.Transform(ref result, ref orientation, out result); //Vector3D.Add(ref result, ref position, out result); result.X = ((direction.X * orientation.M11) + (direction.Y * orientation.M12)) + (direction.Z * orientation.M13); result.Y = ((direction.X * orientation.M21) + (direction.Y * orientation.M22)) + (direction.Z * orientation.M23); result.Z = ((direction.X * orientation.M31) + (direction.Y * orientation.M32)) + (direction.Z * orientation.M33); support.SupportMapping(ref result, out result); double x = ((result.X * orientation.M11) + (result.Y * orientation.M21)) + (result.Z * orientation.M31); double y = ((result.X * orientation.M12) + (result.Y * orientation.M22)) + (result.Z * orientation.M32); double z = ((result.X * orientation.M13) + (result.Y * orientation.M23)) + (result.Z * orientation.M33); result.X = position.X + x; result.Y = position.Y + y; result.Z = position.Z + z; }
private static void SupportMapTransformed(ISupportMappable support, ref TSMatrix orientation, ref TSVector position, ref TSVector direction, out TSVector result) { //JVector.Transform(ref direction, ref invOrientation, out result); //support.SupportMapping(ref result, out result); //JVector.Transform(ref result, ref orientation, out result); //JVector.Add(ref result, ref position, out result); result.x = ((direction.x * orientation.M11) + (direction.y * orientation.M12)) + (direction.z * orientation.M13); result.y = ((direction.x * orientation.M21) + (direction.y * orientation.M22)) + (direction.z * orientation.M23); result.z = ((direction.x * orientation.M31) + (direction.y * orientation.M32)) + (direction.z * orientation.M33); support.SupportMapping(ref result, out result); FP x = ((result.x * orientation.M11) + (result.y * orientation.M21)) + (result.z * orientation.M31); FP y = ((result.x * orientation.M12) + (result.y * orientation.M22)) + (result.z * orientation.M32); FP z = ((result.x * orientation.M13) + (result.y * orientation.M23)) + (result.z * orientation.M33); result.x = position.x + x; result.y = position.y + y; result.z = position.z + z; }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector point, out JVector normal, out float penetration) { // Used variables JVector temp1, temp2; JVector v01, v02, v0; JVector v11, v12, v1; JVector v21, v22, v2; JVector v31, v32, v3; JVector v41, v42, v4; JVector mn; // Initialization of the output point = normal = JVector.Zero; penetration = 0.0f; //JVector right = JVector.Right; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); JVector.Transform(ref v01, ref orientation1, out v01); JVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); JVector.Transform(ref v02, ref orientation2, out v02); JVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference JVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) { v0 = new JVector(0.00001f, 0, 0); } // v1 = support in direction of origin mn = v0; JVector.Negate(ref v0, out normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); JVector.Subtract(ref v12, ref v11, out v1); if (JVector.Dot(ref v1, ref normal) <= 0.0f) { return(false); } // v2 = support perpendicular to v1,v0 JVector.Cross(ref v1, ref v0, out normal); if (normal.IsNearlyZero()) { JVector.Subtract(ref v1, ref v0, out normal); normal.Normalize(); point = v11; JVector.Add(ref point, ref v12, out point); JVector.Multiply(ref point, 0.5f, out point); JVector.Subtract(ref v12, ref v11, out temp1); penetration = JVector.Dot(ref temp1, ref normal); //point = v11; //point2 = v12; return(true); } JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); JVector.Subtract(ref v22, ref v21, out v2); if (JVector.Dot(ref v2, ref normal) <= 0.0f) { return(false); } // Determine whether origin is on + or - side of plane (v1,v0,v2) JVector.Subtract(ref v1, ref v0, out temp1); JVector.Subtract(ref v2, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); float dist = JVector.Dot(ref normal, ref v0); // If the origin is on the - side of the plane, reverse the direction of the plane if (dist > 0.0f) { JVector.Swap(ref v1, ref v2); JVector.Swap(ref v11, ref v21); JVector.Swap(ref v12, ref v22); JVector.Negate(ref normal, out normal); } int phase2 = 0; int phase1 = 0; bool hit = false; // Phase One: Identify a portal while (true) { if (phase1 > MaximumIterations) { return(false); } phase1++; // Obtain the support point in a direction perpendicular to the existing plane // Note: This point is guaranteed to lie off the plane JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); JVector.Subtract(ref v32, ref v31, out v3); if (JVector.Dot(ref v3, ref normal) <= 0.0f) { return(false); } // If origin is outside (v1,v0,v3), then eliminate v2 and loop JVector.Cross(ref v1, ref v3, out temp1); if (JVector.Dot(ref temp1, ref v0) < 0.0f) { v2 = v3; v21 = v31; v22 = v32; JVector.Subtract(ref v1, ref v0, out temp1); JVector.Subtract(ref v3, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); continue; } // If origin is outside (v3,v0,v2), then eliminate v1 and loop JVector.Cross(ref v3, ref v2, out temp1); if (JVector.Dot(ref temp1, ref v0) < 0.0f) { v1 = v3; v11 = v31; v12 = v32; JVector.Subtract(ref v3, ref v0, out temp1); JVector.Subtract(ref v2, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); continue; } // Phase Two: Refine the portal // We are now inside of a wedge... while (true) { phase2++; // Compute normal of the wedge face JVector.Subtract(ref v2, ref v1, out temp1); JVector.Subtract(ref v3, ref v1, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); // Can this happen??? Can it be handled more cleanly? if (normal.IsNearlyZero()) { return(true); } normal.Normalize(); // Compute distance from origin to wedge face float d = JVector.Dot(ref normal, ref v1); // If the origin is inside the wedge, we have a hit if (d >= 0 && !hit) { // HIT!!! hit = true; } // Find the support point in the direction of the wedge face JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v41); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v42); JVector.Subtract(ref v42, ref v41, out v4); JVector.Subtract(ref v4, ref v3, out temp1); float delta = JVector.Dot(ref temp1, ref normal); penetration = JVector.Dot(ref v4, ref normal); // If the boundary is thin enough or the origin is outside the support plane for the newly discovered vertex, then we can terminate if (delta <= CollideEpsilon || penetration <= 0.0f || phase2 > MaximumIterations) { if (hit) { JVector.Cross(ref v1, ref v2, out temp1); float b0 = JVector.Dot(ref temp1, ref v3); JVector.Cross(ref v3, ref v2, out temp1); float b1 = JVector.Dot(ref temp1, ref v0); JVector.Cross(ref v0, ref v1, out temp1); float b2 = JVector.Dot(ref temp1, ref v3); JVector.Cross(ref v2, ref v1, out temp1); float b3 = JVector.Dot(ref temp1, ref v0); float sum = b0 + b1 + b2 + b3; if (sum <= 0) { b0 = 0; JVector.Cross(ref v2, ref v3, out temp1); b1 = JVector.Dot(ref temp1, ref normal); JVector.Cross(ref v3, ref v1, out temp1); b2 = JVector.Dot(ref temp1, ref normal); JVector.Cross(ref v1, ref v2, out temp1); b3 = JVector.Dot(ref temp1, ref normal); sum = b1 + b2 + b3; } float inv = 1.0f / sum; JVector.Multiply(ref v01, b0, out point); JVector.Multiply(ref v11, b1, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v21, b2, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v31, b3, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v02, b0, out temp2); JVector.Add(ref temp2, ref point, out point); JVector.Multiply(ref v12, b1, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v22, b2, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v32, b3, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref point, inv * 0.5f, out point); } // Compute the barycentric coordinates of the origin return(hit); } ////// Compute the tetrahedron dividing face (v4,v0,v1) //JVector.Cross(ref v4, ref v1, out temp1); //float d1 = JVector.Dot(ref temp1, ref v0); ////// Compute the tetrahedron dividing face (v4,v0,v2) //JVector.Cross(ref v4, ref v2, out temp1); //float d2 = JVector.Dot(ref temp1, ref v0); // Compute the tetrahedron dividing face (v4,v0,v3) JVector.Cross(ref v4, ref v0, out temp1); float dot = JVector.Dot(ref temp1, ref v1); if (dot >= 0.0f) { dot = JVector.Dot(ref temp1, ref v2); if (dot >= 0.0f) { // Inside d1 & inside d2 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } else { // Inside d1 & outside d2 ==> eliminate v3 v3 = v4; v31 = v41; v32 = v42; } } else { dot = JVector.Dot(ref temp1, ref v3); if (dot >= 0.0f) { // Outside d1 & inside d3 ==> eliminate v2 v2 = v4; v21 = v41; v22 = v42; } else { // Outside d1 & outside d3 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } } } } }
// see: btSubSimplexConvexCast.cpp /// <summary> /// Checks if a ray definied through it's origin and direction collides /// with a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="origin">The origin of the ray.</param> /// <param name="direction">The direction of the ray.</param> /// <param name="fraction">The fraction which gives information where at the /// ray the collision occured. The hitPoint is calculated by: origin+friction*direction.</param> /// <param name="normal">The normal from the ray collision.</param> /// <returns>Returns true if the ray hit the shape, false otherwise.</returns> public static bool Raycast(ISupportMappable support, ref JMatrix orientation, ref JMatrix invOrientation, ref JVector position,ref JVector origin,ref JVector direction, out float fraction, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); normal = JVector.Zero; fraction = float.MaxValue; float lambda = 0.0f; JVector r = direction; JVector x = origin; JVector w, p, v; JVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref r, out arbitraryPoint); JVector.Subtract(ref x, ref arbitraryPoint, out v); int maxIter = MaxIterations; float distSq = v.LengthSquared(); float epsilon = 0.000001f; float VdotR; while ((distSq > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); JVector.Subtract(ref x, ref p, out w); float VdotW = JVector.Dot(ref v, ref w); if (VdotW > 0.0f) { VdotR = JVector.Dot(ref v, ref r); if (VdotR >= -JMath.Epsilon) { simplexSolverPool.GiveBack(simplexSolver); return false; } else { lambda = lambda - VdotW / VdotR; JVector.Multiply(ref r, lambda, out x); JVector.Add(ref origin, ref x, out x); JVector.Subtract(ref x, ref p, out w); normal = v; } } if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, x, p); if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); } else distSq = 0.0f; } #region Retrieving hitPoint // Giving back the fraction like this *should* work // but is inaccurate against large objects: // fraction = lambda; JVector p1, p2; simplexSolver.ComputePoints(out p1, out p2); p2 = p2 - origin; fraction = p2.Length() / direction.Length(); #endregion if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) normal.Normalize(); simplexSolverPool.GiveBack(simplexSolver); return true; }
private static void SupportMapTransformed( ISupportMappable support, in JMatrix orientation,
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector p1, out JVector p2, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = JVector.Zero; JVector r = position1 - position2; JVector w, v; JVector supVertexA; JVector rn, vn; rn = JVector.Negate(r); SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); JVector supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = JVector.Zero; int iter = 0; float distSq = v.LengthSquared(); float epsilon = 0.00001f; while ((distSq > epsilon) && (iter++ < MaxIterations)) { IterationsTaken = iter; vn = JVector.Negate(v); SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, supVertexA, supVertexB); } if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); normal = v; } else { distSq = 0.0f; } } simplexSolver.ComputePoints(out p1, out p2); if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
public static bool Pointcast(ISupportMappable support, ref TSMatrix orientation, ref TSVector position, ref TSVector point) { TSVector tSVector; GJKCollide.SupportMapTransformed(support, ref orientation, ref position, ref point, out tSVector); TSVector.Subtract(ref point, ref tSVector, out tSVector); TSVector tSVector2; support.SupportCenter(out tSVector2); TSVector.Transform(ref tSVector2, ref orientation, out tSVector2); TSVector.Add(ref position, ref tSVector2, out tSVector2); TSVector.Subtract(ref point, ref tSVector2, out tSVector2); TSVector p = point; TSVector tSVector3; TSVector.Subtract(ref p, ref tSVector, out tSVector3); FP x = tSVector3.sqrMagnitude; FP eN = FP.EN4; int num = 15; VoronoiSimplexSolver @new = GJKCollide.simplexSolverPool.GetNew(); @new.Reset(); bool result; while (x > eN && num-- != 0) { TSVector q; GJKCollide.SupportMapTransformed(support, ref orientation, ref position, ref tSVector3, out q); TSVector w; TSVector.Subtract(ref p, ref q, out w); FP x2 = TSVector.Dot(ref tSVector3, ref w); bool flag = x2 > FP.Zero; if (flag) { FP x3 = TSVector.Dot(ref tSVector3, ref tSVector2); bool flag2 = x3 >= -(TSMath.Epsilon * TSMath.Epsilon); if (flag2) { GJKCollide.simplexSolverPool.GiveBack(@new); result = false; return(result); } @new.Reset(); } bool flag3 = [email protected](w); if (flag3) { @new.AddVertex(w, p, q); } bool flag4 = @new.Closest(out tSVector3); if (flag4) { x = tSVector3.sqrMagnitude; } else { x = FP.Zero; } } GJKCollide.simplexSolverPool.GiveBack(@new); result = true; return(result); }
public static bool Raycast(ISupportMappable support, ref TSMatrix orientation, ref TSMatrix invOrientation, ref TSVector position, ref TSVector origin, ref TSVector direction, out FP fraction, out TSVector normal) { VoronoiSimplexSolver @new = GJKCollide.simplexSolverPool.GetNew(); @new.Reset(); normal = TSVector.zero; fraction = FP.MaxValue; FP fP = FP.Zero; TSVector tSVector = direction; TSVector p = origin; TSVector tSVector2; GJKCollide.SupportMapTransformed(support, ref orientation, ref position, ref tSVector, out tSVector2); TSVector tSVector3; TSVector.Subtract(ref p, ref tSVector2, out tSVector3); int num = 15; FP x = tSVector3.sqrMagnitude; FP eN = FP.EN6; bool result; while (x > eN && num-- != 0) { TSVector q; GJKCollide.SupportMapTransformed(support, ref orientation, ref position, ref tSVector3, out q); TSVector w; TSVector.Subtract(ref p, ref q, out w); FP x2 = TSVector.Dot(ref tSVector3, ref w); bool flag = x2 > FP.Zero; if (flag) { FP fP2 = TSVector.Dot(ref tSVector3, ref tSVector); bool flag2 = fP2 >= -TSMath.Epsilon; if (flag2) { GJKCollide.simplexSolverPool.GiveBack(@new); result = false; return(result); } fP -= x2 / fP2; TSVector.Multiply(ref tSVector, fP, out p); TSVector.Add(ref origin, ref p, out p); TSVector.Subtract(ref p, ref q, out w); normal = tSVector3; } bool flag3 = [email protected](w); if (flag3) { @new.AddVertex(w, p, q); } bool flag4 = @new.Closest(out tSVector3); if (flag4) { x = tSVector3.sqrMagnitude; } else { x = FP.Zero; } } TSVector tSVector4; TSVector value; @new.ComputePoints(out tSVector4, out value); value -= origin; fraction = value.magnitude / direction.magnitude; bool flag5 = normal.sqrMagnitude > TSMath.Epsilon * TSMath.Epsilon; if (flag5) { normal.Normalize(); } GJKCollide.simplexSolverPool.GiveBack(@new); result = true; return(result); }
// see: btSubSimplexConvexCast.cpp /// <summary> /// Checks if a ray definied through it's origin and direction collides /// with a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="origin">The origin of the ray.</param> /// <param name="direction">The direction of the ray.</param> /// <param name="fraction">The fraction which gives information where at the /// ray the collision occured. The hitPoint is calculated by: origin+friction*direction.</param> /// <param name="normal">The normal from the ray collision.</param> /// <returns>Returns true if the ray hit the shape, false otherwise.</returns> public static bool Raycast(ISupportMappable support, ref MatrixD orientation, ref MatrixD invOrientation, ref Vector3D position, ref Vector3D origin, ref Vector3D direction, out double fraction, out Vector3D normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); normal = Vector3D.Zero; fraction = double.MaxValue; double lambda = 0.0f; Vector3D r = direction; Vector3D x = origin; Vector3D w, p, v; Vector3D arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref r, out arbitraryPoint); Vector3D.Subtract(ref x, ref arbitraryPoint, out v); int maxIter = MaxIterations; double distSq = v.LengthSquared(); double epsilon = 0.000001f; double VdotR; while ((distSq > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); Vector3D.Subtract(ref x, ref p, out w); double VdotW = Vector3D.Dot(v, w); if (VdotW > 0.0f) { VdotR = Vector3D.Dot(v, r); if (VdotR >= -MathHelper.EPSILON) { simplexSolverPool.GiveBack(simplexSolver); return(false); } else { lambda = lambda - VdotW / VdotR; Vector3D.Multiply(ref r, lambda, out x); Vector3D.Add(ref origin, ref x, out x); Vector3D.Subtract(ref x, ref p, out w); normal = v; } } if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, x, p); } if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); } else { distSq = 0.0f; } } #region Retrieving hitPoint // Giving back the fraction like this *should* work // but is inaccurate against large objects: // fraction = lambda; Vector3D p1, p2; simplexSolver.ComputePoints(out p1, out p2); p2 = p2 - origin; fraction = p2.Length() / direction.Length(); #endregion if (normal.LengthSquared() > MathHelper.EPSILON * MathHelper.EPSILON) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref FPMatrix orientation1, ref FPMatrix orientation2, ref FPVector position1, ref FPVector position2, out FPVector point, out FPVector normal, out FP penetration) { // Used variables FPVector temp1, temp2; FPVector v01, v02, v0; FPVector v11, v12, v1; FPVector v21, v22, v2; FPVector v31, v32, v3; FPVector v41 = FPVector.zero, v42 = FPVector.zero, v4 = FPVector.zero; FPVector mn; // Initialization of the output point = normal = FPVector.zero; penetration = FP.Zero; //JVector right = JVector.Right; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); FPVector.Transform(ref v01, ref orientation1, out v01); FPVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); FPVector.Transform(ref v02, ref orientation2, out v02); FPVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference FPVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) { v0 = new FPVector(FP.EN4, 0, 0); } // v1 = support in direction of origin mn = v0; FPVector.Negate(ref v0, out normal); //UnityEngine.Debug.Log("normal: " + normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); FPVector.Subtract(ref v12, ref v11, out v1); if (FPVector.Dot(ref v1, ref normal) <= FP.Zero) { return(false); } // v2 = support perpendicular to v1,v0 FPVector.Cross(ref v1, ref v0, out normal); if (normal.IsNearlyZero()) { FPVector.Subtract(ref v1, ref v0, out normal); //UnityEngine.Debug.Log("normal: " + normal); normal.Normalize(); point = v11; FPVector.Add(ref point, ref v12, out point); FPVector.Multiply(ref point, FP.Half, out point); FPVector.Subtract(ref v12, ref v11, out temp1); penetration = FPVector.Dot(ref temp1, ref normal); //point = v11; //point2 = v12; return(true); } FPVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); FPVector.Subtract(ref v22, ref v21, out v2); if (FPVector.Dot(ref v2, ref normal) <= FP.Zero) { return(false); } // Determine whether origin is on + or - side of plane (v1,v0,v2) FPVector.Subtract(ref v1, ref v0, out temp1); FPVector.Subtract(ref v2, ref v0, out temp2); FPVector.Cross(ref temp1, ref temp2, out normal); FP dist = FPVector.Dot(ref normal, ref v0); // If the origin is on the - side of the plane, reverse the direction of the plane if (dist > FP.Zero) { FPVector.Swap(ref v1, ref v2); FPVector.Swap(ref v11, ref v21); FPVector.Swap(ref v12, ref v22); FPVector.Negate(ref normal, out normal); UnityEngine.Debug.Log("normal: " + normal); } int phase2 = 0; int phase1 = 0; bool hit = false; // Phase One: Identify a portal while (true) { if (phase1 > MaximumIterations) { return(false); } phase1++; // Obtain the support point in a direction perpendicular to the existing plane // Note: This point is guaranteed to lie off the plane FPVector.Negate(ref normal, out mn); //UnityEngine.Debug.Log("mn: " + mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); FPVector.Subtract(ref v32, ref v31, out v3); if (FPVector.Dot(ref v3, ref normal) <= FP.Zero) { return(false); } // If origin is outside (v1,v0,v3), then eliminate v2 and loop FPVector.Cross(ref v1, ref v3, out temp1); if (FPVector.Dot(ref temp1, ref v0) < FP.Zero) { v2 = v3; v21 = v31; v22 = v32; FPVector.Subtract(ref v1, ref v0, out temp1); FPVector.Subtract(ref v3, ref v0, out temp2); FPVector.Cross(ref temp1, ref temp2, out normal); // UnityEngine.Debug.Log("normal: " + normal); continue; } // If origin is outside (v3,v0,v2), then eliminate v1 and loop FPVector.Cross(ref v3, ref v2, out temp1); if (FPVector.Dot(ref temp1, ref v0) < FP.Zero) { v1 = v3; v11 = v31; v12 = v32; FPVector.Subtract(ref v3, ref v0, out temp1); FPVector.Subtract(ref v2, ref v0, out temp2); FPVector.Cross(ref temp1, ref temp2, out normal); //UnityEngine.Debug.Log("normal: " + normal); continue; } // Phase Two: Refine the portal // We are now inside of a wedge... while (true) { phase2++; /* * UnityEngine.Debug.LogError(" ::Start STATE"); * UnityEngine.Debug.Log(temp1 + " " + temp2); * UnityEngine.Debug.Log( v01 + " " + v02 + " "+ v0); * UnityEngine.Debug.Log( v11+" "+ v12 +" "+ v1); * UnityEngine.Debug.Log( v21 +" "+ v22 +" "+ v2); * UnityEngine.Debug.Log( v31 +" "+ v32 +" "+ v3); * UnityEngine.Debug.Log( v41 +" "+ v42 +" "+ v4); * UnityEngine.Debug.Log( mn); * * UnityEngine.Debug.LogError(" ::END STATE"); */ // Compute normal of the wedge face FPVector.Subtract(ref v2, ref v1, out temp1); FPVector.Subtract(ref v3, ref v1, out temp2); FPVector.Cross(ref temp1, ref temp2, out normal); // Beginer // UnityEngine.Debug.Log("normal: " + normal); // Can this happen??? Can it be handled more cleanly? if (normal.IsNearlyZero()) { return(true); } normal.Normalize(); //UnityEngine.Debug.Log("normal: " + normal); // Compute distance from origin to wedge face FP d = FPVector.Dot(ref normal, ref v1); // If the origin is inside the wedge, we have a hit if (d >= 0 && !hit) { // HIT!!! hit = true; } // Find the support point in the direction of the wedge face FPVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v41); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v42); FPVector.Subtract(ref v42, ref v41, out v4); FPVector.Subtract(ref v4, ref v3, out temp1); FP delta = FPVector.Dot(ref temp1, ref normal); penetration = FPVector.Dot(ref v4, ref normal); // If the boundary is thin enough or the origin is outside the support plane for the newly discovered vertex, then we can terminate if (delta <= CollideEpsilon || penetration <= FP.Zero || phase2 > MaximumIterations) { if (hit) { FPVector.Cross(ref v1, ref v2, out temp1); FP b0 = FPVector.Dot(ref temp1, ref v3); FPVector.Cross(ref v3, ref v2, out temp1); FP b1 = FPVector.Dot(ref temp1, ref v0); FPVector.Cross(ref v0, ref v1, out temp1); FP b2 = FPVector.Dot(ref temp1, ref v3); FPVector.Cross(ref v2, ref v1, out temp1); FP b3 = FPVector.Dot(ref temp1, ref v0); FP sum = b0 + b1 + b2 + b3; if (sum <= 0) { b0 = 0; FPVector.Cross(ref v2, ref v3, out temp1); b1 = FPVector.Dot(ref temp1, ref normal); FPVector.Cross(ref v3, ref v1, out temp1); b2 = FPVector.Dot(ref temp1, ref normal); FPVector.Cross(ref v1, ref v2, out temp1); b3 = FPVector.Dot(ref temp1, ref normal); sum = b1 + b2 + b3; } FP inv = FP.One / sum; FPVector.Multiply(ref v01, b0, out point); FPVector.Multiply(ref v11, b1, out temp1); FPVector.Add(ref point, ref temp1, out point); FPVector.Multiply(ref v21, b2, out temp1); FPVector.Add(ref point, ref temp1, out point); FPVector.Multiply(ref v31, b3, out temp1); FPVector.Add(ref point, ref temp1, out point); FPVector.Multiply(ref v02, b0, out temp2); FPVector.Add(ref temp2, ref point, out point); FPVector.Multiply(ref v12, b1, out temp1); FPVector.Add(ref point, ref temp1, out point); FPVector.Multiply(ref v22, b2, out temp1); FPVector.Add(ref point, ref temp1, out point); FPVector.Multiply(ref v32, b3, out temp1); FPVector.Add(ref point, ref temp1, out point); FPVector.Multiply(ref point, inv * FP.Half, out point); } // Compute the barycentric coordinates of the origin return(hit); } //// Compute the tetrahedron dividing face (v4,v0,v1) //JVector.Cross(ref v4, ref v1, out temp1); //FP d1 = JVector.Dot(ref temp1, ref v0); //// Compute the tetrahedron dividing face (v4,v0,v2) //JVector.Cross(ref v4, ref v2, out temp1); //FP d2 = JVector.Dot(ref temp1, ref v0); // Compute the tetrahedron dividing face (v4,v0,v3) //UnityEngine.Debug.LogError("v4:" + v4 + " v0:" + v0); FPVector.Cross(ref v4, ref v0, out temp1); //UnityEngine.Debug.LogError("temp1:"+ temp1); //Ender // UnityEngine.Debug.Log("normal: " + normal); FP dot = FPVector.Dot(ref temp1, ref v1); if (dot >= FP.Zero) { // UnityEngine.Debug.Log("dot >= 0 temp1:" + temp1 + " v2:" + v2 ); dot = FPVector.Dot(ref temp1, ref v2); if (dot >= FP.Zero) { // UnityEngine.Debug.Log("dot >= 0 v1->v4"); // Inside d1 & inside d2 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } else { // UnityEngine.Debug.Log("dot < v3->v4"); // Inside d1 & outside d2 ==> eliminate v3 v3 = v4; v31 = v41; v32 = v42; } } else { // UnityEngine.Debug.Log("dot < 0 temp1:" + temp1 + " v3:" + v3 ); dot = FPVector.Dot(ref temp1, ref v3); if (dot >= FP.Zero) { // UnityEngine.Debug.Log("dot >= 0 v2 => v4"); // Outside d1 & inside d3 ==> eliminate v2 v2 = v4; v21 = v41; v22 = v42; } else { // UnityEngine.Debug.Log("dot < 0 v1 => v4"); // Outside d1 & outside d3 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } } } } }
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref MatrixD orientation1, ref MatrixD orientation2, ref Vector3D position1, ref Vector3D position2, out Vector3D p1, out Vector3D p2, out Vector3D normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = Vector3D.Zero; Vector3D r = position1 - position2; Vector3D w, v; Vector3D supVertexA; Vector3D rn, vn; rn = Vector3D.Negate(r); SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); Vector3D supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = Vector3D.Zero; int maxIter = 15; double distSq = v.LengthSquared(); double epsilon = 0.00001f; while ((distSq > epsilon) && (maxIter-- != 0)) { vn = Vector3D.Negate(v); SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, supVertexA, supVertexB); } if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); normal = v; } else { distSq = 0.0f; } } simplexSolver.ComputePoints(out p1, out p2); if (normal.LengthSquared() > MathHelper.EPSILON * MathHelper.EPSILON) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector point, out JVector normal, out float penetration) { // Used variables JVector v01, v02, v0; JVector v11, v12, v1; JVector v21, v22, v2; JVector v31, v32, v3; JVector mn; // Initialization of the output point = normal = JVector.Zero; penetration = 0.0f; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); JVector.Transform(ref v01, ref orientation1, out v01); JVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); JVector.Transform(ref v02, ref orientation2, out v02); JVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference JVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) v0 = new JVector(0.00001f, 0); // v1 = support in direction of origin mn = v0; JVector.Negate(ref v0, out normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); JVector.Subtract(ref v12, ref v11, out v1); if (JVector.Dot(ref v1, ref normal) <= 0.0f) return false; // v2 = support perpendicular to v1,v0 normal = OutsidePortal(v1, v0); JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); JVector.Subtract(ref v22, ref v21, out v2); //LD.Draw(Conversion.ToXNAVector2(v1), Conversion.ToXNAVector2(v0), Color.Blue); //LD.Draw(Conversion.ToXNAVector2(v2), Conversion.ToXNAVector2(v0), Color.Blue); if (JVector.Dot(ref v2, ref normal) <= 0.0f) return false; // phase two: portal refinement int maxIterations = 0; while (true) { // find normal direction if (!IntersectPortal(v0, v2, v1)) normal = InsidePortal(v2, v1); else // origin ray crosses the portal normal = OutsidePortal(v2, v1); // obtain the next support point JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); JVector.Subtract(ref v32, ref v31, out v3); //LD.Draw(Conversion.ToXNAVector2(v3), Conversion.ToXNAVector2(v0), Color.Green); if (JVector.Dot(v3, normal) <= 0) { JVector ab = v3 - v2; float t = -(JVector.Dot(v2, ab)) / (JVector.Dot(ab, ab)); normal = (v2 + (t * ab)); return false; } // Portal lies on the outside edge of the Minkowski Hull. // Return contact information if (JVector.Dot((v3 - v2), normal) <= CollideEpsilon || ++maxIterations > MaximumIterations) { JVector ab = v2 - v1; float t = JVector.Dot(JVector.Negate(v1), ab); if (t <= 0.0f) { t = 0.0f; normal = v1; } else { float denom = JVector.Dot(ab, ab); if (t >= denom) { normal = v2; t = 1.0f; } else { t /= denom; normal = v1 + t * ab; } } float s = 1 - t; point = s * v11 + t * v21; var point2 = s * v12 + t * v22; // this causes a sq root = bad! penetration = normal.Length(); normal.Normalize(); return true; } // if origin is inside (v1, v0, v3), refine portal if (OriginInTriangle(v0, v1, v3)) { v2 = v3; v21 = v31; v22 = v32; continue; } // if origin is inside (v3, v0, v2), refine portal else if (OriginInTriangle(v0, v2, v3)) { v1 = v3; v11 = v31; v12 = v32; continue; } return false; } }
/// <summary> /// Checks if given point is within a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="point">The point to check.</param> /// <returns>Returns true if the point is within the shape, otherwise false.</returns> public static bool Pointcast(ISupportMappable support, ref JMatrix orientation, ref JVector position, ref JVector point) { JVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref point, out arbitraryPoint); JVector.Subtract(ref point, ref arbitraryPoint, out arbitraryPoint); JVector r; support.SupportCenter(out r); JVector.Transform(ref r, ref orientation, out r); JVector.Add(ref position, ref r, out r); JVector.Subtract(ref point, ref r, out r); JVector x = point; JVector w, p; float VdotR; JVector v; JVector.Subtract(ref x, ref arbitraryPoint, out v); float dist = v.LengthSquared(); float epsilon = 0.0001f; int maxIter = MaxIterations; VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); while ((dist > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); JVector.Subtract(ref x, ref p, out w); float VdotW = JVector.Dot(ref v, ref w); if (VdotW > 0.0f) { VdotR = JVector.Dot(ref v, ref r); if (VdotR >= -(JMath.Epsilon * JMath.Epsilon)) { simplexSolverPool.GiveBack(simplexSolver); return(false); } else { simplexSolver.Reset(); } } if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, x, p); } if (simplexSolver.Closest(out v)) { dist = v.LengthSquared(); } else { dist = 0.0f; } } simplexSolverPool.GiveBack(simplexSolver); return(true); }
public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref TSMatrix orientation1, ref TSMatrix orientation2, ref TSVector position1, ref TSVector position2, out TSVector point, out TSVector normal, out FP penetration) { TSVector zero = TSVector.zero; TSVector zero2 = TSVector.zero; TSVector zero3 = TSVector.zero; point = (normal = TSVector.zero); penetration = FP.Zero; TSVector tSVector; support1.SupportCenter(out tSVector); TSVector.Transform(ref tSVector, ref orientation1, out tSVector); TSVector.Add(ref position1, ref tSVector, out tSVector); TSVector tSVector2; support2.SupportCenter(out tSVector2); TSVector.Transform(ref tSVector2, ref orientation2, out tSVector2); TSVector.Add(ref position2, ref tSVector2, out tSVector2); TSVector tSVector3; TSVector.Subtract(ref tSVector2, ref tSVector, out tSVector3); bool flag = tSVector3.IsNearlyZero(); if (flag) { tSVector3 = new TSVector(FP.EN4, 0, 0); } TSVector tSVector4 = tSVector3; TSVector.Negate(ref tSVector3, out normal); TSVector tSVector5; XenoCollide.SupportMapTransformed(support1, ref orientation1, ref position1, ref tSVector4, out tSVector5); TSVector tSVector6; XenoCollide.SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out tSVector6); TSVector tSVector7; TSVector.Subtract(ref tSVector6, ref tSVector5, out tSVector7); bool flag2 = TSVector.Dot(ref tSVector7, ref normal) <= FP.Zero; bool result; if (flag2) { result = false; } else { TSVector.Cross(ref tSVector7, ref tSVector3, out normal); bool flag3 = normal.IsNearlyZero(); if (flag3) { TSVector.Subtract(ref tSVector7, ref tSVector3, out normal); normal.Normalize(); point = tSVector5; TSVector.Add(ref point, ref tSVector6, out point); TSVector.Multiply(ref point, FP.Half, out point); TSVector tSVector8; TSVector.Subtract(ref tSVector6, ref tSVector5, out tSVector8); penetration = TSVector.Dot(ref tSVector8, ref normal); result = true; } else { TSVector.Negate(ref normal, out tSVector4); TSVector tSVector9; XenoCollide.SupportMapTransformed(support1, ref orientation1, ref position1, ref tSVector4, out tSVector9); TSVector tSVector10; XenoCollide.SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out tSVector10); TSVector tSVector11; TSVector.Subtract(ref tSVector10, ref tSVector9, out tSVector11); bool flag4 = TSVector.Dot(ref tSVector11, ref normal) <= FP.Zero; if (flag4) { result = false; } else { TSVector tSVector8; TSVector.Subtract(ref tSVector7, ref tSVector3, out tSVector8); TSVector tSVector12; TSVector.Subtract(ref tSVector11, ref tSVector3, out tSVector12); TSVector.Cross(ref tSVector8, ref tSVector12, out normal); FP x = TSVector.Dot(ref normal, ref tSVector3); bool flag5 = x > FP.Zero; if (flag5) { TSVector.Swap(ref tSVector7, ref tSVector11); TSVector.Swap(ref tSVector5, ref tSVector9); TSVector.Swap(ref tSVector6, ref tSVector10); TSVector.Negate(ref normal, out normal); Debug.Log("normal: " + normal); } int num = 0; int num2 = 0; bool flag6 = false; while (true) { bool flag7 = num2 > 34; if (flag7) { break; } num2++; TSVector.Negate(ref normal, out tSVector4); TSVector tSVector13; XenoCollide.SupportMapTransformed(support1, ref orientation1, ref position1, ref tSVector4, out tSVector13); TSVector tSVector14; XenoCollide.SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out tSVector14); TSVector tSVector15; TSVector.Subtract(ref tSVector14, ref tSVector13, out tSVector15); bool flag8 = TSVector.Dot(ref tSVector15, ref normal) <= FP.Zero; if (flag8) { goto Block_7; } TSVector.Cross(ref tSVector7, ref tSVector15, out tSVector8); bool flag9 = TSVector.Dot(ref tSVector8, ref tSVector3) < FP.Zero; if (flag9) { tSVector11 = tSVector15; tSVector9 = tSVector13; tSVector10 = tSVector14; TSVector.Subtract(ref tSVector7, ref tSVector3, out tSVector8); TSVector.Subtract(ref tSVector15, ref tSVector3, out tSVector12); TSVector.Cross(ref tSVector8, ref tSVector12, out normal); } else { TSVector.Cross(ref tSVector15, ref tSVector11, out tSVector8); bool flag10 = TSVector.Dot(ref tSVector8, ref tSVector3) < FP.Zero; if (!flag10) { goto IL_385; } tSVector7 = tSVector15; tSVector5 = tSVector13; tSVector6 = tSVector14; TSVector.Subtract(ref tSVector15, ref tSVector3, out tSVector8); TSVector.Subtract(ref tSVector11, ref tSVector3, out tSVector12); TSVector.Cross(ref tSVector8, ref tSVector12, out normal); } } result = false; return(result); Block_7: result = false; return(result); IL_385: while (true) { num++; TSVector.Subtract(ref tSVector11, ref tSVector7, out tSVector8); TSVector tSVector15; TSVector.Subtract(ref tSVector15, ref tSVector7, out tSVector12); TSVector.Cross(ref tSVector8, ref tSVector12, out normal); bool flag11 = normal.IsNearlyZero(); if (flag11) { break; } normal.Normalize(); FP x2 = TSVector.Dot(ref normal, ref tSVector7); bool flag12 = x2 >= 0 && !flag6; if (flag12) { flag6 = true; } TSVector.Negate(ref normal, out tSVector4); XenoCollide.SupportMapTransformed(support1, ref orientation1, ref position1, ref tSVector4, out zero); XenoCollide.SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out zero2); TSVector.Subtract(ref zero2, ref zero, out zero3); TSVector.Subtract(ref zero3, ref tSVector15, out tSVector8); FP x3 = TSVector.Dot(ref tSVector8, ref normal); penetration = TSVector.Dot(ref zero3, ref normal); bool flag13 = x3 <= XenoCollide.CollideEpsilon || penetration <= FP.Zero || num > 34; if (flag13) { goto Block_15; } TSVector.Cross(ref zero3, ref tSVector3, out tSVector8); FP x4 = TSVector.Dot(ref tSVector8, ref tSVector7); bool flag14 = x4 >= FP.Zero; if (flag14) { x4 = TSVector.Dot(ref tSVector8, ref tSVector11); bool flag15 = x4 >= FP.Zero; if (flag15) { tSVector7 = zero3; tSVector5 = zero; tSVector6 = zero2; } else { tSVector15 = zero3; TSVector tSVector13 = zero; TSVector tSVector14 = zero2; } } else { x4 = TSVector.Dot(ref tSVector8, ref tSVector15); bool flag16 = x4 >= FP.Zero; if (flag16) { tSVector11 = zero3; tSVector9 = zero; tSVector10 = zero2; } else { tSVector7 = zero3; tSVector5 = zero; tSVector6 = zero2; } } } result = true; return(result); Block_15: bool flag17 = flag6; if (flag17) { TSVector.Cross(ref tSVector7, ref tSVector11, out tSVector8); TSVector tSVector15; FP fP = TSVector.Dot(ref tSVector8, ref tSVector15); TSVector.Cross(ref tSVector15, ref tSVector11, out tSVector8); FP fP2 = TSVector.Dot(ref tSVector8, ref tSVector3); TSVector.Cross(ref tSVector3, ref tSVector7, out tSVector8); FP fP3 = TSVector.Dot(ref tSVector8, ref tSVector15); TSVector.Cross(ref tSVector11, ref tSVector7, out tSVector8); FP fP4 = TSVector.Dot(ref tSVector8, ref tSVector3); FP fP5 = fP + fP2 + fP3 + fP4; bool flag18 = fP5 <= 0; if (flag18) { fP = 0; TSVector.Cross(ref tSVector11, ref tSVector15, out tSVector8); fP2 = TSVector.Dot(ref tSVector8, ref normal); TSVector.Cross(ref tSVector15, ref tSVector7, out tSVector8); fP3 = TSVector.Dot(ref tSVector8, ref normal); TSVector.Cross(ref tSVector7, ref tSVector11, out tSVector8); fP4 = TSVector.Dot(ref tSVector8, ref normal); fP5 = fP2 + fP3 + fP4; } FP x5 = FP.One / fP5; TSVector.Multiply(ref tSVector, fP, out point); TSVector.Multiply(ref tSVector5, fP2, out tSVector8); TSVector.Add(ref point, ref tSVector8, out point); TSVector.Multiply(ref tSVector9, fP3, out tSVector8); TSVector.Add(ref point, ref tSVector8, out point); TSVector tSVector13; TSVector.Multiply(ref tSVector13, fP4, out tSVector8); TSVector.Add(ref point, ref tSVector8, out point); TSVector.Multiply(ref tSVector2, fP, out tSVector12); TSVector.Add(ref tSVector12, ref point, out point); TSVector.Multiply(ref tSVector6, fP2, out tSVector8); TSVector.Add(ref point, ref tSVector8, out point); TSVector.Multiply(ref tSVector10, fP3, out tSVector8); TSVector.Add(ref point, ref tSVector8, out point); TSVector tSVector14; TSVector.Multiply(ref tSVector14, fP4, out tSVector8); TSVector.Add(ref point, ref tSVector8, out point); TSVector.Multiply(ref point, x5 * FP.Half, out point); } result = flag6; } } } return(result); }
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref TSMatrix orientation1, ref TSMatrix orientation2, ref TSVector position1, ref TSVector position2, out TSVector p1, out TSVector p2, out TSVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = TSVector.zero; TSVector r = position1 - position2; TSVector w, v; TSVector supVertexA; TSVector rn, vn; rn = TSVector.Negate(r); SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); TSVector supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = TSVector.zero; int maxIter = MaxIterations; FP distSq = v.sqrMagnitude; FP epsilon = CollideEpsilon; while ((distSq > epsilon) && (maxIter-- != 0)) { vn = TSVector.Negate(v); SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, supVertexA, supVertexB); } if (simplexSolver.Closest(out v)) { distSq = v.sqrMagnitude; normal = v; } else { distSq = FP.Zero; } } simplexSolver.ComputePoints(out p1, out p2); if (normal.sqrMagnitude > TSMath.Epsilon * TSMath.Epsilon) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref Matrix3 orientation1, ref Matrix3 orientation2, ref Vector3 position1, ref Vector3 position2, out Vector3 p1, out Vector3 p2, out Vector3 normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = Vector3.Zero; Vector3 r = position1 - position2; Vector3 w, v; Vector3 supVertexA; Vector3 rn, vn; rn = r * -1; SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); Vector3 supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = Vector3.Zero; int maxIter = 15; float distSq = v.LengthSquared; float epsilon = 0.00001f; while ((distSq > epsilon) && (maxIter-- != 0)) { vn = v * -1; SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, supVertexA, supVertexB); } if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared; normal = v; } else { distSq = 0.0f; } } simplexSolver.ComputePoints(out p1, out p2); if (normal.LengthSquared > JMath.Epsilon * JMath.Epsilon) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector point, out JVector normal, out double penetration) { // Used variables JVector temp1, temp2; JVector v01, v02, v0; JVector v11, v12, v1; JVector v21, v22, v2; JVector v31, v32, v3; JVector v41, v42, v4; JVector mn; // Initialization of the output point = normal = JVector.Zero; penetration = 0.0f; //JVector right = JVector.Right; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); JVector.Transform(ref v01, ref orientation1, out v01); JVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); JVector.Transform(ref v02, ref orientation2, out v02); JVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference JVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) v0 = new JVector(0.00001f, 0, 0); // v1 = support in direction of origin mn = v0; JVector.Negate(ref v0, out normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); JVector.Subtract(ref v12, ref v11, out v1); if (JVector.Dot(ref v1, ref normal) <= 0.0f) return false; // v2 = support perpendicular to v1,v0 JVector.Cross(ref v1, ref v0, out normal); if (normal.IsNearlyZero()) { JVector.Subtract(ref v1, ref v0, out normal); normal.Normalize(); point = v11; JVector.Add(ref point, ref v12, out point); JVector.Multiply(ref point, 0.5f, out point); JVector.Subtract(ref v12, ref v11, out temp1); penetration = JVector.Dot(ref temp1, ref normal); //point = v11; //point2 = v12; return true; } JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); JVector.Subtract(ref v22, ref v21, out v2); if (JVector.Dot(ref v2, ref normal) <= 0.0f) return false; // Determine whether origin is on + or - side of plane (v1,v0,v2) JVector.Subtract(ref v1, ref v0, out temp1); JVector.Subtract(ref v2, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); double dist = JVector.Dot(ref normal, ref v0); // If the origin is on the - side of the plane, reverse the direction of the plane if (dist > 0.0f) { JVector.Swap(ref v1, ref v2); JVector.Swap(ref v11, ref v21); JVector.Swap(ref v12, ref v22); JVector.Negate(ref normal, out normal); } int phase2 = 0; int phase1 = 0; bool hit = false; // Phase One: Identify a portal while (true) { if (phase1 > MaximumIterations) return false; phase1++; // Obtain the support point in a direction perpendicular to the existing plane // Note: This point is guaranteed to lie off the plane JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); JVector.Subtract(ref v32, ref v31, out v3); if (JVector.Dot(ref v3, ref normal) <= 0.0f) { return false; } // If origin is outside (v1,v0,v3), then eliminate v2 and loop JVector.Cross(ref v1, ref v3, out temp1); if (JVector.Dot(ref temp1, ref v0) < 0.0f) { v2 = v3; v21 = v31; v22 = v32; JVector.Subtract(ref v1, ref v0, out temp1); JVector.Subtract(ref v3, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); continue; } // If origin is outside (v3,v0,v2), then eliminate v1 and loop JVector.Cross(ref v3, ref v2, out temp1); if (JVector.Dot(ref temp1, ref v0) < 0.0f) { v1 = v3; v11 = v31; v12 = v32; JVector.Subtract(ref v3, ref v0, out temp1); JVector.Subtract(ref v2, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); continue; } // Phase Two: Refine the portal // We are now inside of a wedge... while (true) { phase2++; // Compute normal of the wedge face JVector.Subtract(ref v2, ref v1, out temp1); JVector.Subtract(ref v3, ref v1, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); // Can this happen??? Can it be handled more cleanly? if (normal.IsNearlyZero()) return true; normal.Normalize(); // Compute distance from origin to wedge face double d = JVector.Dot(ref normal, ref v1); // If the origin is inside the wedge, we have a hit if (d >= 0 && !hit) { // HIT!!! hit = true; } // Find the support point in the direction of the wedge face JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v41); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v42); JVector.Subtract(ref v42, ref v41, out v4); JVector.Subtract(ref v4, ref v3, out temp1); double delta = JVector.Dot(ref temp1, ref normal); penetration = JVector.Dot(ref v4, ref normal); // If the boundary is thin enough or the origin is outside the support plane for the newly discovered vertex, then we can terminate if (delta <= CollideEpsilon || penetration <= 0.0f || phase2 > MaximumIterations) { if (hit) { JVector.Cross(ref v1, ref v2, out temp1); double b0 = JVector.Dot(ref temp1, ref v3); JVector.Cross(ref v3, ref v2, out temp1); double b1 = JVector.Dot(ref temp1, ref v0); JVector.Cross(ref v0, ref v1, out temp1); double b2 = JVector.Dot(ref temp1, ref v3); JVector.Cross(ref v2, ref v1, out temp1); double b3 = JVector.Dot(ref temp1, ref v0); double sum = b0 + b1 + b2 + b3; if (sum <= 0) { b0 = 0; JVector.Cross(ref v2, ref v3, out temp1); b1 = JVector.Dot(ref temp1, ref normal); JVector.Cross(ref v3, ref v1, out temp1); b2 = JVector.Dot(ref temp1, ref normal); JVector.Cross(ref v1, ref v2, out temp1); b3 = JVector.Dot(ref temp1, ref normal); sum = b1 + b2 + b3; } double inv = 1.0f / sum; JVector.Multiply(ref v01, b0, out point); JVector.Multiply(ref v11, b1, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v21, b2, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v31, b3, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v02, b0, out temp2); JVector.Add(ref temp2, ref point, out point); JVector.Multiply(ref v12, b1, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v22, b2, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v32, b3, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref point, inv * 0.5f, out point); } // Compute the barycentric coordinates of the origin return hit; } //// Compute the tetrahedron dividing face (v4,v0,v1) //JVector.Cross(ref v4, ref v1, out temp1); //double d1 = JVector.Dot(ref temp1, ref v0); //// Compute the tetrahedron dividing face (v4,v0,v2) //JVector.Cross(ref v4, ref v2, out temp1); //double d2 = JVector.Dot(ref temp1, ref v0); // Compute the tetrahedron dividing face (v4,v0,v3) JVector.Cross(ref v4, ref v0, out temp1); double dot = JVector.Dot(ref temp1, ref v1); if (dot >= 0.0f) { dot = JVector.Dot(ref temp1, ref v2); if (dot >= 0.0f) { // Inside d1 & inside d2 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } else { // Inside d1 & outside d2 ==> eliminate v3 v3 = v4; v31 = v41; v32 = v42; } } else { dot = JVector.Dot(ref temp1, ref v3); if (dot >= 0.0f) { // Outside d1 & inside d3 ==> eliminate v2 v2 = v4; v21 = v41; v22 = v42; } else { // Outside d1 & outside d3 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } } } } }
/// <summary> /// Checks if given point is within a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="point">The point to check.</param> /// <returns>Returns true if the point is within the shape, otherwise false.</returns> public static bool Pointcast(ISupportMappable support, ref MatrixD orientation, ref Vector3D position, ref Vector3D point) { Vector3D arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref point, out arbitraryPoint); Vector3D.Subtract(ref point, ref arbitraryPoint, out arbitraryPoint); Vector3D r; support.SupportCenter(out r); Vector3D.Transform(ref r, ref orientation, out r); Vector3D.Add(ref position, ref r, out r); Vector3D.Subtract(ref point, ref r, out r); Vector3D x = point; Vector3D w, p; double VdotR; Vector3D v; Vector3D.Subtract(ref x, ref arbitraryPoint, out v); double dist = v.LengthSquared(); double epsilon = 0.0001f; int maxIter = MaxIterations; VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); while ((dist > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); Vector3D.Subtract(ref x, ref p, out w); double VdotW = Vector3D.Dot(v, w); if (VdotW > 0.0f) { VdotR = Vector3D.Dot(v, r); if (VdotR >= -(MathHelper.EPSILON * MathHelper.EPSILON)) { simplexSolverPool.GiveBack(simplexSolver); return(false); } else { simplexSolver.Reset(); } } if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, x, p); } if (simplexSolver.Closest(out v)) { dist = v.LengthSquared(); } else { dist = 0.0f; } } simplexSolverPool.GiveBack(simplexSolver); return(true); }
// public static bool TimeOfImpact(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, //ref JMatrix orientation2, ref JVector position1, ref JVector position2, ref JVector sweptA, ref JVector sweptB, //out JVector p1, out JVector p2, out JVector normal) // { // VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); // simplexSolver.Reset(); // FP lambda = FP.Zero; // p1 = p2 = JVector.Zero; // JVector x1 = position1; // JVector x2 = position2; // JVector r = sweptA - sweptB; // JVector w, v; // JVector supVertexA; // JVector rn = JVector.Negate(r); // SupportMapTransformed(support1, ref orientation1, ref x1, ref rn, out supVertexA); // JVector supVertexB; // SupportMapTransformed(support2, ref orientation2, ref x2, ref r, out supVertexB); // v = supVertexA - supVertexB; // bool hasResult = false; // normal = JVector.Zero; // FP lastLambda = lambda; // int maxIter = MaxIterations; // FP distSq = v.LengthSquared(); // FP epsilon = FP.EN5; // FP VdotR; // while ((distSq > epsilon) && (maxIter-- != 0)) // { // JVector vn = JVector.Negate(v); // SupportMapTransformed(support1, ref orientation1, ref x1, ref vn, out supVertexA); // SupportMapTransformed(support2, ref orientation2, ref x2, ref v, out supVertexB); // w = supVertexA - supVertexB; // FP VdotW = JVector.Dot(ref v, ref w); // if (VdotW > FP.Zero) // { // VdotR = JVector.Dot(ref v, ref r); // if (VdotR >= -JMath.Epsilon) // { // simplexSolverPool.GiveBack(simplexSolver); // return false; // } // else // { // lambda = lambda - VdotW / VdotR; // x1 = position1 + lambda * sweptA; // x2 = position2 + lambda * sweptB; // w = supVertexA - supVertexB; // normal = v; // hasResult = true; // } // } // if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, supVertexA, supVertexB); // if (simplexSolver.Closest(out v)) // { // distSq = v.LengthSquared(); // normal = v; // hasResult = true; // } // else distSq = FP.Zero; // } // simplexSolver.ComputePoints(out p1, out p2); // if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) // normal.Normalize(); // p1 = p1 - lambda * sweptA; // p2 = p2 - lambda * sweptB; // simplexSolverPool.GiveBack(simplexSolver); // return true; // } #endregion // see: btSubSimplexConvexCast.cpp /// <summary> /// Checks if a ray definied through it's origin and direction collides /// with a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="origin">The origin of the ray.</param> /// <param name="direction">The direction of the ray.</param> /// <param name="fraction">The fraction which gives information where at the /// ray the collision occured. The hitPoint is calculated by: origin+friction*direction.</param> /// <param name="normal">The normal from the ray collision.</param> /// <returns>Returns true if the ray hit the shape, false otherwise.</returns> public static bool Raycast(ISupportMappable support, ref TSMatrix orientation, ref TSMatrix invOrientation, ref TSVector position, ref TSVector origin, ref TSVector direction, out FP fraction, out TSVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); normal = TSVector.zero; fraction = FP.MaxValue; FP lambda = FP.Zero; TSVector r = direction; TSVector x = origin; TSVector w, p, v; TSVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref r, out arbitraryPoint); TSVector.Subtract(ref x, ref arbitraryPoint, out v); int maxIter = MaxIterations; FP distSq = v.sqrMagnitude; FP epsilon = FP.EN6; FP VdotR; while ((distSq > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); TSVector.Subtract(ref x, ref p, out w); FP VdotW = TSVector.Dot(ref v, ref w); if (VdotW > FP.Zero) { VdotR = TSVector.Dot(ref v, ref r); if (VdotR >= -TSMath.Epsilon) { simplexSolverPool.GiveBack(simplexSolver); return(false); } else { lambda = lambda - VdotW / VdotR; TSVector.Multiply(ref r, lambda, out x); TSVector.Add(ref origin, ref x, out x); TSVector.Subtract(ref x, ref p, out w); normal = v; } } if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, x, p); } if (simplexSolver.Closest(out v)) { distSq = v.sqrMagnitude; } else { distSq = FP.Zero; } } #region Retrieving hitPoint // Giving back the fraction like this *should* work // but is inaccurate against large objects: // fraction = lambda; TSVector p1, p2; simplexSolver.ComputePoints(out p1, out p2); p2 = p2 - origin; fraction = p2.magnitude / direction.magnitude; #endregion if (normal.sqrMagnitude > TSMath.Epsilon * TSMath.Epsilon) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
// see: btSubSimplexConvexCast.cpp /// <summary> /// Checks if a ray definied through it's origin and direction collides /// with a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="origin">The origin of the ray.</param> /// <param name="direction">The direction of the ray.</param> /// <param name="fraction">The fraction which gives information where at the /// ray the collision occured. The hitPoint is calculated by: origin+friction*direction.</param> /// <param name="normal">The normal from the ray collision.</param> /// <returns>Returns true if the ray hit the shape, false otherwise.</returns> public static bool Raycast(ISupportMappable support, ref JMatrix orientation, ref JMatrix invOrientation, ref JVector position, ref JVector origin, ref JVector direction, out float fraction, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); normal = JVector.Zero; fraction = float.MaxValue; float lambda = 0.0f; JVector r = direction; JVector x = origin; JVector w, p, v; JVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref r, out arbitraryPoint); JVector.Subtract(ref x, ref arbitraryPoint, out v); int maxIter = MaxIterations; float distSq = v.LengthSquared(); float epsilon = 0.000001f; float VdotR; while ((distSq > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); JVector.Subtract(ref x, ref p, out w); float VdotW = JVector.Dot(ref v, ref w); if (VdotW > 0.0f) { VdotR = JVector.Dot(ref v, ref r); if (VdotR >= -JMath.Epsilon) { simplexSolverPool.GiveBack(simplexSolver); return(false); } else { lambda = lambda - VdotW / VdotR; JVector.Multiply(ref r, lambda, out x); JVector.Add(ref origin, ref x, out x); JVector.Subtract(ref x, ref p, out w); normal = v; } } if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, x, p); } if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); } else { distSq = 0.0f; } } #region Retrieving hitPoint // Giving back the fraction like this *should* work // but is inaccurate against large objects: // fraction = lambda; JVector p1, p2; simplexSolver.ComputePoints(out p1, out p2); p2 = p2 - origin; fraction = p2.Length() / direction.Length(); #endregion if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) { normal.Normalize(); } simplexSolverPool.GiveBack(simplexSolver); return(true); }
/// <summary> /// Checks if given point is within a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="point">The point to check.</param> /// <returns>Returns true if the point is within the shape, otherwise false.</returns> public static bool Pointcast(ISupportMappable support, ref TSMatrix orientation, ref TSVector position, ref TSVector point) { TSVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref point, out arbitraryPoint); TSVector.Subtract(ref point, ref arbitraryPoint, out arbitraryPoint); TSVector r; support.SupportCenter(out r); TSVector.Transform(ref r, ref orientation, out r); TSVector.Add(ref position, ref r, out r); TSVector.Subtract(ref point, ref r, out r); TSVector x = point; TSVector w, p; FP VdotR; TSVector v; TSVector.Subtract(ref x, ref arbitraryPoint, out v); FP dist = v.sqrMagnitude; FP epsilon = CollideEpsilon; int maxIter = MaxIterations; VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); while ((dist > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); TSVector.Subtract(ref x, ref p, out w); FP VdotW = TSVector.Dot(ref v, ref w); if (VdotW > FP.Zero) { VdotR = TSVector.Dot(ref v, ref r); if (VdotR >= -(TSMath.Epsilon * TSMath.Epsilon)) { simplexSolverPool.GiveBack(simplexSolver); return(false); } else { simplexSolver.Reset(); } } if (!simplexSolver.InSimplex(w)) { simplexSolver.AddVertex(w, x, p); } if (simplexSolver.Closest(out v)) { dist = v.sqrMagnitude; } else { dist = FP.Zero; } } simplexSolverPool.GiveBack(simplexSolver); return(true); }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector point, out JVector normal, out float penetration) { // Used variables JVector v01, v02, v0; JVector v11, v12, v1; JVector v21, v22, v2; JVector v31, v32, v3; JVector mn; // Initialization of the output point = normal = JVector.Zero; penetration = 0.0f; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); JVector.Transform(ref v01, ref orientation1, out v01); JVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); JVector.Transform(ref v02, ref orientation2, out v02); JVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference JVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) { v0 = new JVector(0.00001f, 0); } // v1 = support in direction of origin mn = v0; JVector.Negate(ref v0, out normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); JVector.Subtract(ref v12, ref v11, out v1); if (JVector.Dot(ref v1, ref normal) <= 0.0f) { return(false); } // v2 = support perpendicular to v1,v0 normal = OutsidePortal(v1, v0); JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); JVector.Subtract(ref v22, ref v21, out v2); //LD.Draw(Conversion.ToXNAVector2(v1), Conversion.ToXNAVector2(v0), Color.Blue); //LD.Draw(Conversion.ToXNAVector2(v2), Conversion.ToXNAVector2(v0), Color.Blue); if (JVector.Dot(ref v2, ref normal) <= 0.0f) { return(false); } // phase two: portal refinement int maxIterations = 0; while (true) { // find normal direction if (!IntersectPortal(v0, v2, v1)) { normal = InsidePortal(v2, v1); } else { // origin ray crosses the portal normal = OutsidePortal(v2, v1); } // obtain the next support point JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); JVector.Subtract(ref v32, ref v31, out v3); //LD.Draw(Conversion.ToXNAVector2(v3), Conversion.ToXNAVector2(v0), Color.Green); if (JVector.Dot(v3, normal) <= 0) { JVector ab = v3 - v2; float t = -(JVector.Dot(v2, ab)) / (JVector.Dot(ab, ab)); normal = (v2 + (t * ab)); return(false); } // Portal lies on the outside edge of the Minkowski Hull. // Return contact information if (JVector.Dot((v3 - v2), normal) <= CollideEpsilon || ++maxIterations > MaximumIterations) { JVector ab = v2 - v1; float t = JVector.Dot(JVector.Negate(v1), ab); if (t <= 0.0f) { t = 0.0f; normal = v1; } else { float denom = JVector.Dot(ab, ab); if (t >= denom) { normal = v2; t = 1.0f; } else { t /= denom; normal = v1 + t * ab; } } float s = 1 - t; point = s * v11 + t * v21; var point2 = s * v12 + t * v22; // this causes a sq root = bad! penetration = normal.Length(); normal.Normalize(); return(true); } // if origin is inside (v1, v0, v3), refine portal if (OriginInTriangle(v0, v1, v3)) { v2 = v3; v21 = v31; v22 = v32; continue; } // if origin is inside (v3, v0, v2), refine portal else if (OriginInTriangle(v0, v2, v3)) { v1 = v3; v11 = v31; v12 = v32; continue; } return(false); } }