예제 #1
0
        /// <summary>
        /// The points in world space gets recalculated by transforming the
        /// local coordinates. Also new penetration depth is estimated.
        /// </summary>
        public void UpdatePosition()
        {
            if (body1IsParticle)
            {
                JVector.Add(ref realRelPos1, ref body1.position, out p1);
            }
            else
            {
                JMatrix xForm = JMatrix.CreateRotationZ(body1.invOrientation);
                JVector.Transform(ref realRelPos1, ref xForm, out p1);
                JVector.Add(ref p1, ref body1.position, out p1);
            }

            if (body2IsParticle)
            {
                JVector.Add(ref realRelPos2, ref body2.position, out p2);
            }
            else
            {
                JMatrix xForm = JMatrix.CreateRotationZ(body2.invOrientation);
                JVector.Transform(ref realRelPos2, ref xForm, out p2);
                JVector.Add(ref p2, ref body2.position, out p2);
            }

            JVector dist; JVector.Subtract(ref p1, ref p2, out dist);

            penetration = JVector.Dot(ref dist, ref normal);
        }
예제 #2
0
 /// <summary>
 /// Turn the <paramref name="input"/>-vector in the same direction as the <paramref name="direction"/>.
 /// </summary>
 /// <param name="input">Input vector to adjust</param>
 /// <param name="direction">Given direction</param>
 private void TurnIntoDirectionOf(ref JVector input, JVector direction)
 {
     if (JVector.Dot(input, direction) < 0.0f)
     {
         input = -1 * input;
     }
 }
예제 #3
0
            public void SupportMapping(ref JVector direction, out JVector result)
            {
                float min = JVector.Dot(ref owner.points[indices.I0].position, ref direction);
                float dot = JVector.Dot(ref owner.points[indices.I1].position, ref direction);

                JVector minVertex = owner.points[indices.I0].position;

                if (dot > min)
                {
                    min       = dot;
                    minVertex = owner.points[indices.I1].position;
                }
                dot = JVector.Dot(ref owner.points[indices.I2].position, ref direction);
                if (dot > min)
                {
                    min       = dot;
                    minVertex = owner.points[indices.I2].position;
                }


                JVector exp;

                JVector.Normalize(ref direction, out exp);
                exp   *= owner.triangleExpansion;
                result = minVertex + exp;
            }
예제 #4
0
        /// <summary>
        /// SupportMapping. Finds the point in the shape furthest away from the given direction.
        /// Imagine a plane with a normal in the search direction. Now move the plane along the normal
        /// until the plane does not intersect the shape. The last intersection point is the result.
        /// </summary>
        /// <param name="direction">The direction.</param>
        /// <param name="result">The result.</param>
        public override void SupportMapping(ref JVector direction, out JVector result)
        {
            JVector expandVector;

            JVector.Normalize(ref direction, out expandVector);
            JVector.Multiply(ref expandVector, sphericalExpansion, out expandVector);

            int   minIndex = 0;
            float min      = JVector.Dot(ref points[0], ref direction);
            float dot      = JVector.Dot(ref points[1], ref direction);

            if (dot > min)
            {
                min      = dot;
                minIndex = 1;
            }
            dot = JVector.Dot(ref points[2], ref direction);
            if (dot > min)
            {
                min      = dot;
                minIndex = 2;
            }

            JVector.Add(ref points[minIndex], ref expandVector, out result);
        }
예제 #5
0
        /// <summary>
        /// The points in wolrd space gets recalculated by transforming the
        /// local coordinates. Also new penetration depth is estimated.
        /// </summary>
        public void UpdatePosition()
        {
            if (body1IsMassPoint)
            {
                JVector.Add(ref realRelPos1, ref body1.position, out p1);
            }
            else
            {
                JVector.Transform(ref realRelPos1, ref body1.orientation, out p1);
                JVector.Add(ref p1, ref body1.position, out p1);
            }

            if (body2IsMassPoint)
            {
                JVector.Add(ref realRelPos2, ref body2.position, out p2);
            }
            else
            {
                JVector.Transform(ref realRelPos2, ref body2.orientation, out p2);
                JVector.Add(ref p2, ref body2.position, out p2);
            }


            JVector dist; JVector.Subtract(ref p1, ref p2, out dist);

            penetration = JVector.Dot(ref dist, ref normal);
        }
예제 #6
0
        /// <summary>
        /// SupportMapping. Finds the point in the shape furthest away from the given direction.
        /// Imagine a plane with a normal in the search direction. Now move the plane along the normal
        /// until the plane does not intersect the shape. The last intersection point is the result.
        /// </summary>
        /// <param name="direction">The direction.</param>
        /// <param name="result">The result.</param>
        public override void SupportMapping(ref JVector direction, out JVector result)
        {
            JVector exp;

            JVector.Normalize(ref direction, out exp);
            exp *= sphericalExpansion;

            float min      = JVector.Dot(ref vecs[0], ref direction);
            int   minIndex = 0;
            float dot      = JVector.Dot(ref vecs[1], ref direction);

            if (dot > min)
            {
                min      = dot;
                minIndex = 1;
            }
            dot = JVector.Dot(ref vecs[2], ref direction);
            if (dot > min)
            {
                min      = dot;
                minIndex = 2;
            }

            result = vecs[minIndex] + exp;
        }
예제 #7
0
        public override void Iterate()
        {
            JVector bodyLinearVelocity  = this.Body1.LinearVelocity;
            float   lockedAxisMagnitude = JVector.Dot(lockedAxis, bodyLinearVelocity);
            JVector correctionVelocity  = lockedAxisMagnitude * lockedAxis;

            Body1.LinearVelocity = bodyLinearVelocity - correctionVelocity;
        }
예제 #8
0
        /// <summary>
        /// Reflect the <paramref name="input"/>-vector on the <paramref name="normal"/>-vector.
        /// </summary>
        /// <param name="input">Input-vector</param>
        /// <param name="normal">Reflector-normal</param>
        /// <returns>Vector which is the reflection of input on normal</returns>
        private JVector ReflectOnNormal(JVector input, JVector normal)
        {
            JVector normalNormalized = normal;

            normalNormalized.Normalize();
            JVector inputNormalized = input;

            inputNormalized.Normalize();

            return(inputNormalized - 2 * JVector.Dot(inputNormalized, normalNormalized) * normalNormalized);
        }
예제 #9
0
        public LimitedHingeJoint(World world, RigidBody body1, RigidBody body2, JVector position, JVector hingeAxis, float hingeFwdAngle, float hingeBckAngle) : base(world)
        {
            worldPointConstraint = new PointOnPoint[2];

            hingeAxis *= 0.5f;

            var pos1 = position;

            JVector.Add(pos1, hingeAxis, out pos1);
            var pos2 = position;

            JVector.Subtract(pos2, hingeAxis, out pos2);

            worldPointConstraint[0] = new PointOnPoint(body1, body2, pos1);
            worldPointConstraint[1] = new PointOnPoint(body1, body2, pos2);

            hingeAxis = JVector.Normalize(hingeAxis);

            var perpDir = JVector.Up;

            if (JVector.Dot(perpDir, hingeAxis) > 0.1f)
            {
                perpDir = JVector.Right;
            }

            var sideAxis = JVector.Cross(hingeAxis, perpDir);

            perpDir = JVector.Cross(sideAxis, hingeAxis);
            perpDir = JVector.Normalize(perpDir);

            float len = 10.0f * 3;

            var hingeRelAnchorPos0 = perpDir * len;

            float angleToMiddle      = 0.5f * (hingeFwdAngle - hingeBckAngle);
            var   hingeRelAnchorPos1 = JVector.Transform(hingeRelAnchorPos0, JMatrix.CreateFromAxisAngle(hingeAxis, -angleToMiddle / 360.0f * 2.0f * JMath.Pi));

            float hingeHalfAngle  = 0.5f * (hingeFwdAngle + hingeBckAngle);
            float allowedDistance = len * 2.0f * (float)System.Math.Sin(hingeHalfAngle * 0.5f / 360.0f * 2.0f * JMath.Pi);

            var hingePos = body1.Position;
            var relPos0c = hingePos + hingeRelAnchorPos0;
            var relPos1c = hingePos + hingeRelAnchorPos1;

            DistanceConstraint = new PointPointDistance(body1, body2, relPos0c, relPos1c)
            {
                Distance = allowedDistance,
                Behavior = PointPointDistance.DistanceBehavior.LimitMaximumDistance
            };
        }
