Ejemplo n.º 1
0
 private void SupportMapping(RigidBody body, Shape workingShape, ref FPVector direction, out FPVector result)
 {
     FPVector.Transform(ref direction, ref body.invOrientation, out result);
     workingShape.SupportMapping(ref result, out result);
     FPVector.Transform(ref result, ref body.orientation, out result);
     FPVector.Add(ref result, ref body.position, out result);
 }
Ejemplo n.º 2
0
 public void Rotate(FPMatrix orientation, FPVector center)
 {
     for (int i = 0; i < points.Count; i++)
     {
         points[i].position = FPVector.Transform(points[i].position - center, orientation);
     }
 }
Ejemplo n.º 3
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 FPVector direction, out FPVector result)
 {
     FPVector.Transform(ref direction, ref shapes[currentShape].invOrientation, out result);
     shapes[currentShape].Shape.SupportMapping(ref direction, out result);
     FPVector.Transform(ref result, ref shapes[currentShape].orientation, out result);
     FPVector.Add(ref result, ref shapes[currentShape].position, out result);
 }
        /// <summary>
        /// Raycasts a single body. NOTE: For performance reasons terrain and trianglemeshshape aren't checked
        /// against rays (rays are of infinite length). They are checked against segments
        /// which start at rayOrigin and end in rayOrigin + rayDirection.
        /// </summary>
        #region public override bool Raycast(RigidBody body, JVector rayOrigin, JVector rayDirection, out JVector normal, out FP fraction)
        public override bool Raycast(RigidBody body, FPVector rayOrigin, FPVector rayDirection, out FPVector normal, out FP fraction)
        {
            fraction = FP.MaxValue; normal = FPVector.zero;

            if (!body.BoundingBox.RayIntersect(ref rayOrigin, ref rayDirection))
            {
                return(false);
            }

            if (body.Shape is Multishape)
            {
                Multishape ms = (body.Shape as Multishape).RequestWorkingClone();

                FPVector tempNormal; FP tempFraction;
                bool     multiShapeCollides = false;

                FPVector transformedOrigin; FPVector.Subtract(ref rayOrigin, ref body.position, out transformedOrigin);
                FPVector.Transform(ref transformedOrigin, ref body.invOrientation, out transformedOrigin);
                FPVector transformedDirection; FPVector.Transform(ref rayDirection, ref body.invOrientation, out transformedDirection);

                int msLength = ms.Prepare(ref transformedOrigin, ref transformedDirection);

                for (int i = 0; i < msLength; i++)
                {
                    ms.SetCurrentShape(i);

                    if (GJKCollide.Raycast(ms, ref body.orientation, ref body.invOrientation, ref body.position,
                                           ref rayOrigin, ref rayDirection, out tempFraction, out tempNormal))
                    {
                        if (tempFraction < fraction)
                        {
                            if (useTerrainNormal && ms is TerrainShape)
                            {
                                (ms as TerrainShape).CollisionNormal(out tempNormal);
                                FPVector.Transform(ref tempNormal, ref body.orientation, out tempNormal);
                                tempNormal.Negate();
                            }
                            else if (useTriangleMeshNormal && ms is TriangleMeshShape)
                            {
                                (ms as TriangleMeshShape).CollisionNormal(out tempNormal);
                                FPVector.Transform(ref tempNormal, ref body.orientation, out tempNormal);
                                tempNormal.Negate();
                            }

                            normal             = tempNormal;
                            fraction           = tempFraction;
                            multiShapeCollides = true;
                        }
                    }
                }

                ms.ReturnWorkingClone();
                return(multiShapeCollides);
            }
            else
            {
                return(GJKCollide.Raycast(body.Shape, ref body.orientation, ref body.invOrientation, ref body.position,
                                          ref rayOrigin, ref rayDirection, out fraction, out normal));
            }
        }