예제 #10
0
            /// Test if point p and d lie on opposite sides of plane through abc
            public int PointOutsideOfPlane(JVector p, JVector a, JVector b, JVector c, JVector d)
            {
                JVector normal = JVector.Cross(b - a, c - a);

                float signp = JVector.Dot(p - a, normal); // [AP AB AC]
                float signd = JVector.Dot(d - a, normal); // [AD AB AC]

                //if (CatchDegenerateTetrahedron)
                if (signd * signd < (1e-4f * 1e-4f))
                {
                    return(-1);
                }

                // Points on opposite sides if expression signs are opposite
                return(signp * signd < 0f ? 1 : 0);
            }
예제 #11
0
            /// <summary>
            /// Iteratively solve this constraint.
            /// </summary>
            public override void Iterate()
            {
                if (skipConstraint)
                {
                    return;
                }

                float jv = JVector.Dot(ref body1.linearVelocity, ref jacobian[0]);

                jv += JVector.Dot(ref body2.linearVelocity, ref jacobian[1]);

                float softnessScalar = accumulatedImpulse * softnessOverDt;

                float lambda = -effectiveMass * (jv + bias + softnessScalar);

                if (behavior == DistanceBehavior.LimitMinimumDistance)
                {
                    float previousAccumulatedImpulse = accumulatedImpulse;
                    accumulatedImpulse = JMath.Max(accumulatedImpulse + lambda, 0);
                    lambda             = accumulatedImpulse - previousAccumulatedImpulse;
                }
                else if (behavior == DistanceBehavior.LimitMaximumDistance)
                {
                    float previousAccumulatedImpulse = accumulatedImpulse;
                    accumulatedImpulse = JMath.Min(accumulatedImpulse + lambda, 0);
                    lambda             = accumulatedImpulse - previousAccumulatedImpulse;
                }
                else
                {
                    accumulatedImpulse += lambda;
                }

                JVector temp;

                if (!body1.isStatic)
                {
                    JVector.Multiply(ref jacobian[0], lambda * body1.inverseMass, out temp);
                    JVector.Add(ref temp, ref body1.linearVelocity, out body1.linearVelocity);
                }

                if (!body2.isStatic)
                {
                    JVector.Multiply(ref jacobian[1], lambda * body2.inverseMass, out temp);
                    JVector.Add(ref temp, ref body2.linearVelocity, out body2.linearVelocity);
                }
            }
예제 #12
0
        private bool ShouldGenerateContact(RigidBody body, JVector[] triangle)
        {
            if (triangle == null)
            {
                return(true);
            }

            if (SurfaceTriangle.ComputeSurfaceType(triangle, WindingTypes.CounterClockwise) == SurfaceTypes.Floor)
            {
                return(false);
            }

            var n = Utilities.ComputeNormal(triangle[0], triangle[1], triangle[2], WindingTypes.CounterClockwise,
                                            false);

            return(JVector.Dot(controllingBody.LinearVelocity, n) < 0);
        }
예제 #13
0
        // This is primarily used for tracking relative rotation on moving platforms.
        public static float ComputeYaw(this JMatrix matrix)
        {
            // See https://stackoverflow.com/a/4341489/7281613.
            JVector t = JVector.Transform(JVector.Left, matrix);
            JVector f = t - JVector.Dot(t, JVector.Up) * JVector.Up;

            f.Normalize();

            float angle = (float)Math.Acos(JVector.Dot(JVector.Left, f));
            float d     = JVector.Dot(JVector.Up, JVector.Cross(JVector.Left, f));

            if (d < 0)
            {
                angle = Constants.TwoPi - angle;
            }

            return(angle);
        }
예제 #14
0
        /// <summary>
        /// SupportMapping. Finds the point in the shape furthest away from the given direction.
        /// Imagine a plane with a normal in the search direction. Now move the plane along the normal
        /// until the plane does not intersect the shape. The last intersection point is the result.
        /// </summary>
        /// <param name="direction">The direction.</param>
        /// <param name="result">The result.</param>
        public override void SupportMapping(ref JVector direction, out JVector result)
        {
            double maxDotProduct = double.MinValue;
            int    maxIndex      = 0;
            double dotProduct;

            for (int i = 0; i < vertices.Count; i++)
            {
                dotProduct = JVector.Dot(vertices[i], direction);
                if (dotProduct > maxDotProduct)
                {
                    maxDotProduct = dotProduct;
                    maxIndex      = i;
                }
            }

            result = vertices[maxIndex] - this.shifted;
        }
예제 #15
0
        private void HandlePlayerCollision(SteerableCollider player, Collider other, JVector collisionPoint, JVector normal)
        {
            //float angle = JVector.Dot(right, normal) > 0.0f ? -15.0f : 15.0f;
            float angle = 0.0f;

            angle += MathHelper.ToDegrees(player.RotationY);

            JVector forward = Conversion.ToJitterVector(player.GameObject.transform.Forward);

            // If the player is driving away of the wall there should be no collision-handling
            if (JVector.Dot(forward, normal) > 0.0f)
            {
                return;
            }

            JVector newPosition = ProjectToNonCollision(player, collisionPoint, normal);

            player.GameObject.GetComponent <Player>().SetCollisionState(other, Conversion.ToXnaVector(newPosition), angle);
            player.Position = newPosition;
        }
예제 #16
0
        private void FindSupportPoints(RigidBody body1, RigidBody body2,
                                       Shape shape1, Shape shape2, ref JVector point, ref JVector normal,
                                       out JVector point1, out JVector point2)
        {
            JVector mn; JVector.Negate(ref normal, out mn);

            JVector sA; SupportMapping(body1, shape1, ref mn, out sA);
            JVector sB; SupportMapping(body2, shape2, ref normal, out sB);

            JVector.Subtract(ref sA, ref point, out sA);
            JVector.Subtract(ref sB, ref point, out sB);

            float dot1 = JVector.Dot(ref sA, ref normal);
            float dot2 = JVector.Dot(ref sB, ref normal);

            JVector.Multiply(ref normal, dot1, out sA);
            JVector.Multiply(ref normal, dot2, out sB);

            JVector.Add(ref point, ref sA, out point1);
            JVector.Add(ref point, ref sB, out point2);
        }
예제 #17
0
        internal static bool CircleCapsuleTest(JVector centerA, float radiusA, JVector centerB, JVector axis, float length, float radiusB, out JVector pointA, out JVector pointB, out JVector normal, out float distance)
        {
            // get capsule endpoints
            var p0 = centerB - axis * (length * 0.5f);
            var p1 = centerB + axis * (length * 0.5f);

            // get vector from endpoint to circle
            var D = centerA - p0;

            // project vector onto axis and clamp
            var d = JVector.Dot(D, axis);

            d = JMath.Clamp(d, 0, length);

            // get point on axis
            var R = p0 + axis * d;

            // distance
            var b = Math.Abs((centerA - R).Length());

            normal = (centerA - R) / b;

            // calculate closest 2 points
            var RH = JVector.Normalize(centerA - R);

            pointA = JVector.Negate(RH) * radiusA + centerA;
            pointB = RH * radiusB + R;

            normal.Negate();

            distance = b - (radiusA + radiusB);

            //
            if (b < radiusA + radiusB)
            {
                return(true);
            }
            return(false);
        }
예제 #18
0
        private void UpdateArbiterContacts(Arbiter arbiter)
        {
            if (arbiter.contactList.Count == 0)
            {
                lock (removedArbiterStack) { removedArbiterStack.Push(arbiter); }
                return;
            }

            for (int i = arbiter.contactList.Count - 1; i >= 0; i--)
            {
                Contact c = arbiter.contactList[i];
                c.UpdatePosition();

                if (c.penetration < -contactSettings.breakThreshold)
                {
                    Contact.Pool.GiveBack(c);
                    arbiter.contactList.RemoveAt(i);
                    continue;
                }
                else
                {
                    JVector diff; JVector.Subtract(ref c.p1, ref c.p2, out diff);
                    double  distance = JVector.Dot(ref diff, ref c.normal);

                    diff     = diff - distance * c.normal;
                    distance = diff.LengthSquared();

                    // hack (multiplication by factor 100) in the
                    // following line.
                    if (distance > contactSettings.breakThreshold * contactSettings.breakThreshold * 100)
                    {
                        Contact.Pool.GiveBack(c);
                        arbiter.contactList.RemoveAt(i);
                        continue;
                    }
                }
            }
        }
예제 #19
0
        /// <summary>
        /// PrepareForIteration has to be called before <see cref="Iterate"/>.
        /// </summary>
        /// <param name="timestep">The timestep of the simulation.</param>
        public void PrepareForIteration(float timestep)
        {
            float dvx, dvy, dvz;

            if (considerAngularVelocity)
            {
                dvx = (body2.angularVelocity.Y * relativePos2.Z) - (body2.angularVelocity.Z * relativePos2.Y) + body2.linearVelocity.X;
                dvy = (body2.angularVelocity.Z * relativePos2.X) - (body2.angularVelocity.X * relativePos2.Z) + body2.linearVelocity.Y;
                dvz = (body2.angularVelocity.X * relativePos2.Y) - (body2.angularVelocity.Y * relativePos2.X) + body2.linearVelocity.Z;

                dvx = dvx - (body1.angularVelocity.Y * relativePos1.Z) + (body1.angularVelocity.Z * relativePos1.Y) - body1.linearVelocity.X;
                dvy = dvy - (body1.angularVelocity.Z * relativePos1.X) + (body1.angularVelocity.X * relativePos1.Z) - body1.linearVelocity.Y;
                dvz = dvz - (body1.angularVelocity.X * relativePos1.Y) + (body1.angularVelocity.Y * relativePos1.X) - body1.linearVelocity.Z;
            }
            else
            {
                dvx = body2.linearVelocity.X;
                dvy = body2.linearVelocity.Y;
                dvz = body2.linearVelocity.Z;

                dvx = dvx - body1.linearVelocity.X;
                dvy = dvy - body1.linearVelocity.Y;
                dvz = dvz - body1.linearVelocity.Z;
            }

            float kNormal = 0.0f;

            JVector rantra = JVector.Zero;

            if (!treatBody1AsStatic)
            {
                kNormal += body1.inverseMass;

                if (!body1IsMassPoint)
                {
                    // JVector.Cross(ref relativePos1, ref normal, out rantra);
                    rantra.X = (relativePos1.Y * normal.Z) - (relativePos1.Z * normal.Y);
                    rantra.Y = (relativePos1.Z * normal.X) - (relativePos1.X * normal.Z);
                    rantra.Z = (relativePos1.X * normal.Y) - (relativePos1.Y * normal.X);

                    // JVector.Transform(ref rantra, ref body1.invInertiaWorld, out rantra);
                    float num0 = ((rantra.X * body1.invInertiaWorld.M11) + (rantra.Y * body1.invInertiaWorld.M21)) + (rantra.Z * body1.invInertiaWorld.M31);
                    float num1 = ((rantra.X * body1.invInertiaWorld.M12) + (rantra.Y * body1.invInertiaWorld.M22)) + (rantra.Z * body1.invInertiaWorld.M32);
                    float num2 = ((rantra.X * body1.invInertiaWorld.M13) + (rantra.Y * body1.invInertiaWorld.M23)) + (rantra.Z * body1.invInertiaWorld.M33);

                    rantra.X = num0; rantra.Y = num1; rantra.Z = num2;

                    //JVector.Cross(ref rantra, ref relativePos1, out rantra);
                    num0 = (rantra.Y * relativePos1.Z) - (rantra.Z * relativePos1.Y);
                    num1 = (rantra.Z * relativePos1.X) - (rantra.X * relativePos1.Z);
                    num2 = (rantra.X * relativePos1.Y) - (rantra.Y * relativePos1.X);

                    rantra.X = num0; rantra.Y = num1; rantra.Z = num2;
                }
            }

            JVector rbntrb = JVector.Zero;

            if (!treatBody2AsStatic)
            {
                kNormal += body2.inverseMass;

                if (!body2IsMassPoint)
                {
                    // JVector.Cross(ref relativePos1, ref normal, out rantra);
                    rbntrb.X = (relativePos2.Y * normal.Z) - (relativePos2.Z * normal.Y);
                    rbntrb.Y = (relativePos2.Z * normal.X) - (relativePos2.X * normal.Z);
                    rbntrb.Z = (relativePos2.X * normal.Y) - (relativePos2.Y * normal.X);

                    // JVector.Transform(ref rantra, ref body1.invInertiaWorld, out rantra);
                    float num0 = ((rbntrb.X * body2.invInertiaWorld.M11) + (rbntrb.Y * body2.invInertiaWorld.M21)) + (rbntrb.Z * body2.invInertiaWorld.M31);
                    float num1 = ((rbntrb.X * body2.invInertiaWorld.M12) + (rbntrb.Y * body2.invInertiaWorld.M22)) + (rbntrb.Z * body2.invInertiaWorld.M32);
                    float num2 = ((rbntrb.X * body2.invInertiaWorld.M13) + (rbntrb.Y * body2.invInertiaWorld.M23)) + (rbntrb.Z * body2.invInertiaWorld.M33);

                    rbntrb.X = num0; rbntrb.Y = num1; rbntrb.Z = num2;

                    //JVector.Cross(ref rantra, ref relativePos1, out rantra);
                    num0 = (rbntrb.Y * relativePos2.Z) - (rbntrb.Z * relativePos2.Y);
                    num1 = (rbntrb.Z * relativePos2.X) - (rbntrb.X * relativePos2.Z);
                    num2 = (rbntrb.X * relativePos2.Y) - (rbntrb.Y * relativePos2.X);

                    rbntrb.X = num0; rbntrb.Y = num1; rbntrb.Z = num2;
                }
            }

            if (!treatBody1AsStatic)
            {
                kNormal += rantra.X * normal.X + rantra.Y * normal.Y + rantra.Z * normal.Z;
            }
            if (!treatBody2AsStatic)
            {
                kNormal += rbntrb.X * normal.X + rbntrb.Y * normal.Y + rbntrb.Z * normal.Z;
            }

            massNormal = 1.0f / kNormal;

            float num = dvx * normal.X + dvy * normal.Y + dvz * normal.Z;

            tangent.X = dvx - normal.X * num;
            tangent.Y = dvy - normal.Y * num;
            tangent.Z = dvz - normal.Z * num;

            num = tangent.X * tangent.X + tangent.Y * tangent.Y + tangent.Z * tangent.Z;

            if (num != 0.0f)
            {
                num        = (float)Math.Sqrt(num);
                tangent.X /= num;
                tangent.Y /= num;
                tangent.Z /= num;
            }

            float kTangent = 0.0f;

            if (treatBody1AsStatic)
            {
                rantra.MakeZero();
            }
            else
            {
                kTangent += body1.inverseMass;

                if (!body1IsMassPoint)
                {
                    // JVector.Cross(ref relativePos1, ref normal, out rantra);
                    rantra.X = (relativePos1.Y * tangent.Z) - (relativePos1.Z * tangent.Y);
                    rantra.Y = (relativePos1.Z * tangent.X) - (relativePos1.X * tangent.Z);
                    rantra.Z = (relativePos1.X * tangent.Y) - (relativePos1.Y * tangent.X);

                    // JVector.Transform(ref rantra, ref body1.invInertiaWorld, out rantra);
                    float num0 = ((rantra.X * body1.invInertiaWorld.M11) + (rantra.Y * body1.invInertiaWorld.M21)) + (rantra.Z * body1.invInertiaWorld.M31);
                    float num1 = ((rantra.X * body1.invInertiaWorld.M12) + (rantra.Y * body1.invInertiaWorld.M22)) + (rantra.Z * body1.invInertiaWorld.M32);
                    float num2 = ((rantra.X * body1.invInertiaWorld.M13) + (rantra.Y * body1.invInertiaWorld.M23)) + (rantra.Z * body1.invInertiaWorld.M33);

                    rantra.X = num0; rantra.Y = num1; rantra.Z = num2;

                    //JVector.Cross(ref rantra, ref relativePos1, out rantra);
                    num0 = (rantra.Y * relativePos1.Z) - (rantra.Z * relativePos1.Y);
                    num1 = (rantra.Z * relativePos1.X) - (rantra.X * relativePos1.Z);
                    num2 = (rantra.X * relativePos1.Y) - (rantra.Y * relativePos1.X);

                    rantra.X = num0; rantra.Y = num1; rantra.Z = num2;
                }
            }

            if (treatBody2AsStatic)
            {
                rbntrb.MakeZero();
            }
            else
            {
                kTangent += body2.inverseMass;

                if (!body2IsMassPoint)
                {
                    // JVector.Cross(ref relativePos1, ref normal, out rantra);
                    rbntrb.X = (relativePos2.Y * tangent.Z) - (relativePos2.Z * tangent.Y);
                    rbntrb.Y = (relativePos2.Z * tangent.X) - (relativePos2.X * tangent.Z);
                    rbntrb.Z = (relativePos2.X * tangent.Y) - (relativePos2.Y * tangent.X);

                    // JVector.Transform(ref rantra, ref body1.invInertiaWorld, out rantra);
                    float num0 = ((rbntrb.X * body2.invInertiaWorld.M11) + (rbntrb.Y * body2.invInertiaWorld.M21)) + (rbntrb.Z * body2.invInertiaWorld.M31);
                    float num1 = ((rbntrb.X * body2.invInertiaWorld.M12) + (rbntrb.Y * body2.invInertiaWorld.M22)) + (rbntrb.Z * body2.invInertiaWorld.M32);
                    float num2 = ((rbntrb.X * body2.invInertiaWorld.M13) + (rbntrb.Y * body2.invInertiaWorld.M23)) + (rbntrb.Z * body2.invInertiaWorld.M33);

                    rbntrb.X = num0; rbntrb.Y = num1; rbntrb.Z = num2;

                    //JVector.Cross(ref rantra, ref relativePos1, out rantra);
                    num0 = (rbntrb.Y * relativePos2.Z) - (rbntrb.Z * relativePos2.Y);
                    num1 = (rbntrb.Z * relativePos2.X) - (rbntrb.X * relativePos2.Z);
                    num2 = (rbntrb.X * relativePos2.Y) - (rbntrb.Y * relativePos2.X);

                    rbntrb.X = num0; rbntrb.Y = num1; rbntrb.Z = num2;
                }
            }

            if (!treatBody1AsStatic)
            {
                kTangent += JVector.Dot(ref rantra, ref tangent);
            }
            if (!treatBody2AsStatic)
            {
                kTangent += JVector.Dot(ref rbntrb, ref tangent);
            }
            massTangent = 1.0f / kTangent;

            restitutionBias = lostSpeculativeBounce;

            speculativeVelocity = 0.0f;

            float relNormalVel = normal.X * dvx + normal.Y * dvy + normal.Z * dvz; //JVector.Dot(ref normal, ref dv);

            if (Penetration > settings.allowedPenetration)
            {
                restitutionBias = settings.bias * (1.0f / timestep) * JMath.Max(0.0f, Penetration - settings.allowedPenetration);
                restitutionBias = JMath.Clamp(restitutionBias, 0.0f, settings.maximumBias);
                //  body1IsMassPoint = body2IsMassPoint = false;
            }


            float timeStepRatio = timestep / lastTimeStep;

            accumulatedNormalImpulse  *= timeStepRatio;
            accumulatedTangentImpulse *= timeStepRatio;

            {
                // Static/Dynamic friction
                float relTangentVel     = -(tangent.X * dvx + tangent.Y * dvy + tangent.Z * dvz);
                float tangentImpulse    = massTangent * relTangentVel;
                float maxTangentImpulse = -staticFriction * accumulatedNormalImpulse;

                if (tangentImpulse < maxTangentImpulse)
                {
                    friction = dynamicFriction;
                }
                else
                {
                    friction = staticFriction;
                }
            }

            JVector impulse;

            // Simultaneos solving and restitution is simply not possible
            // so fake it a bit by just applying restitution impulse when there
            // is a new contact.
            if (relNormalVel < -1.0f && newContact)
            {
                restitutionBias = Math.Max(-restitution * relNormalVel, restitutionBias);
            }

            // Speculative Contacts!
            // if the penetration is negative (which means the bodies are not already in contact, but they will
            // be in the future) we store the current bounce bias in the variable 'lostSpeculativeBounce'
            // and apply it the next frame, when the speculative contact was already solved.
            if (penetration < -settings.allowedPenetration)
            {
                speculativeVelocity = penetration / timestep;

                lostSpeculativeBounce = restitutionBias;
                restitutionBias       = 0.0f;
            }
            else
            {
                lostSpeculativeBounce = 0.0f;
            }

            impulse.X = normal.X * accumulatedNormalImpulse + tangent.X * accumulatedTangentImpulse;
            impulse.Y = normal.Y * accumulatedNormalImpulse + tangent.Y * accumulatedTangentImpulse;
            impulse.Z = normal.Z * accumulatedNormalImpulse + tangent.Z * accumulatedTangentImpulse;

            if (!treatBody1AsStatic)
            {
                body1.linearVelocity.X -= (impulse.X * body1.inverseMass);
                body1.linearVelocity.Y -= (impulse.Y * body1.inverseMass);
                body1.linearVelocity.Z -= (impulse.Z * body1.inverseMass);

                if (!body1IsMassPoint && considerAngularVelocity)
                {
                    float num0, num1, num2;
                    num0 = relativePos1.Y * impulse.Z - relativePos1.Z * impulse.Y;
                    num1 = relativePos1.Z * impulse.X - relativePos1.X * impulse.Z;
                    num2 = relativePos1.X * impulse.Y - relativePos1.Y * impulse.X;

                    float num3 =
                        (((num0 * body1.invInertiaWorld.M11) +
                          (num1 * body1.invInertiaWorld.M21)) +
                         (num2 * body1.invInertiaWorld.M31));
                    float num4 =
                        (((num0 * body1.invInertiaWorld.M12) +
                          (num1 * body1.invInertiaWorld.M22)) +
                         (num2 * body1.invInertiaWorld.M32));
                    float num5 =
                        (((num0 * body1.invInertiaWorld.M13) +
                          (num1 * body1.invInertiaWorld.M23)) +
                         (num2 * body1.invInertiaWorld.M33));

                    body1.angularVelocity.X -= num3;
                    body1.angularVelocity.Y -= num4;
                    body1.angularVelocity.Z -= num5;
                }
            }

            if (!treatBody2AsStatic)
            {
                body2.linearVelocity.X += (impulse.X * body2.inverseMass);
                body2.linearVelocity.Y += (impulse.Y * body2.inverseMass);
                body2.linearVelocity.Z += (impulse.Z * body2.inverseMass);

                if (!body2IsMassPoint && considerAngularVelocity)
                {
                    float num0, num1, num2;
                    num0 = relativePos2.Y * impulse.Z - relativePos2.Z * impulse.Y;
                    num1 = relativePos2.Z * impulse.X - relativePos2.X * impulse.Z;
                    num2 = relativePos2.X * impulse.Y - relativePos2.Y * impulse.X;

                    float num3 =
                        (((num0 * body2.invInertiaWorld.M11) +
                          (num1 * body2.invInertiaWorld.M21)) +
                         (num2 * body2.invInertiaWorld.M31));
                    float num4 =
                        (((num0 * body2.invInertiaWorld.M12) +
                          (num1 * body2.invInertiaWorld.M22)) +
                         (num2 * body2.invInertiaWorld.M32));
                    float num5 =
                        (((num0 * body2.invInertiaWorld.M13) +
                          (num1 * body2.invInertiaWorld.M23)) +
                         (num2 * body2.invInertiaWorld.M33));

                    body2.angularVelocity.X += num3;
                    body2.angularVelocity.Y += num4;
                    body2.angularVelocity.Z += num5;
                }
            }

            lastTimeStep = timestep;

            newContact = false;
        }