Ejemplo n.º 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)
            {
                FPVector.Add(ref realRelPos1, ref body1.position, out p1);
            }
            else
            {
                FPVector.Transform(ref realRelPos1, ref body1.orientation, out p1);
                FPVector.Add(ref p1, ref body1.position, out p1);
            }

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


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

            penetration = FPVector.Dot(ref dist, ref normal);
        }
        private void IntegrateForces()
        {
            for (int index = 0, length = rigidBodies.Count; index < length; index++)
            {
                RigidBody body = rigidBodies[index];
                if (!body.isStatic && body.IsActive)
                {
                    FPVector temp;
                    FPVector.Multiply(ref body.force, body.inverseMass * timestep, out temp);
                    FPVector.Add(ref temp, ref body.linearVelocity, out body.linearVelocity);

                    if (!(body.isParticle))
                    {
                        FPVector.Multiply(ref body.torque, timestep, out temp);
                        FPVector.Transform(ref temp, ref body.invInertiaWorld, out temp);
                        FPVector.Add(ref temp, ref body.angularVelocity, out body.angularVelocity);
                    }

                    if (body.affectedByGravity)
                    {
                        FPVector.Multiply(ref gravity, timestep, out temp);
                        FPVector.Add(ref body.linearVelocity, ref temp, out body.linearVelocity);
                    }
                }

                body.force.MakeZero();
                body.torque.MakeZero();
            }
        }
        /// <summary>
        /// Iteratively solve this constraint.
        /// </summary>
        public override void Iterate()
        {
            FP jv =
                body1.linearVelocity * jacobian[0] +
                body1.angularVelocity * jacobian[1] +
                body2.linearVelocity * jacobian[2] +
                body2.angularVelocity * jacobian[3];

            FP softnessScalar = accumulatedImpulse * softnessOverDt;

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

            accumulatedImpulse += lambda;

            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * lambda * jacobian[0];
                body1.angularVelocity += FPVector.Transform(lambda * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * lambda * jacobian[2];
                body2.angularVelocity += FPVector.Transform(lambda * jacobian[3], body2.invInertiaWorld);
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Initializes a new instance of the DistanceConstraint class.
        /// </summary>
        /// <param name="body1">The first body.</param>
        /// <param name="body2">The second body.</param>
        /// <param name="anchor1">The anchor point of the first body in world space.
        /// The distance is given by the initial distance between both anchor points.</param>
        /// <param name="anchor2">The anchor point of the second body in world space.
        /// The distance is given by the initial distance between both anchor points.</param>
        public PointOnPoint(RigidBody body1, RigidBody body2, FPVector anchor)
            : base(body1, body2)
        {
            FPVector.Subtract(ref anchor, ref body1.position, out localAnchor1);
            FPVector.Subtract(ref anchor, ref body2.position, out localAnchor2);

            FPVector.Transform(ref localAnchor1, ref body1.invOrientation, out localAnchor1);
            FPVector.Transform(ref localAnchor2, ref body2.invOrientation, out localAnchor2);
        }
        /// <summary>
        /// Gets the axis aligned bounding box of the orientated shape.
        /// </summary>
        /// <param name="orientation">The orientation of the shape.</param>
        /// <param name="box">The axis aligned bounding box of the shape.</param>
        public override void GetBoundingBox(ref FPMatrix orientation, out FPBBox box)
        {
            FPMatrix abs; FPMath.Absolute(ref orientation, out abs);
            FPVector temp;

            FPVector.Transform(ref halfSize, ref abs, out temp);

            box.max = temp;
            FPVector.Negate(ref temp, out box.min);
        }
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The simulation timestep</param>
        public override void PrepareForIteration(FP timestep)
        {
            FPVector.Transform(ref localAnchor1, ref body1.orientation, out r1);
            FPVector.Transform(ref localAnchor2, ref body2.orientation, out r2);

            FPVector p1, p2, dp;

            FPVector.Add(ref body1.position, ref r1, out p1);
            FPVector.Add(ref body2.position, ref r2, out p2);

            FPVector.Subtract(ref p2, ref p1, out dp);

            FPVector l = FPVector.Transform(lineNormal, body1.orientation);

            l.Normalize();

            FPVector t = (p1 - p2) % l;

            if (t.sqrMagnitude != FP.Zero)
            {
                t.Normalize();
            }
            t = t % l;

            jacobian[0] = t;                      // linearVel Body1
            jacobian[1] = (r1 + p2 - p1) % t;     // angularVel Body1
            jacobian[2] = -FP.One * t;            // linearVel Body2
            jacobian[3] = -FP.One * r2 % t;       // angularVel Body2

            effectiveMass = body1.inverseMass + body2.inverseMass
                            + FPVector.Transform(jacobian[1], body1.invInertiaWorld) * jacobian[1]
                            + FPVector.Transform(jacobian[3], body2.invInertiaWorld) * jacobian[3];

            softnessOverDt = softness / timestep;
            effectiveMass += softnessOverDt;

            if (effectiveMass != 0)
            {
                effectiveMass = FP.One / effectiveMass;
            }

            bias = -(l % (p2 - p1)).magnitude * biasFactor * (FP.One / timestep);

            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * accumulatedImpulse * jacobian[0];
                body1.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * accumulatedImpulse * jacobian[2];
                body2.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[3], body2.invInertiaWorld);
            }
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Initializes a contact.
        /// </summary>
        /// <param name="body1">The first body.</param>
        /// <param name="body2">The second body.</param>
        /// <param name="point1">The collision point in worldspace</param>
        /// <param name="point2">The collision point in worldspace</param>
        /// <param name="n">The normal pointing to body2.</param>
        /// <param name="penetration">The estimated penetration depth.</param>
        public void Initialize(RigidBody body1, RigidBody body2, ref FPVector point1, ref FPVector point2, ref FPVector n,
                               FP penetration, bool newContact, ContactSettings settings)
        {
            this.body1  = body1;  this.body2 = body2;
            this.normal = n; normal.Normalize();
            this.p1     = point1; this.p2 = point2;

            this.newContact = newContact;

            FPVector.Subtract(ref p1, ref body1.position, out relativePos1);
            FPVector.Subtract(ref p2, ref body2.position, out relativePos2);
            FPVector.Transform(ref relativePos1, ref body1.invOrientation, out realRelPos1);
            FPVector.Transform(ref relativePos2, ref body2.invOrientation, out realRelPos2);

            this.initialPen  = penetration;
            this.penetration = penetration;

            body1IsMassPoint = body1.isParticle;
            body2IsMassPoint = body2.isParticle;

            // Material Properties
            if (newContact)
            {
                treatBody1AsStatic = body1.isStatic;
                treatBody2AsStatic = body2.isStatic;

                accumulatedNormalImpulse  = FP.Zero;
                accumulatedTangentImpulse = FP.Zero;

                lostSpeculativeBounce = FP.Zero;

                switch (settings.MaterialCoefficientMixing)
                {
                case ContactSettings.MaterialCoefficientMixingType.TakeMaximum:
                    staticFriction  = FPMath.Max(body1.staticFriction, body2.staticFriction);
                    dynamicFriction = FPMath.Max(body1.staticFriction, body2.staticFriction);
                    restitution     = FPMath.Max(body1.restitution, body2.restitution);
                    break;

                case ContactSettings.MaterialCoefficientMixingType.TakeMinimum:
                    staticFriction  = FPMath.Min(body1.staticFriction, body2.staticFriction);
                    dynamicFriction = FPMath.Min(body1.staticFriction, body2.staticFriction);
                    restitution     = FPMath.Min(body1.restitution, body2.restitution);
                    break;

                case ContactSettings.MaterialCoefficientMixingType.UseAverage:
                    staticFriction  = (body1.staticFriction + body2.staticFriction) * FP.Half;
                    dynamicFriction = (body1.staticFriction + body2.staticFriction) * FP.Half;
                    restitution     = (body1.restitution + body2.restitution) * FP.Half;
                    break;
                }
            }

            this.settings = settings;
        }
        /// <summary>
        /// Constraints a point on a body to be fixed on a line
        /// which is fixed on another body.
        /// </summary>
        /// <param name="body1"></param>
        /// <param name="body2"></param>
        /// <param name="lineStartPointBody1"></param>
        /// <param name="lineDirection"></param>
        /// <param name="pointBody2"></param>
        public PointOnLine(RigidBody body1, RigidBody body2,
                           FPVector lineStartPointBody1, FPVector pointBody2) : base(body1, body2)
        {
            FPVector.Subtract(ref lineStartPointBody1, ref body1.position, out localAnchor1);
            FPVector.Subtract(ref pointBody2, ref body2.position, out localAnchor2);

            FPVector.Transform(ref localAnchor1, ref body1.invOrientation, out localAnchor1);
            FPVector.Transform(ref localAnchor2, ref body2.invOrientation, out localAnchor2);

            lineNormal = FPVector.Normalize(lineStartPointBody1 - pointBody2);
        }
        /// <summary>
        /// Initializes a new instance of the DistanceConstraint class.
        /// </summary>
        /// <param name="body1">The first body.</param>
        /// <param name="body2">The second body.</param>
        /// <param name="anchor1">The anchor point of the first body in world space.
        /// The distance is given by the initial distance between both anchor points.</param>
        /// <param name="anchor2">The anchor point of the second body in world space.
        /// The distance is given by the initial distance between both anchor points.</param>
        public PointPointDistance(RigidBody body1, RigidBody body2, FPVector anchor1, FPVector anchor2)
            : base(body1, body2)
        {
            FPVector.Subtract(ref anchor1, ref body1.position, out localAnchor1);
            FPVector.Subtract(ref anchor2, ref body2.position, out localAnchor2);

            FPVector.Transform(ref localAnchor1, ref body1.invOrientation, out localAnchor1);
            FPVector.Transform(ref localAnchor2, ref body2.invOrientation, out localAnchor2);

            distance = (anchor1 - anchor2).magnitude;
        }
Ejemplo n.º 14
0
        public void Transform(ref FPMatrix orientation)
        {
            FPVector halfExtents = FP.Half * (max - min);
            FPVector center      = FP.Half * (max + min);

            FPVector.Transform(ref center, ref orientation, out center);

            FPMatrix abs; FPMath.Absolute(ref orientation, out abs);

            FPVector.Transform(ref halfExtents, ref abs, out halfExtents);

            max = center + halfExtents;
            min = center - halfExtents;
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The 5simulation timestep</param>
        public override void PrepareForIteration(FP timestep)
        {
            FPVector.Transform(ref localAnchor1, ref body1.orientation, out r1);
            FPVector.Transform(ref localAnchor2, ref body2.orientation, out r2);

            FPVector p1, p2, dp;

            FPVector.Add(ref body1.position, ref r1, out p1);
            FPVector.Add(ref body2.position, ref r2, out p2);

            FPVector.Subtract(ref p2, ref p1, out dp);

            FP deltaLength = dp.magnitude;

            FPVector n = p2 - p1;

            if (n.sqrMagnitude != FP.Zero)
            {
                n.Normalize();
            }

            jacobian[0] = -FP.One * n;
            jacobian[1] = -FP.One * (r1 % n);
            jacobian[2] = FP.One * n;
            jacobian[3] = (r2 % n);

            effectiveMass = body1.inverseMass + body2.inverseMass
                            + FPVector.Transform(jacobian[1], body1.invInertiaWorld) * jacobian[1]
                            + FPVector.Transform(jacobian[3], body2.invInertiaWorld) * jacobian[3];

            softnessOverDt = softness / timestep;
            effectiveMass += softnessOverDt;

            effectiveMass = FP.One / effectiveMass;

            bias = deltaLength * biasFactor * (FP.One / timestep);

            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * accumulatedImpulse * jacobian[0];
                body1.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * accumulatedImpulse * jacobian[2];
                body2.angularVelocity += FPVector.Transform(accumulatedImpulse * jacobian[3], body2.invInertiaWorld);
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Called once before iteration starts.
        /// </summary>
        /// <param name="timestep">The 5simulation timestep</param>
        public override void PrepareForIteration(FP timestep)
        {
            effectiveMass = body1.invInertiaWorld + body2.invInertiaWorld;

            softnessOverDt = softness / timestep;

            effectiveMass.M11 += softnessOverDt;
            effectiveMass.M22 += softnessOverDt;
            effectiveMass.M33 += softnessOverDt;

            FPMatrix.Inverse(ref effectiveMass, out effectiveMass);

            FPMatrix orientationDifference;

            FPMatrix.Multiply(ref initialOrientation1, ref initialOrientation2, out orientationDifference);
            FPMatrix.Transpose(ref orientationDifference, out orientationDifference);

            FPMatrix q = orientationDifference * body2.invOrientation * body1.orientation;
            FPVector axis;

            FP x = q.M32 - q.M23;
            FP y = q.M13 - q.M31;
            FP z = q.M21 - q.M12;

            FP r = FPMath.Sqrt(x * x + y * y + z * z);
            FP t = q.M11 + q.M22 + q.M33;

            FP angle = FP.Atan2(r, t - 1);

            axis = new FPVector(x, y, z) * angle;

            if (r != FP.Zero)
            {
                axis = axis * (FP.One / r);
            }

            bias = axis * biasFactor * (-FP.One / timestep);

            // Apply previous frame solution as initial guess for satisfying the constraint.
            if (!body1.IsStatic)
            {
                body1.angularVelocity += FPVector.Transform(accumulatedImpulse, body1.invInertiaWorld);
            }
            if (!body2.IsStatic)
            {
                body2.angularVelocity += FPVector.Transform(-FP.One * accumulatedImpulse, body2.invInertiaWorld);
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Applies an impulse on the specific position. Changing linear
        /// and angular velocity.
        /// </summary>
        /// <param name="impulse">Impulse direction and magnitude.</param>
        /// <param name="relativePosition">The position where the impulse gets applied
        /// in Body coordinate frame.</param>
        public void ApplyImpulse(FPVector impulse, FPVector relativePosition)
        {
            if (this.isStatic)
            {
                return;
            }

            FPVector temp;

            FPVector.Multiply(ref impulse, inverseMass, out temp);
            FPVector.Add(ref linearVelocity, ref temp, out linearVelocity);

            FPVector.Cross(ref relativePosition, ref impulse, out temp);
            FPVector.Transform(ref temp, ref invInertiaWorld, out temp);
            FPVector.Add(ref angularVelocity, ref temp, out angularVelocity);
        }
Ejemplo n.º 18
0
        public override void MakeHull(ref List <FPVector> triangleList, int generationThreshold)
        {
            List <FPVector> triangles = new List <FPVector>();

            for (int i = 0; i < shapes.Length; i++)
            {
                shapes[i].Shape.MakeHull(ref triangles, 4);
                for (int e = 0; e < triangles.Count; e++)
                {
                    FPVector pos = triangles[e];
                    FPVector.Transform(ref pos, ref shapes[i].orientation, out pos);
                    FPVector.Add(ref pos, ref shapes[i].position, out pos);
                    triangleList.Add(pos);
                }
                triangles.Clear();
            }
        }
        /// <summary>
        /// Iteratively solve this constraint.
        /// </summary>
        public override void Iterate()
        {
            if (skipConstraint)
            {
                return;
            }

            FP jv =
                body1.linearVelocity * jacobian[0] +
                body1.angularVelocity * jacobian[1] +
                body2.linearVelocity * jacobian[2] +
                body2.angularVelocity * jacobian[3];

            FP softnessScalar = accumulatedImpulse * softnessOverDt;

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

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

            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * lambda * jacobian[0];
                body1.angularVelocity += FPVector.Transform(lambda * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * lambda * jacobian[2];
                body2.angularVelocity += FPVector.Transform(lambda * jacobian[3], body2.invInertiaWorld);
            }
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Iteratively solve this constraint.
        /// </summary>
        public override void Iterate()
        {
            FPVector jv = body1.angularVelocity - body2.angularVelocity;

            FPVector softnessVector = accumulatedImpulse * softnessOverDt;

            FPVector lambda = -FP.One * FPVector.Transform(jv + bias + softnessVector, effectiveMass);

            accumulatedImpulse += lambda;

            if (!body1.IsStatic)
            {
                body1.angularVelocity += FPVector.Transform(lambda, body1.invInertiaWorld);
            }
            if (!body2.IsStatic)
            {
                body2.angularVelocity += FPVector.Transform(-FP.One * lambda, body2.invInertiaWorld);
            }
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Gets the axis aligned bounding box of the orientated shape. (Inlcuding all
        /// 'sub' shapes)
        /// </summary>
        /// <param name="orientation">The orientation of the shape.</param>
        /// <param name="box">The axis aligned bounding box of the shape.</param>
        public override void GetBoundingBox(ref FPMatrix orientation, out TSBBox box)
        {
            box.min = mInternalBBox.min;
            box.max = mInternalBBox.max;

            FPVector localHalfExtents = FP.Half * (box.max - box.min);
            FPVector localCenter      = FP.Half * (box.max + box.min);

            FPVector center;

            FPVector.Transform(ref localCenter, ref orientation, out center);

            FPMatrix abs; FPMath.Absolute(ref orientation, out abs);
            FPVector temp;

            FPVector.Transform(ref localHalfExtents, ref abs, out temp);

            box.max = center + temp;
            box.min = center - temp;
        }
Ejemplo n.º 22
0
        public void DebugDraw(IDebugDrawer drawer)
        {
            FPVector pos1, pos2, pos3;

            for (int i = 0; i < hullPoints.Count; i += 3)
            {
                pos1 = hullPoints[i + 0];
                pos2 = hullPoints[i + 1];
                pos3 = hullPoints[i + 2];

                FPVector.Transform(ref pos1, ref orientation, out pos1);
                FPVector.Add(ref pos1, ref position, out pos1);

                FPVector.Transform(ref pos2, ref orientation, out pos2);
                FPVector.Add(ref pos2, ref position, out pos2);

                FPVector.Transform(ref pos3, ref orientation, out pos3);
                FPVector.Add(ref pos3, ref position, out pos3);

                drawer.DrawTriangle(pos1, pos2, pos3);
            }
        }
        /// <summary>
        /// PrepareForIteration has to be called before <see cref="Iterate"/>.
        /// </summary>
        /// <param name="timestep">The timestep of the simulation.</param>
        public void PrepareForIteration(FP timestep)
        {
            FPVector dv      = CalculateRelativeVelocity();
            FP       kNormal = FP.Zero;

            FPVector rantra = FPVector.zero;

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

                if (!body1IsMassPoint)
                {
                    FPVector.Cross(ref relativePos1, ref normal, out rantra);
                    FPVector.Transform(ref rantra, ref body1.invInertiaWorld, out rantra);
                    FPVector.Cross(ref rantra, ref relativePos1, out rantra);
                }
            }

            FPVector rbntrb = FPVector.zero;

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

                if (!body2IsMassPoint)
                {
                    FPVector.Cross(ref relativePos2, ref normal, out rbntrb);
                    FPVector.Transform(ref rbntrb, ref body2.invInertiaWorld, out rbntrb);
                    FPVector.Cross(ref rbntrb, ref relativePos2, out rbntrb);
                }
            }

            if (!treatBody1AsStatic)
            {
                kNormal += FPVector.Dot(ref rantra, ref normal);
            }

            if (!treatBody2AsStatic)
            {
                kNormal += FPVector.Dot(ref rbntrb, ref normal);
            }

            massNormal = FP.One / kNormal;

            tangent = dv - FPVector.Dot(dv, normal) * normal;
            tangent.Normalize();

            FP kTangent = FP.Zero;

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

                if (!body1IsMassPoint)
                {
                    FPVector.Cross(ref relativePos1, ref normal, out rantra);
                    FPVector.Transform(ref rantra, ref body1.invInertiaWorld, out rantra);
                    FPVector.Cross(ref rantra, ref relativePos1, out rantra);
                }
            }

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

                if (!body2IsMassPoint)
                {
                    FPVector.Cross(ref relativePos2, ref tangent, out rbntrb);
                    FPVector.Transform(ref rbntrb, ref body2.invInertiaWorld, out rbntrb);
                    FPVector.Cross(ref rbntrb, ref relativePos2, out rbntrb);
                }
            }

            if (!treatBody1AsStatic)
            {
                kTangent += FPVector.Dot(ref rantra, ref tangent);
            }
            if (!treatBody2AsStatic)
            {
                kTangent += FPVector.Dot(ref rbntrb, ref tangent);
            }

            massTangent = FP.One / kTangent;

            restitutionBias = lostSpeculativeBounce;

            speculativeVelocity = FP.Zero;

            FP relNormalVel = FPVector.Dot(ref normal, ref dv);

            if (Penetration > settings.allowedPenetration)
            {
                restitutionBias = settings.bias * (FP.One / timestep) * FPMath.Max(FP.Zero, Penetration - settings.allowedPenetration);
                restitutionBias = FPMath.Clamp(restitutionBias, FP.Zero, settings.maximumBias);
                //  body1IsMassPoint = body2IsMassPoint = false;
            }


            FP timeStepRatio = timestep / lastTimeStep;

            accumulatedNormalImpulse  *= timeStepRatio;
            accumulatedTangentImpulse *= timeStepRatio;

            {
                // Static/Dynamic friction
                FP relTangentVel     = -FPVector.Dot(ref tangent, ref dv);
                FP tangentImpulse    = massTangent * relTangentVel;
                FP maxTangentImpulse = -staticFriction * accumulatedNormalImpulse;

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

            FPVector 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 < -FP.One && newContact)
            {
                restitutionBias = FPMath.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       = FP.Zero;
            }
            else
            {
                lostSpeculativeBounce = FP.Zero;
            }

            impulse = normal * accumulatedNormalImpulse + tangent * accumulatedTangentImpulse;
            ApplyImpulse(ref impulse);

            lastTimeStep = timestep;

            newContact = false;
        }
Ejemplo n.º 24
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 FPMatrix orientation, ref FPVector position, ref FPVector point)
        {
            FPVector arbitraryPoint;

            SupportMapTransformed(support, ref orientation, ref position, ref point, out arbitraryPoint);
            FPVector.Subtract(ref point, ref arbitraryPoint, out arbitraryPoint);

            FPVector r; support.SupportCenter(out r);

            FPVector.Transform(ref r, ref orientation, out r);
            FPVector.Add(ref position, ref r, out r);
            FPVector.Subtract(ref point, ref r, out r);

            FPVector x = point;
            FPVector w, p;
            FP       VdotR;

            FPVector v; FPVector.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);
                FPVector.Subtract(ref x, ref p, out w);

                FP VdotW = FPVector.Dot(ref v, ref w);

                if (VdotW > FP.Zero)
                {
                    VdotR = FPVector.Dot(ref v, ref r);

                    if (VdotR >= -(FPMath.Epsilon * FPMath.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);
        }
Ejemplo n.º 25
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 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;
                        }
                    }
                }
            }
        }