예제 #20
0
 /// <summary>
 /// Calculates the dot product of two vectors.
 /// </summary>
 /// <param name="value1">The first vector.</param>
 /// <param name="value2">The second vector.</param>
 /// <returns>Returns the dot product of both.</returns>
 #region public static Fix64 operator *(JVector value1, JVector value2)
 public static Fix64 operator *(JVector value1, JVector value2)
 {
     return(JVector.Dot(ref value1, ref value2));
 }
예제 #21
0
        /// <summary>
        /// PrepareForIteration has to be called before <see cref="Iterate"/>.
        /// </summary>
        /// <param name="timestep">The timestep of the simulation.</param>
        public void PrepareForIteration(float timestep)
        {
            if (body1.IsTrigger || body2.IsTrigger)
            {
                return;
            }

            float dvx, dvy;

            // relative velocity at contact point
            dvx = body2.linearVelocity.X + (-body2.angularVelocity * relativePos2.Y);
            dvy = body2.linearVelocity.Y + (body2.angularVelocity * relativePos2.X);

            dvx = dvx - body1.linearVelocity.X + (-body1.angularVelocity * relativePos1.Y);
            dvy = dvy - body1.linearVelocity.Y + (body1.angularVelocity * relativePos1.X);

            float kNormal = 0.0f;

            float rantra = 0.0f;

            // if body1 isn't static
            if (!treatBody1AsStatic)
            {
                // add it's mass to the mass normal
                kNormal += body1.inverseMass;

                // if body1 isn't a mass point (particle)
                if (!body1IsMassPoint)
                {
                    //
                    rantra = relativePos1.X * normal.Y - relativePos1.Y * normal.X;
                }
            }

            float rbntrb = 0.0f;

            // if body2 isn't static
            if (!treatBody2AsStatic)
            {
                // add it's mass to the mass normal
                kNormal += body2.inverseMass;

                // if body1 isn't a mass point (particle)
                if (!body2IsMassPoint)
                {
                    //
                    rbntrb = relativePos2.X * normal.Y - relativePos2.Y * normal.X;
                }
            }

            // compute overall mass normal
            if (!treatBody1AsStatic)
            {
                kNormal += body1.invInertia * (rantra * rantra);
            }
            if (!treatBody2AsStatic)
            {
                kNormal += body2.invInertia * (rbntrb * rbntrb);
            }

            massNormal = 1.0f / kNormal;

            tangent.X = -normal.Y;
            tangent.Y = normal.X;

            float kTangent = 0.0f;

            if (treatBody1AsStatic)
            {
                rantra = 0.0f;
            }
            else
            {
                kTangent += body1.inverseMass;

                if (!body1IsMassPoint)
                {
                    //
                    rantra = relativePos1.X * tangent.Y - relativePos1.Y * tangent.X;
                }
            }

            if (treatBody2AsStatic)
            {
                rbntrb = 0.0f;
            }
            else
            {
                kTangent += body2.inverseMass;

                if (!body2IsMassPoint)
                {
                    rantra = relativePos2.X * tangent.Y - relativePos2.Y * tangent.X;
                }
            }

            // compute overall mass tangent
            if (!treatBody1AsStatic)
            {
                kTangent += body1.invInertia * (rantra * rantra);
            }
            if (!treatBody2AsStatic)
            {
                kTangent += body2.invInertia * (rbntrb * rbntrb);
            }

            massTangent = 1.0f / kTangent;

            restitutionBias = lostSpeculativeBounce;

            speculativeVelocity = 0.0f;

            float relNormalVel = JVector.Dot(normal, body2.linearVelocity + JVector.Cross(body2.angularVelocity, relativePos2) - body1.linearVelocity + JVector.Cross(body1.angularVelocity, relativePos1));

            if (Penetration > settings.allowedPenetration)
            {
                restitutionBias = settings.bias * (1.0f / timestep) * JMath.Max(0.0f, Penetration - settings.allowedPenetration);
                restitutionBias = JMath.Clamp(restitutionBias, 0.0f, settings.maximumBias);
                //  body1IsMassPoint = body2IsMassPoint = false;
            }


            float timeStepRatio = timestep / lastTimeStep;

            accumulatedNormalImpulse  *= timeStepRatio;
            accumulatedTangentImpulse *= timeStepRatio;

            {
                // Static/Dynamic friction
                float relTangentVel     = -(tangent.X * dvx + tangent.Y * dvy);
                float tangentImpulse    = massTangent * relTangentVel;
                float maxTangentImpulse = -staticFriction * accumulatedNormalImpulse;

                if (tangentImpulse < maxTangentImpulse)
                {
                    friction = dynamicFriction;
                }
                else
                {
                    friction = staticFriction;
                }
            }

            JVector impulse;

            // Simultaneous solving and restitution is simply not possible
            // so fake it a bit by just applying restitution impulse when there
            // is a new contact.
            if (relNormalVel < -1.0f && newContact)
            {
                restitutionBias = Math.Max(-restitution * relNormalVel, restitutionBias);
            }

            // Speculative Contacts!
            // if the penetration is negative (which means the bodies are not already in contact, but they will
            // be in the future) we store the current bounce bias in the variable 'lostSpeculativeBounce'
            // and apply it the next frame, when the speculative contact was already solved.
            if (penetration < -settings.allowedPenetration)
            {
                speculativeVelocity = penetration / timestep;

                lostSpeculativeBounce = restitutionBias;
                restitutionBias       = 0.0f;
            }
            else
            {
                lostSpeculativeBounce = 0.0f;
            }

            // warm start

            impulse.X = normal.X * accumulatedNormalImpulse + tangent.X * accumulatedTangentImpulse;
            impulse.Y = normal.Y * accumulatedNormalImpulse + tangent.Y * accumulatedTangentImpulse;

            if (!treatBody1AsStatic)
            {
                body1.linearVelocity.X -= (impulse.X * body1.inverseMass);
                body1.linearVelocity.Y -= (impulse.Y * body1.inverseMass);

                if (!body1IsMassPoint)
                {
                    body1.angularVelocity -= body1.invInertia * (relativePos1.X * impulse.Y - relativePos1.Y * impulse.X);
                }
            }

            if (!treatBody2AsStatic)
            {
                body2.linearVelocity.X += (impulse.X * body2.inverseMass);
                body2.linearVelocity.Y += (impulse.Y * body2.inverseMass);

                if (!body2IsMassPoint)
                {
                    body2.angularVelocity += body2.invInertia * (relativePos2.X * impulse.Y - relativePos2.Y * impulse.X);
                }
            }

            lastTimeStep = timestep;

            newContact = false;
        }
예제 #22
0
        /// <summary>
        /// Initializes a new instance of the HingeJoint class.
        /// </summary>
        /// <param name="world">The world class where the constraints get added to.</param>
        /// <param name="body1">The first body connected to the second one.</param>
        /// <param name="body2">The second body connected to the first one.</param>
        /// <param name="position">The position in world space where both bodies get connected.</param>
        /// <param name="hingeAxis">The axis if the hinge.</param>
        public LimitedHingeJoint(JitterWorld world, RigidBody body1, RigidBody body2, JVector position, JVector hingeAxis,
                                 float hingeFwdAngle, float hingeBckAngle)
            : base(world)
        {
            // Create the hinge first, two point constraints

            worldPointConstraint = new PointOnPoint[2];

            hingeAxis *= 0.5f;

            JVector pos1 = position; JVector.Add(ref pos1, ref hingeAxis, out pos1);
            JVector pos2 = position; JVector.Subtract(ref pos2, ref hingeAxis, out pos2);

            worldPointConstraint[0] = new PointOnPoint(body1, body2, pos1);
            worldPointConstraint[1] = new PointOnPoint(body1, body2, pos2);


            // Now the limit, one max distance constraint

            hingeAxis.Normalize();

            // choose a direction that is perpendicular to the hinge
            JVector perpDir = JVector.Up;

            if (JVector.Dot(perpDir, hingeAxis) > 0.1f)
            {
                perpDir = JVector.Right;
            }

            // now make it perpendicular to the hinge
            JVector sideAxis = JVector.Cross(hingeAxis, perpDir);

            perpDir = JVector.Cross(sideAxis, hingeAxis);
            perpDir.Normalize();

            // the length of the "arm" TODO take this as a parameter? what's
            // the effect of changing it?
            float len = 10.0f * 3;

            // Choose a position using that dir. this will be the anchor point
            // for body 0. relative to hinge
            JVector hingeRelAnchorPos0 = perpDir * len;


            // anchor point for body 2 is chosen to be in the middle of the
            // angle range.  relative to hinge
            float   angleToMiddle      = 0.5f * (hingeFwdAngle - hingeBckAngle);
            JVector hingeRelAnchorPos1 = JVector.Transform(hingeRelAnchorPos0, JMatrix.CreateFromAxisAngle(hingeAxis, -angleToMiddle / 360.0f * 2.0f * JMath.Pi));

            // work out the "string" length
            float hingeHalfAngle  = 0.5f * (hingeFwdAngle + hingeBckAngle);
            float allowedDistance = len * 2.0f * (float)System.Math.Sin(hingeHalfAngle * 0.5f / 360.0f * 2.0f * JMath.Pi);

            JVector hingePos = body1.Position;
            JVector relPos0c = hingePos + hingeRelAnchorPos0;
            JVector relPos1c = hingePos + hingeRelAnchorPos1;

            distance          = new PointPointDistance(body1, body2, relPos0c, relPos1c);
            distance.Distance = allowedDistance;
            distance.Behavior = PointPointDistance.DistanceBehavior.LimitMaximumDistance;
        }