Ejemplo n.º 26
0
        private void DetectRigidRigid(RigidBody body1, RigidBody body2)
        {
            bool b1IsMulti = (body1.Shape is Multishape);
            bool b2IsMulti = (body2.Shape is Multishape);

            bool speculative = speculativeContacts ||
                               (body1.EnableSpeculativeContacts || body2.EnableSpeculativeContacts);

            FPVector point, normal;
            FP       penetration;

            if (!b1IsMulti && !b2IsMulti)
            {
                if (XenoCollide.Detect(body1.Shape, body2.Shape, ref body1.orientation,
                                       ref body2.orientation, ref body1.position, ref body2.position,
                                       out point, out normal, out penetration))
                {
                    //normal = JVector.Up;
                    //UnityEngine.Debug.Log("FINAL  --- >>> normal: " + normal);
                    FPVector point1, point2;
                    FindSupportPoints(body1, body2, body1.Shape, body2.Shape, ref point, ref normal, out point1, out point2);
                    RaiseCollisionDetected(body1, body2, ref point1, ref point2, ref normal, penetration);
                }
                else if (speculative)
                {
                    FPVector hit1, hit2;

                    if (GJKCollide.ClosestPoints(body1.Shape, body2.Shape, ref body1.orientation, ref body2.orientation,
                                                 ref body1.position, ref body2.position, out hit1, out hit2, out normal))
                    {
                        FPVector delta = hit2 - hit1;

                        if (delta.sqrMagnitude < (body1.sweptDirection - body2.sweptDirection).sqrMagnitude)
                        {
                            penetration = delta * normal;

                            if (penetration < FP.Zero)
                            {
                                RaiseCollisionDetected(body1, body2, ref hit1, ref hit2, ref normal, penetration);
                            }
                        }
                    }
                }

                //UnityEngine.Debug.Log("-----------------------: " + normal);
            }
            else if (b1IsMulti && b2IsMulti)
            {
                Multishape ms1 = (body1.Shape as Multishape);
                Multishape ms2 = (body2.Shape as Multishape);

                ms1 = ms1.RequestWorkingClone();
                ms2 = ms2.RequestWorkingClone();

                FPBBox transformedBoundingBox = body2.boundingBox;
                transformedBoundingBox.InverseTransform(ref body1.position, ref body1.orientation);

                int ms1Length = ms1.Prepare(ref transformedBoundingBox);

                transformedBoundingBox = body1.boundingBox;
                transformedBoundingBox.InverseTransform(ref body2.position, ref body2.orientation);

                int ms2Length = ms2.Prepare(ref transformedBoundingBox);

                if (ms1Length == 0 || ms2Length == 0)
                {
                    ms1.ReturnWorkingClone();
                    ms2.ReturnWorkingClone();
                    return;
                }

                for (int i = 0; i < ms1Length; i++)
                {
                    ms1.SetCurrentShape(i);

                    for (int e = 0; e < ms2Length; e++)
                    {
                        ms2.SetCurrentShape(e);

                        if (XenoCollide.Detect(ms1, ms2, ref body1.orientation,
                                               ref body2.orientation, ref body1.position, ref body2.position,
                                               out point, out normal, out penetration))
                        {
                            FPVector point1, point2;
                            FindSupportPoints(body1, body2, ms1, ms2, ref point, ref normal, out point1, out point2);
                            RaiseCollisionDetected(body1, body2, ref point1, ref point2, ref normal, penetration);
                        }
                        else if (speculative)
                        {
                            FPVector hit1, hit2;

                            if (GJKCollide.ClosestPoints(ms1, ms2, ref body1.orientation, ref body2.orientation,
                                                         ref body1.position, ref body2.position, out hit1, out hit2, out normal))
                            {
                                FPVector delta = hit2 - hit1;

                                if (delta.sqrMagnitude < (body1.sweptDirection - body2.sweptDirection).sqrMagnitude)
                                {
                                    penetration = delta * normal;

                                    if (penetration < FP.Zero)
                                    {
                                        RaiseCollisionDetected(body1, body2, ref hit1, ref hit2, ref normal, penetration);
                                    }
                                }
                            }
                        }
                    }
                }

                ms1.ReturnWorkingClone();
                ms2.ReturnWorkingClone();
            }
            else
            {
                RigidBody b1, b2;

                if (body2.Shape is Multishape)
                {
                    b1 = body2; b2 = body1;
                }
                else
                {
                    b2 = body2; b1 = body1;
                }

                Multishape ms = (b1.Shape as Multishape);

                ms = ms.RequestWorkingClone();

                FPBBox transformedBoundingBox = b2.boundingBox;
                transformedBoundingBox.InverseTransform(ref b1.position, ref b1.orientation);

                int msLength = ms.Prepare(ref transformedBoundingBox);

                if (msLength == 0)
                {
                    ms.ReturnWorkingClone();
                    return;
                }

                for (int i = 0; i < msLength; i++)
                {
                    ms.SetCurrentShape(i);

                    if (XenoCollide.Detect(ms, b2.Shape, ref b1.orientation,
                                           ref b2.orientation, ref b1.position, ref b2.position,
                                           out point, out normal, out penetration))
                    {
                        FPVector point1, point2;
                        FindSupportPoints(b1, b2, ms, b2.Shape, ref point, ref normal, out point1, out point2);

                        if (useTerrainNormal && ms is TerrainShape)
                        {
                            (ms as TerrainShape).CollisionNormal(out normal);
                            FPVector.Transform(ref normal, ref b1.orientation, out normal);
                        }
                        else if (useTriangleMeshNormal && ms is TriangleMeshShape)
                        {
                            (ms as TriangleMeshShape).CollisionNormal(out normal);
                            FPVector.Transform(ref normal, ref b1.orientation, out normal);
                        }

                        RaiseCollisionDetected(b1, b2, ref point1, ref point2, ref normal, penetration);
                    }
                    else if (speculative)
                    {
                        FPVector hit1, hit2;

                        if (GJKCollide.ClosestPoints(ms, b2.Shape, ref b1.orientation, ref b2.orientation,
                                                     ref b1.position, ref b2.position, out hit1, out hit2, out normal))
                        {
                            FPVector delta = hit2 - hit1;

                            if (delta.sqrMagnitude < (body1.sweptDirection - body2.sweptDirection).sqrMagnitude)
                            {
                                penetration = delta * normal;

                                if (penetration < FP.Zero)
                                {
                                    RaiseCollisionDetected(b1, b2, ref hit1, ref hit2, ref normal, penetration);
                                }
                            }
                        }
                    }
                }

                ms.ReturnWorkingClone();
            }
        }
 public override void DebugDraw(IDebugDrawer drawer)
 {
     drawer.DrawLine(body1.position + r1,
                     body1.position + r1 + FPVector.Transform(lineNormal, body1.orientation) * 100);
 }
Ejemplo n.º 28
0
 /// <summary>
 /// Adds torque to the body. The torque gets applied
 /// the next time <see cref="World.Step"/> is called. The 'impact'
 /// of the torque depends on the time it is applied to a body - so
 /// the timestep influences the energy added to the body.
 /// </summary>
 /// <param name="torque">The torque to add next <see cref="World.Step"/>.</param>
 public void AddRelativeTorque(FPVector torque)
 {
     torque = FPVector.Transform(torque, this.FPOrientation);
     FPVector.Add(ref torque, ref this.torque, out this.torque);
 }