예제 #23
0
        /// <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;
                        }
                    }
                }
            }
        }
예제 #24
0
        // 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);
        }
예제 #25
0
            public bool UpdateClosestVectorAndPoints()
            {
                if (_needsUpdate)
                {
                    _cachedBC.Reset();
                    _needsUpdate = false;

                    JVector p, a, b, c, d;
                    switch (NumVertices)
                    {
                    case 0:
                        _cachedValidClosest = false;
                        break;

                    case 1:
                        _cachedPA = _simplexPointsP[0];
                        _cachedPB = _simplexPointsQ[0];
                        _cachedV  = _cachedPA - _cachedPB;
                        _cachedBC.Reset();
                        _cachedBC.SetBarycentricCoordinates(1f, 0f, 0f, 0f);
                        _cachedValidClosest = _cachedBC.IsValid;
                        break;

                    case 2:
                        //closest point origin from line segment
                        JVector from = _simplexVectorW[0];
                        JVector to   = _simplexVectorW[1];
                        JVector nearest;

                        JVector diff = from * (-1);
                        JVector v    = to - from;
                        float   t    = JVector.Dot(v, diff);

                        if (t > 0)
                        {
                            float dotVV = v.LengthSquared();
                            if (t < dotVV)
                            {
                                t    /= dotVV;
                                diff -= t * v;
                                _cachedBC.UsedVertices.UsedVertexA = true;
                                _cachedBC.UsedVertices.UsedVertexB = true;
                            }
                            else
                            {
                                t     = 1;
                                diff -= v;
                                //reduce to 1 point
                                _cachedBC.UsedVertices.UsedVertexB = true;
                            }
                        }
                        else
                        {
                            t = 0;
                            //reduce to 1 point
                            _cachedBC.UsedVertices.UsedVertexA = true;
                        }

                        _cachedBC.SetBarycentricCoordinates(1 - t, t, 0, 0);
                        nearest = from + t * v;

                        _cachedPA = _simplexPointsP[0] + t * (_simplexPointsP[1] - _simplexPointsP[0]);
                        _cachedPB = _simplexPointsQ[0] + t * (_simplexPointsQ[1] - _simplexPointsQ[0]);
                        _cachedV  = _cachedPA - _cachedPB;

                        ReduceVertices(_cachedBC.UsedVertices);

                        _cachedValidClosest = _cachedBC.IsValid;
                        break;

                    case 3:
                        //closest point origin from triangle
                        p = new JVector();
                        a = _simplexVectorW[0];
                        b = _simplexVectorW[1];
                        c = _simplexVectorW[2];

                        ClosestPtPointTriangle(p, a, b, c, ref _cachedBC);
                        _cachedPA = _simplexPointsP[0] * _cachedBC.BarycentricCoords[0] +
                                    _simplexPointsP[1] * _cachedBC.BarycentricCoords[1] +
                                    _simplexPointsP[2] * _cachedBC.BarycentricCoords[2] +
                                    _simplexPointsP[3] * _cachedBC.BarycentricCoords[3];

                        _cachedPB = _simplexPointsQ[0] * _cachedBC.BarycentricCoords[0] +
                                    _simplexPointsQ[1] * _cachedBC.BarycentricCoords[1] +
                                    _simplexPointsQ[2] * _cachedBC.BarycentricCoords[2] +
                                    _simplexPointsQ[3] * _cachedBC.BarycentricCoords[3];

                        _cachedV = _cachedPA - _cachedPB;

                        ReduceVertices(_cachedBC.UsedVertices);
                        _cachedValidClosest = _cachedBC.IsValid;
                        break;

                    case 4:
                        p = new JVector();
                        a = _simplexVectorW[0];
                        b = _simplexVectorW[1];
                        c = _simplexVectorW[2];
                        d = _simplexVectorW[3];

                        bool hasSeperation = ClosestPtPointTetrahedron(p, a, b, c, d, ref _cachedBC);

                        if (hasSeperation)
                        {
                            _cachedPA = _simplexPointsP[0] * _cachedBC.BarycentricCoords[0] +
                                        _simplexPointsP[1] * _cachedBC.BarycentricCoords[1] +
                                        _simplexPointsP[2] * _cachedBC.BarycentricCoords[2] +
                                        _simplexPointsP[3] * _cachedBC.BarycentricCoords[3];

                            _cachedPB = _simplexPointsQ[0] * _cachedBC.BarycentricCoords[0] +
                                        _simplexPointsQ[1] * _cachedBC.BarycentricCoords[1] +
                                        _simplexPointsQ[2] * _cachedBC.BarycentricCoords[2] +
                                        _simplexPointsQ[3] * _cachedBC.BarycentricCoords[3];

                            _cachedV = _cachedPA - _cachedPB;
                            ReduceVertices(_cachedBC.UsedVertices);
                        }
                        else
                        {
                            if (_cachedBC.Degenerate)
                            {
                                _cachedValidClosest = false;
                            }
                            else
                            {
                                _cachedValidClosest = true;
                                //degenerate case == false, penetration = true + zero
                                _cachedV.X = _cachedV.Y = _cachedV.Z = 0f;
                            }
                            break;     // !!!!!!!!!!!! proverit na vsakiy sluchai
                        }

                        _cachedValidClosest = _cachedBC.IsValid;

                        //closest point origin from tetrahedron
                        break;

                    default:
                        _cachedValidClosest = false;
                        break;
                    }
                }

                return(_cachedValidClosest);
            }
예제 #26
0
        public void PreStep(float timeStep)
        {
            float vel = car.LinearVelocity.Length();

            SideFriction    = 2.5f - JMath.Clamp(vel / 20.0f, 0.0f, 1.4f);
            ForwardFriction = 5.5f - JMath.Clamp(vel / 20.0f, 0.0f, 5.4f);

            JVector force = JVector.Zero;

            JVector worldAxis = JVector.Transform(JVector.Up, car.Orientation);
            JVector worldPos  = car.Position + JVector.Transform(Position, car.Orientation);

            JVector forward = new JVector(-car.Orientation.M31, -car.Orientation.M32, -car.Orientation.M33);

            JVector wheelFwd  = JVector.Transform(forward, JMatrix.CreateFromAxisAngle(JVector.Up, SteerAngle / 360 * 2 * JMath.Pi));
            JVector wheelLeft = JVector.Cross(JVector.Up, wheelFwd); wheelLeft.Normalize();
            JVector wheelUp   = JVector.Cross(wheelFwd, wheelLeft);

            float rayLen = 2.0f * Radius + WheelTravel;

            JVector wheelRayStart = worldPos;
            JVector wheelDelta    = -Radius * worldAxis;
            JVector wheelRayEnd   = worldPos + wheelDelta;

            float deltaFwd      = (2.0f * Radius) / (NumberOfRays + 1);
            float deltaFwdStart = deltaFwd;

            lastDisplacement = displacement;
            displacement     = 0.0f;

            lastOnFloor = false;

            JVector rayOrigin = car.Position + JVector.Transform(Position, car.Orientation);

            JVector   groundNormal = JVector.Zero;
            JVector   groundPos    = JVector.Zero;
            float     deepestFrac  = float.MaxValue;
            RigidBody worldBody    = null;

            for (int i = 0; i < NumberOfRays; i++)
            {
                float distFwd = (deltaFwdStart + i * deltaFwd) - Radius;
                float zOffset = Radius * (1.0f - (float)Math.Cos(Math.PI / 4 * (distFwd / Radius)));

                JVector newOrigin = wheelRayStart + distFwd * wheelFwd + zOffset * wheelUp;

                RigidBody body; JVector normal; float frac;
                bool      result = world.CollisionSystem.Raycast(newOrigin, wheelDelta,
                                                                 raycast, out body, out normal, out frac);



                if (result && frac <= 1.0f)
                {
                    if (frac < deepestFrac)
                    {
                        deepestFrac  = frac;
                        groundPos    = rayOrigin + frac * wheelDelta;
                        worldBody    = body;
                        groundNormal = normal;
                    }

                    lastOnFloor = true;
                }
            }

            if (!lastOnFloor)
            {
                return;
            }

            if (groundNormal.LengthSquared() > 0.0f)
            {
                groundNormal.Normalize();
            }

            // System.Diagnostics.Debug.WriteLine(groundPos.ToString());


            displacement = rayLen * (1.0f - deepestFrac);
            displacement = JMath.Clamp(displacement, 0.0f, WheelTravel);

            float displacementForceMag = displacement * Spring;

            // reduce force when suspension is par to ground
            displacementForceMag *= Math.Abs(JVector.Dot(groundNormal, worldAxis));

            // apply damping
            float dampingForceMag = upSpeed * Damping;

            float totalForceMag = displacementForceMag + dampingForceMag;

            if (totalForceMag < 0.0f)
            {
                totalForceMag = 0.0f;
            }

            JVector extraForce = totalForceMag * worldAxis;

            force += extraForce;

            JVector groundUp   = groundNormal;
            JVector groundLeft = JVector.Cross(groundNormal, wheelFwd);

            if (groundLeft.LengthSquared() > 0.0f)
            {
                groundLeft.Normalize();
            }

            JVector groundFwd = JVector.Cross(groundLeft, groundUp);

            JVector wheelPointVel = car.LinearVelocity +
                                    JVector.Cross(car.AngularVelocity, JVector.Transform(Position, car.Orientation));

            // rimVel=(wxr)*v
            JVector rimVel = angVel * JVector.Cross(wheelLeft, groundPos - worldPos);

            wheelPointVel += rimVel;

            JVector worldVel = worldBody.LinearVelocity +
                               JVector.Cross(worldBody.AngularVelocity, groundPos - worldBody.Position);

            wheelPointVel -= worldVel;

            // sideways forces
            float noslipVel  = 0.1f;
            float slipVel    = 0.1f;
            float slipFactor = 0.7f;

            float smallVel = 3;
            float friction = SideFriction;

            float sideVel = JVector.Dot(wheelPointVel, groundLeft);

            if ((sideVel > slipVel) || (sideVel < -slipVel))
            {
                friction *= slipFactor;
            }
            else
            if ((sideVel > noslipVel) || (sideVel < -noslipVel))
            {
                friction *= 1.0f - (1.0f - slipFactor) * (System.Math.Abs(sideVel) - noslipVel) / (slipVel - noslipVel);
            }

            if (sideVel < 0.0f)
            {
                friction *= -1.0f;
            }

            if (System.Math.Abs(sideVel) < smallVel)
            {
                friction *= System.Math.Abs(sideVel) / smallVel;
            }

            float sideForce = -friction * totalForceMag;

            extraForce = sideForce * groundLeft;
            force     += extraForce;

            // fwd/back forces
            friction = ForwardFriction;
            float fwdVel = JVector.Dot(wheelPointVel, groundFwd);

            if ((fwdVel > slipVel) || (fwdVel < -slipVel))
            {
                friction *= slipFactor;
            }
            else
            if ((fwdVel > noslipVel) || (fwdVel < -noslipVel))
            {
                friction *= 1.0f - (1.0f - slipFactor) * (System.Math.Abs(fwdVel) - noslipVel) / (slipVel - noslipVel);
            }

            if (fwdVel < 0.0f)
            {
                friction *= -1.0f;
            }

            if (System.Math.Abs(fwdVel) < smallVel)
            {
                friction *= System.Math.Abs(fwdVel) / smallVel;
            }

            float fwdForce = -friction * totalForceMag;

            extraForce = fwdForce * groundFwd;
            force     += extraForce;

            // fwd force also spins the wheel
            JVector wheelCentreVel = car.LinearVelocity +
                                     JVector.Cross(car.AngularVelocity, JVector.Transform(Position, car.Orientation));

            angVelForGrip = JVector.Dot(wheelCentreVel, groundFwd) / Radius;
            torque       += -fwdForce * Radius;

            // add force to car
            car.AddForce(force, groundPos + 0.5f * JVector.Up);

            // add force to the world
            if (!worldBody.IsStatic)
            {
                worldBody.AddForce(force * (-1) * 0.01f, groundPos);
            }
        }
예제 #27
0
            public bool ClosestPtPointTriangle(JVector p, JVector a, JVector b, JVector c,
                                               ref SubSimplexClosestResult result)
            {
                result.UsedVertices.Reset();

                float v, w;

                // Check if P in vertex region outside A
                JVector ab = b - a;
                JVector ac = c - a;
                JVector ap = p - a;
                float   d1 = JVector.Dot(ab, ap);
                float   d2 = JVector.Dot(ac, ap);

                if (d1 <= 0f && d2 <= 0f)
                {
                    result.ClosestPointOnSimplex    = a;
                    result.UsedVertices.UsedVertexA = true;
                    result.SetBarycentricCoordinates(1, 0, 0, 0);
                    return(true); // a; // barycentric coordinates (1,0,0)
                }

                // Check if P in vertex region outside B
                JVector bp = p - b;
                float   d3 = JVector.Dot(ab, bp);
                float   d4 = JVector.Dot(ac, bp);

                if (d3 >= 0f && d4 <= d3)
                {
                    result.ClosestPointOnSimplex    = b;
                    result.UsedVertices.UsedVertexB = true;
                    result.SetBarycentricCoordinates(0, 1, 0, 0);

                    return(true); // b; // barycentric coordinates (0,1,0)
                }
                // Check if P in edge region of AB, if so return projection of P onto AB
                float vc = d1 * d4 - d3 * d2;

                if (vc <= 0f && d1 >= 0f && d3 <= 0f)
                {
                    v = d1 / (d1 - d3);
                    result.ClosestPointOnSimplex    = a + v * ab;
                    result.UsedVertices.UsedVertexA = true;
                    result.UsedVertices.UsedVertexB = true;
                    result.SetBarycentricCoordinates(1 - v, v, 0, 0);
                    return(true);
                    //return a + v * ab; // barycentric coordinates (1-v,v,0)
                }

                // Check if P in vertex region outside C
                JVector cp = p - c;
                float   d5 = JVector.Dot(ab, cp);
                float   d6 = JVector.Dot(ac, cp);

                if (d6 >= 0f && d5 <= d6)
                {
                    result.ClosestPointOnSimplex    = c;
                    result.UsedVertices.UsedVertexC = true;
                    result.SetBarycentricCoordinates(0, 0, 1, 0);
                    return(true);//c; // barycentric coordinates (0,0,1)
                }

                // Check if P in edge region of AC, if so return projection of P onto AC
                float vb = d5 * d2 - d1 * d6;

                if (vb <= 0f && d2 >= 0f && d6 <= 0f)
                {
                    w = d2 / (d2 - d6);
                    result.ClosestPointOnSimplex    = a + w * ac;
                    result.UsedVertices.UsedVertexA = true;
                    result.UsedVertices.UsedVertexC = true;
                    result.SetBarycentricCoordinates(1 - w, 0, w, 0);
                    return(true);
                    //return a + w * ac; // barycentric coordinates (1-w,0,w)
                }

                // Check if P in edge region of BC, if so return projection of P onto BC
                float va = d3 * d6 - d5 * d4;

                if (va <= 0f && (d4 - d3) >= 0f && (d5 - d6) >= 0f)
                {
                    w = (d4 - d3) / ((d4 - d3) + (d5 - d6));

                    result.ClosestPointOnSimplex    = b + w * (c - b);
                    result.UsedVertices.UsedVertexB = true;
                    result.UsedVertices.UsedVertexC = true;
                    result.SetBarycentricCoordinates(0, 1 - w, w, 0);
                    return(true);
                    // return b + w * (c - b); // barycentric coordinates (0,1-w,w)
                }

                // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
                float denom = 1.0f / (va + vb + vc);

                v = vb * denom;
                w = vc * denom;

                result.ClosestPointOnSimplex    = a + ab * v + ac * w;
                result.UsedVertices.UsedVertexA = true;
                result.UsedVertices.UsedVertexB = true;
                result.UsedVertices.UsedVertexC = true;
                result.SetBarycentricCoordinates(1 - v - w, v, w, 0);

                return(true);
            }
예제 #28
0
        /// <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);
        }
예제 #29
0
 /// <summary>
 /// Project vector <paramref name="v"/> on vector <paramref name="u"/>
 /// </summary>
 /// <param name="v">Vector to project</param>
 /// <param name="u">Vector to project on</param>
 /// <returns>v projected on u</returns>
 private JVector ProjectOn(JVector v, JVector u)
 {
     return(JVector.Dot(v, u) / u.LengthSquared() * u);
 }
예제 #30
0
        private void UpdateArbiterContacts(Arbiter arbiter)
        {
            if (arbiter.contactList.Count == 0)
            {
                lock (removedArbiterStack) { removedArbiterStack.Push(arbiter); }
                return;
            }

            for (int i = arbiter.contactList.Count - 1; i >= 0; i--)
            {
                Contact c = arbiter.contactList[i];
                c.UpdatePosition();

                if ((arbiter.body1.isStatic || arbiter.body2.isStatic) == false)
                {
                    UnityEngine.Debug.Log(string.Format("Contacts {0}", arbiter.ContactList.Count));
                }

                if (c.penetration < -contactSettings.breakThreshold)
                {
                    poolContact.GiveBack(c);
                    arbiter.contactList.RemoveAt(i);

                    if ((arbiter.body1.isStatic || arbiter.body2.isStatic) == false)
                    {
                        if (arbiter.ContactList.Count == 0)
                        {
                            UnityEngine.Debug.Log(string.Format("Removed all contacts through breakshold penetration"));
                        }
                    }

                    continue;
                }
                else
                {
                    JVector diff; JVector.Subtract(ref c.p1, ref c.p2, out diff);
                    float   distance = JVector.Dot(ref diff, ref c.normal);

                    diff     = diff - distance * c.normal;
                    distance = diff.LengthSquared();

                    // hack (multiplication by factor 100) in the
                    // following line.
                    if (distance > contactSettings.breakThreshold * contactSettings.breakThreshold * 100)
                    {
                        poolContact.GiveBack(c);
                        arbiter.contactList.RemoveAt(i);


                        if ((arbiter.body1.isStatic || arbiter.body2.isStatic) == false)
                        {
                            if (arbiter.ContactList.Count == 0)
                            {
                                UnityEngine.Debug.Log(string.Format("Removed all contacts through distance"));
                            }
                        }



                        continue;
                    }
                }
            }
        }