Example #1
0
        /** Bias towards the right side of agents.
         * Rotate desiredVelocity at most [value] number of radians. 1 radian ≈ 57°
         * This breaks up symmetries.
         *
         * The desired velocity will only be rotated if it is inside a velocity obstacle (VO).
         * If it is inside one, it will not be rotated further than to the edge of it
         *
         * The targetPointInVelocitySpace will be rotated by the same amount as the desired velocity
         *
         * \returns True if the desired velocity was inside any VO
         */
        static bool BiasDesiredVelocity(VOBuffer vos, ref TSVector2 desiredVelocity, ref TSVector2 targetPointInVelocitySpace, FP maxBiasRadians)
        {
            var desiredVelocityMagn = desiredVelocity.magnitude;
            FP  maxValue            = FP.Zero;

            for (int i = 0; i < vos.length; i++)
            {
                FP value;
                // The value is approximately the distance to the edge of the VO
                // so taking the maximum will give us the distance to the edge of the VO
                // which the desired velocity is furthest inside
                vos.buffer[i].Gradient(desiredVelocity, out value);
                maxValue = TSMath.Max(maxValue, value);
            }

            // Check if the agent was inside any VO
            var inside = maxValue > 0;

            // Avoid division by zero below
            if (desiredVelocityMagn < FP.One / 1000)
            {
                return(inside);
            }

            // Rotate the desired velocity clockwise (to the right) at most maxBiasRadians number of radians
            // Assuming maxBiasRadians is small, we can just move it instead and it will give approximately the same effect
            // See https://en.wikipedia.org/wiki/Small-angle_approximation
            var angle = TSMath.Min(maxBiasRadians, maxValue / desiredVelocityMagn);

            desiredVelocity            += new TSVector2(desiredVelocity.y, -desiredVelocity.x) * angle;
            targetPointInVelocitySpace += new TSVector2(targetPointInVelocitySpace.y, -targetPointInVelocitySpace.x) * angle;
            return(inside);
        }
Example #2
0
 internal void Extend(Envelope by)
 {
     X1 = TSMath.Min(X1, by.X1);
     Y1 = TSMath.Min(Y1, by.Y1);
     X2 = TSMath.Max(X2, by.X2);
     Y2 = TSMath.Max(Y2, by.Y2);
 }
Example #3
0
    public static RectInt ToRect(this SDFRawData sdf, TSVector2 start, TSVector2 end)
    {
        TSVector2 min = new TSVector2(TSMath.Min(start.x, end.x), TSMath.Min(start.y, end.y));
        TSVector2 max = new TSVector2(TSMath.Max(start.x, end.x), TSMath.Max(start.y, end.y));

        return(new RectInt(sdf.FloorToGrid(min), sdf.CeilingToGrid(max)));
    }
Example #4
0
        private static FP IntersectionArea(Envelope what, Envelope with)
        {
            var minX = TSMath.Max(what.X1, with.X1);
            var minY = TSMath.Max(what.Y1, with.Y1);
            var maxX = TSMath.Min(what.X2, with.X2);
            var maxY = TSMath.Min(what.Y2, with.Y2);

            return(TSMath.Max(0, maxX - minX) * TSMath.Max(0, maxY - minY));
        }
Example #5
0
        private static FP CombinedArea(Envelope what, Envelope with)
        {
            var minX1 = TSMath.Max(what.X1, with.X1);
            var minY1 = TSMath.Max(what.Y1, with.Y1);
            var maxX2 = TSMath.Min(what.X2, with.X2);
            var maxY2 = TSMath.Min(what.Y2, with.Y2);

            return((maxX2 - minX1) * (maxY2 - minY1));
        }
Example #6
0
        /** \copydoc Pathfinding::RVO::IAgent::SetTarget */
        public void SetTarget(TSVector2 targetPoint, FP desiredSpeed, FP maxSpeed)
        {
            maxSpeed     = TSMath.Max(maxSpeed, 0);
            desiredSpeed = TSMath.Min(TSMath.Max(desiredSpeed, 0), maxSpeed);

            nextTargetPoint  = targetPoint;
            nextDesiredSpeed = desiredSpeed;
            nextMaxSpeed     = maxSpeed;
        }
Example #7
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 TSVector point1, ref TSVector point2, ref TSVector 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;

            TSVector.Subtract(ref p1, ref body1.position, out relativePos1);
            TSVector.Subtract(ref p2, ref body2.position, out relativePos2);
            TSVector.Transform(ref relativePos1, ref body1.invOrientation, out realRelPos1);
            TSVector.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;

                CBFrame.Utils.Logger.Debug("line812 body2.isStatic:" + body2.isStatic + ",body1.isStatic:" + body1.isStatic);

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

                lostSpeculativeBounce = FP.Zero;

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

                case ContactSettings.MaterialCoefficientMixingType.TakeMinimum:
                    staticFriction  = TSMath.Min(body1.staticFriction, body2.staticFriction);
                    dynamicFriction = TSMath.Min(body1.staticFriction, body2.staticFriction);
                    restitution     = TSMath.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;
        }
Example #8
0
    //旋转的box
    public static FP SDOrientedBox(TSVector2 x, TSVector2 c, TSVector2 rot, TSVector2 b)
    {
        TSVector2 v  = x - c;
        FP        px = TSMath.Abs(TSVector2.Dot(v, rot));                          //在box的x轴的投影长度
        FP        py = TSMath.Abs(TSVector2.Dot(v, new TSVector2(-rot.y, rot.x))); //在box的y轴的投影长度
        TSVector2 p  = new TSVector2(px, py);
        TSVector2 d  = p - b;

        return(TSVector2.Max(d, TSVector2.zero).sqrMagnitude + TSMath.Min(TSMath.Max(d.x, d.y), FP.Zero));
    }
Example #9
0
    //不旋转的box
    public static FP SDBox(TSVector2 x, TSVector2 c, TSVector2 b)
    {
        TSVector2 p = x - c;

        p.x = TSMath.Abs(p.x);
        p.y = TSMath.Abs(p.y);
        TSVector2 d = p - b;

        return(TSVector2.Max(d, TSVector2.zero).sqrMagnitude + TSMath.Min(TSMath.Max(d.x, d.y), FP.Zero));
    }
Example #10
0
        /// <summary>
        /// Passes a axis aligned bounding box to the shape where collision
        /// could occour.
        /// </summary>
        /// <param name="box">The bounding box where collision could occur.</param>
        /// <returns>The upper index with which <see cref="SetCurrentShape"/> can be
        /// called.</returns>
        public override int Prepare(ref TSBBox box)
        {
            // simple idea: the terrain is a grid. x and z is the position in the grid.
            // y the height. we know compute the min and max grid-points. All quads
            // between these points have to be checked.

            // including overflow exception prevention

            if (box.min.x < boundings.min.x)
            {
                minX = 0;
            }
            else
            {
                minX = (int)FP.Floor(((box.min.x - sphericalExpansion) / scaleX));
                minX = (int)TSMath.Max(minX, 0);
            }

            if (box.max.x > boundings.max.x)
            {
                maxX = heightsLength0 - 1;
            }
            else
            {
                maxX = (int)FP.Ceiling(((box.max.x + sphericalExpansion) / scaleX));
                maxX = (int)TSMath.Min(maxX, heightsLength0 - 1);
            }

            if (box.min.z < boundings.min.z)
            {
                minZ = 0;
            }
            else
            {
                minZ = (int)FP.Floor(((box.min.z - sphericalExpansion) / scaleZ));
                minZ = (int)TSMath.Max(minZ, 0);
            }

            if (box.max.z > boundings.max.z)
            {
                maxZ = heightsLength1 - 1;
            }
            else
            {
                maxZ = (int)FP.Ceiling((FP)((box.max.z + sphericalExpansion) / scaleZ));
                maxZ = (int)TSMath.Min(maxZ, heightsLength1 - 1);
            }

            numX = maxX - minX;
            numZ = maxZ - minZ;

            // since every quad contains two triangles we multiply by 2.
            return(numX * numZ * 2);
        }
Example #11
0
 public static bool rectsIntersect(TSVector2 S1, TSVector2 E1, TSVector2 S2, TSVector2 E2)
 {
     if (TSMath.Min(S1.y, E1.y) <= TSMath.Max(S2.y, E2.y) &&
         TSMath.Max(S1.y, E1.y) >= TSMath.Min(S2.y, E2.y) &&
         TSMath.Min(S1.x, E1.x) <= TSMath.Max(S2.x, E2.x) &&
         TSMath.Max(S1.x, E1.x) >= TSMath.Min(S2.x, E2.x))
     {
         return(true);
     }
     return(false);
 }
Example #12
0
            public void QueryRec(int i, QTBound r)
            {
                var radius = TSMath.Min(TSMath.Max((nodes[i].maxSpeed + speed) * timeHorizon, TRadius), maxRadius); //+ TRadius,warning

                if (nodes[i].childNode1 == i)
                {
                    // Leaf node
                    for (T a = nodes[i].nextData; a != null; a = (T)a.next)
                    {
                        FP v = T.InsertNeighbour(a, radius * radius);
                        //
                        if (v < maxRadius * maxRadius)
                        {
                            maxRadius = TSMath.Sqrt(v);
                        }
                    }
                }
                else
                {
                    TSVector min = TSVector.zero, max = TSVector.zero;
                    // Not a leaf node
                    TSVector c = r.center;
                    if (p.x - radius < c.x)
                    {
                        if (p.z - radius < c.z)
                        {
                            QueryRec(nodes[i].childNode1, QTBound.MinMaxQTBound(r.min, c));
                            radius = TSMath.Min(radius, maxRadius);
                        }
                        if (p.z + radius > c.z)
                        {
                            min.Set(r.min.x, 0, c.z);
                            max.Set(c.x, 0, r.max.z);
                            QueryRec(nodes[i].childNode2, QTBound.MinMaxQTBound(min, max));
                            radius = TSMath.Min(radius, maxRadius);
                        }
                    }

                    if (p.x + radius > c.x)
                    {
                        if (p.z - radius < c.z)
                        {
                            max.Set(r.max.x, 0, c.z);
                            min.Set(c.x, 0, r.min.z);
                            QueryRec(nodes[i].childNode3, QTBound.MinMaxQTBound(min, max));
                            radius = TSMath.Min(radius, maxRadius);
                        }
                        if (p.z + radius > c.z)
                        {
                            QueryRec(nodes[i].childNode4, QTBound.MinMaxQTBound(c, r.max));
                        }
                    }
                }
            }
Example #13
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="forceToApply">basic force</param>
        /// <param name="basicVelocity">basic Velocity</param>
        /// <returns></returns>
        protected TSVector ApplySeperateForce(TSVector toAcc, List <IAgentBehaviour> agents, bool bSkipStatic)//,out bool isTminStaticAgent
        {
            int      count         = agents.Count;
            TSVector boidsVelocity = TSVector.zero;
            TSVector forceToApply  = TSVector.zero;
            {
                TSVector totalForce         = TSVector.zero;
                int      neighboursCountSep = 0;
                FP       radius             = _behaviour.colliderRadius * 4;
                FP       sepSqr             = radius * radius;//
                FP       nrSqr = _behaviour.baseData.neighbourRadiusSqr * FP.EN2 * 25;
                for (int j = 0; j < count; j++)
                {
                    IAgentBehaviour a = agents[j];// _behaviour.neighbours
                    Boids.BoidsBehaviourSeparation(_behaviour, a, sepSqr, ref totalForce, ref neighboursCountSep, bSkipStatic);
                }

                if (count > 0)
                {
                    TSVector sep = totalForce * (_behaviour.baseData.maxForce) / count;

                    FP lenSqr = sep.sqrMagnitude;
                    if (lenSqr > _behaviour.baseData.maxForceSqr)
                    {
                        FP fval = _behaviour.baseData.maxForce / TSMath.Sqrt(lenSqr);
                        sep = sep * fval;
                    }
                    forceToApply = sep;
                    if (PathFindingManager.DEBUG)
                    {
#if UNITY_5_5_OR_NEWER && !MULTI_THREAD
                        if (FP.Abs(forceToApply.x) > GridMap.SCALE * 1000 || FP.Abs(forceToApply.z) > GridMap.SCALE * 1000)
                        {
                            UnityEngine.Debug.LogError("forceToApply error!");
                        }
#endif
                    }
                }
            }

            if (forceToApply != TSVector.zero)
            {
                FP max = TSMath.Max(TSMath.Abs(forceToApply.x), TSMath.Abs(forceToApply.z));
                if (max > _behaviour.baseData.maxForce * FP.EN1 * 7)
                {
                    forceToApply = forceToApply / max;
                    forceToApply = _behaviour.baseData.maxForce * forceToApply.normalized * FP.EN1 * 6;
                }
                return((forceToApply + toAcc) * _behaviour.baseData.invMass);//
            }
            return(forceToApply + toAcc);
        }
Example #14
0
            public FP?IntersectsWithRay(TSVector2 origin, TSVector2 direction)
            {
                FP          largestDistance = TSMath.Max(A.Position.x - origin.x, B.Position.x - origin.x) * 2f;
                LineSegment raySegment      = new LineSegment(new Vertex(origin, 0), new Vertex(origin + (direction * largestDistance), 0));

                TSVector2?intersection = FindIntersection(this, raySegment);
                FP?       value        = null;

                if (intersection != null)
                {
                    value = TSVector2.Distance(origin, intersection.Value);
                }

                return(value);
            }
Example #15
0
            /// <summary>
            /// Iteratively solve this constraint.
            /// </summary>
            public override void Iterate()
            {
                if (skipConstraint)
                {
                    return;
                }

                FP jv = TSVector.Dot(ref body1.linearVelocity, ref jacobian[0]);

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

                FP softnessScalar = accumulatedImpulse * softnessOverDt;

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

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

                TSVector temp;

                CBFrame.Utils.Logger.Debug("line195 body2.linearVelocity:" + body2.linearVelocity + ",body1.linearVelocity:" + body1.linearVelocity);
                if (!body1.isStatic)
                {
                    TSVector.Multiply(ref jacobian[0], lambda * body1.inverseMass, out temp);
                    TSVector.Add(ref temp, ref body1.linearVelocity, out body1.linearVelocity);
                }
                CBFrame.Utils.Logger.Debug("line201 body2.linearVelocity:" + body2.linearVelocity + ",body1.linearVelocity:" + body1.linearVelocity);
                if (!body2.isStatic)
                {
                    TSVector.Multiply(ref jacobian[1], lambda * body2.inverseMass, out temp);
                    TSVector.Add(ref temp, ref body2.linearVelocity, out body2.linearVelocity);
                }
                CBFrame.Utils.Logger.Debug("line206 body2.linearVelocity:" + body2.linearVelocity + ",body1.linearVelocity:" + body1.linearVelocity);
            }
        /// <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 = TSMath.Max(accumulatedImpulse + lambda, 0);
                lambda             = accumulatedImpulse - previousAccumulatedImpulse;
            }
            else if (behavior == DistanceBehavior.LimitMaximumDistance)
            {
                FP previousAccumulatedImpulse = accumulatedImpulse;
                accumulatedImpulse = TSMath.Min(accumulatedImpulse + lambda, 0);
                lambda             = accumulatedImpulse - previousAccumulatedImpulse;
            }
            else
            {
                accumulatedImpulse += lambda;
            }
            CBFrame.Utils.Logger.Debug("line202 body2.linearVelocity:" + body2.linearVelocity + ",body1.linearVelocity:" + body1.linearVelocity);
            if (!body1.isStatic)
            {
                body1.linearVelocity  += body1.inverseMass * lambda * jacobian[0];
                body1.angularVelocity += TSVector.Transform(lambda * jacobian[1], body1.invInertiaWorld);
            }

            if (!body2.isStatic)
            {
                body2.linearVelocity  += body2.inverseMass * lambda * jacobian[2];
                body2.angularVelocity += TSVector.Transform(lambda * jacobian[3], body2.invInertiaWorld);
            }
            CBFrame.Utils.Logger.Debug("line213 body2.linearVelocity:" + body2.linearVelocity + ",body1.linearVelocity:" + body1.linearVelocity);
        }
Example #17
0
        /// <summary>
        /// Gets an avoidance vector.
        /// </summary>
        /// <param name="selfPos">This unit's position.</param>
        /// <param name="currentVelocity">This unit's current velocity.</param>
        /// <param name="normalVelocity">This unit's normalized current velocity.</param>
        /// <param name="unitData">This unit's UnitFacade.</param>
        /// <param name="otherPos">The other unit's position.</param>
        /// <param name="otherVelocity">The other unit's velocity.</param>
        /// <param name="otherData">The other unit's UnitFacade.</param>
        /// <param name="combinedRadius">The combined radius.</param>
        /// <returns>An avoidance vector from the other unit's collision position to this unit's collision position - if a collision actually is detected.</returns>
        private static TSVector GetAvoidVector(TSVector selfPos, TSVector currentVelocity, TSVector normalVelocity, IAgentBehaviour unitData, TSVector otherPos, TSVector otherVelocity, IAgentBehaviour otherData, FP combinedRadius)
        {
            TSVector selfCollisionPos = TSVector.zero;
            TSVector avoidDirection   = GetAvoidDirectionVector(selfPos, currentVelocity, otherPos, otherVelocity, combinedRadius, out selfCollisionPos);
            FP       avoidMagnitude   = avoidDirection.magnitude;

            if (avoidMagnitude == 0)
            {
                // if there is absolutely no magnitude to the found avoid direction, then ignore it
                return(TSVector.zero);
            }

            FP vectorLength = combinedRadius * CustomMath.FPHalf;

            if (vectorLength <= 0)
            {
                // if the units' combined radius is 0, then we cannot avoid
                return(TSVector.zero);
            }

            // normalize the avoid vector and then set it's magnitude to the desired vector length (half of the combined radius)
            TSVector avoidNormalized = (avoidDirection / avoidMagnitude);
            TSVector avoidVector     = avoidNormalized * vectorLength;

            FP dotAngle = TSVector.Dot(avoidNormalized, normalVelocity);

            if (dotAngle <= _cosAvoidAngle)
            {
                // the collision is considered "head-on", thus we compute a perpendicular avoid vector instead
                avoidVector = new TSVector(avoidVector.z, avoidVector.y, -avoidVector.x);
            }
            else if (preventPassingInFront
                     //&& (otherData.determination > unitData.determination)
                     && (TSVector.Dot(otherVelocity, avoidVector) > 0 && TSVector.Dot(currentVelocity, otherVelocity) >= 0))
            {
                // if supposed to be preventing front-passing, then check whether we should prevent it in this case and if so compute a different avoid vector
                avoidVector = selfCollisionPos - selfPos;
            }

            // scale the avoid vector depending on the distance to collision, shorter distances need larger magnitudes and vice versa
            FP collisionDistance = TSMath.Max(1, (selfPos - selfCollisionPos).magnitude);

            avoidVector *= currentVelocity.magnitude / collisionDistance;

            return(avoidVector);
        }
Example #18
0
 public FP CalculateMaxSpeed(QTNode[] nodes, int index)
 {
     if (childNode1 == index)
     {
         // Leaf node
         for (var data = nextData; data != null; data = (T)data.next)
         {
             maxSpeed = TSMath.Max(maxSpeed, data.speed);
         }
     }
     else
     {
         maxSpeed = TSMath.Max(nodes[childNode1].CalculateMaxSpeed(nodes, childNode1), nodes[childNode2].CalculateMaxSpeed(nodes, childNode2));
         maxSpeed = TSMath.Max(maxSpeed, nodes[childNode3].CalculateMaxSpeed(nodes, childNode3));
         maxSpeed = TSMath.Max(maxSpeed, nodes[childNode4].CalculateMaxSpeed(nodes, childNode4));
     }
     return(maxSpeed);
 }
Example #19
0
            /// <summary>
            /// Iteratively solve this constraint.
            /// </summary>
            public override void Iterate()
            {
                if (skipConstraint)
                {
                    return;
                }

                FP jv = TSVector.Dot(body1.linearVelocity, jacobian[0]);

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

                FP softnessScalar = accumulatedImpulse * softnessOverDt;

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

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

                TSVector temp;

                if (!body1.isStatic)
                {
                    body1.ApplyImpulse(jacobian[0] * lambda);
                }

                if (!body2.isStatic)
                {
                    body2.ApplyImpulse(jacobian[1] * lambda);
                }
            }
Example #20
0
        public FP Distance(FP x, FP y)
        {
            FP distanceSquared = 0;
            FP greatestMin     = TSMath.Max(X1, x);
            FP leastMax        = TSMath.Min(X2, x);

            if (greatestMin > leastMax)
            {
                distanceSquared += TSMath.Pow(greatestMin - leastMax, 2);
            }
            greatestMin = TSMath.Max(Y1, y);
            leastMax    = TSMath.Min(Y2, y);
            if (greatestMin > leastMax)
            {
                distanceSquared += TSMath.Pow(greatestMin - leastMax, 2);
            }

            return((FP)TSMath.Sqrt(distanceSquared));
        }
Example #21
0
        /** Traces the vector field constructed out of the velocity obstacles.
         * Returns the position which gives the minimum score (approximately).
         *
         * \see https://en.wikipedia.org/wiki/Gradient_descent
         */
        TSVector2 Trace(VOBuffer vos, TSVector2 p, out FP score)
        {
            // Pick a reasonable initial step size
            FP stepSize = TSMath.Max(radius, FP.One / 5 * desiredSpeed);

            FP        bestScore = FP.MaxValue;
            TSVector2 bestP     = p;

            // TODO: Add momentum to speed up convergence?

            const int MaxIterations = 50;

            for (int s = 0; s < MaxIterations; s++)
            {
                FP step = 1 - (s * FP.One / MaxIterations);
                step = Sqr(step) * stepSize;

                FP  value;
                var gradient = EvaluateGradient(vos, p, out value);

                if (value < bestScore)
                {
                    bestScore = value;
                    bestP     = p;
                }

                // TODO: Add cutoff for performance
                gradient.Normalize();
                gradient *= step;
                TSVector2 prev = p;
                p += gradient;

                // if (DebugDraw) Debug.DrawLine(FromXZ(prev + position), FromXZ(p + position), Rainbow(s * 0.1f) * new Color(1, 1, 1, 1f));
            }

            score = bestScore;
            return(bestP);
        }
Example #22
0
        private void PostSolve(Contact contact, ContactVelocityConstraint impulse)
        {
            bool flag = !this.Broken;

            if (flag)
            {
                bool flag2 = this.Parts.Contains(contact.FixtureA) || this.Parts.Contains(contact.FixtureB);
                if (flag2)
                {
                    FP  fP         = 0f;
                    int pointCount = contact.Manifold.PointCount;
                    for (int i = 0; i < pointCount; i++)
                    {
                        fP = TSMath.Max(fP, impulse.points[i].normalImpulse);
                    }
                    bool flag3 = fP > this.Strength;
                    if (flag3)
                    {
                        this._break = true;
                    }
                }
            }
        }
        /// <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)
        {
            FP dvx, dvy, dvz;

            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;

            FP kNormal = FP.Zero;

            TSVector rantra = TSVector.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);
                    FP num0 = ((rantra.x * body1.invInertiaWorld.M11) + (rantra.y * body1.invInertiaWorld.M21)) + (rantra.z * body1.invInertiaWorld.M31);
                    FP num1 = ((rantra.x * body1.invInertiaWorld.M12) + (rantra.y * body1.invInertiaWorld.M22)) + (rantra.z * body1.invInertiaWorld.M32);
                    FP 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;
                }
            }

            TSVector rbntrb = TSVector.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);
                    FP num0 = ((rbntrb.x * body2.invInertiaWorld.M11) + (rbntrb.y * body2.invInertiaWorld.M21)) + (rbntrb.z * body2.invInertiaWorld.M31);
                    FP num1 = ((rbntrb.x * body2.invInertiaWorld.M12) + (rbntrb.y * body2.invInertiaWorld.M22)) + (rbntrb.z * body2.invInertiaWorld.M32);
                    FP 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 = FP.One / kNormal;

            FP 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 != FP.Zero)
            {
                num        = FP.Sqrt(num);
                tangent.x /= num;
                tangent.y /= num;
                tangent.z /= num;
            }

            FP kTangent = FP.Zero;

            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);
                    FP num0 = ((rantra.x * body1.invInertiaWorld.M11) + (rantra.y * body1.invInertiaWorld.M21)) + (rantra.z * body1.invInertiaWorld.M31);
                    FP num1 = ((rantra.x * body1.invInertiaWorld.M12) + (rantra.y * body1.invInertiaWorld.M22)) + (rantra.z * body1.invInertiaWorld.M32);
                    FP 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);
                    FP num0 = ((rbntrb.x * body2.invInertiaWorld.M11) + (rbntrb.y * body2.invInertiaWorld.M21)) + (rbntrb.z * body2.invInertiaWorld.M31);
                    FP num1 = ((rbntrb.x * body2.invInertiaWorld.M12) + (rbntrb.y * body2.invInertiaWorld.M22)) + (rbntrb.z * body2.invInertiaWorld.M32);
                    FP 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 += TSVector.Dot(ref rantra, ref tangent);
            }
            if (!treatBody2AsStatic)
            {
                kTangent += TSVector.Dot(ref rbntrb, ref tangent);
            }
            massTangent = FP.One / kTangent;

            restitutionBias = lostSpeculativeBounce;

            speculativeVelocity = FP.Zero;

            FP relNormalVel = normal.x * dvx + normal.y * dvy + normal.z * dvz; //JVector.Dot(ref normal, ref dv);

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


            FP timeStepRatio = timestep / lastTimeStep;

            accumulatedNormalImpulse  *= timeStepRatio;
            accumulatedTangentImpulse *= timeStepRatio;

            {
                // Static/Dynamic friction
                FP relTangentVel     = -(tangent.x * dvx + tangent.y * dvy + tangent.z * dvz);
                FP tangentImpulse    = massTangent * relTangentVel;
                FP maxTangentImpulse = -staticFriction * accumulatedNormalImpulse;

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

            TSVector 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.
            // modified by tiger, uncommmented.
            //if (relNormalVel < -FP.One && newContact)
            //{
            //    restitutionBias = TSMath.Max(-restitution * relNormalVel, restitutionBias);
            //}

            // added by seok
            //if (!newContact)

            if (!newContact || TSMath.Abs(relNormalVel *= restitution) < restitution)
            {
                relNormalVel = 0;
            }

            restitutionBias = TSMath.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.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)
                {
                    FP 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;

                    FP num3 =
                        (((num0 * body1.invInertiaWorld.M11) +
                          (num1 * body1.invInertiaWorld.M21)) +
                         (num2 * body1.invInertiaWorld.M31));
                    FP num4 =
                        (((num0 * body1.invInertiaWorld.M12) +
                          (num1 * body1.invInertiaWorld.M22)) +
                         (num2 * body1.invInertiaWorld.M32));
                    FP 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)
                {
                    FP 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;

                    FP num3 =
                        (((num0 * body2.invInertiaWorld.M11) +
                          (num1 * body2.invInertiaWorld.M21)) +
                         (num2 * body2.invInertiaWorld.M31));
                    FP num4 =
                        (((num0 * body2.invInertiaWorld.M12) +
                          (num1 * body2.invInertiaWorld.M22)) +
                         (num2 * body2.invInertiaWorld.M32));
                    FP 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;
        }
        /// <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)
        {
            TSVector dv      = CalculateRelativeVelocity();
            FP       kNormal = FP.Zero;

            TSVector rantra = TSVector.zero;

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

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

            TSVector rbntrb = TSVector.zero;

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

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

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

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

            massNormal = FP.One / kNormal;

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

            FP kTangent = FP.Zero;

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

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

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

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

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

            massTangent = FP.One / kTangent;

            restitutionBias = lostSpeculativeBounce;

            speculativeVelocity = FP.Zero;

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

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


            FP timeStepRatio = timestep / lastTimeStep;

            accumulatedNormalImpulse  *= timeStepRatio;
            accumulatedTangentImpulse *= timeStepRatio;

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

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

            TSVector 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 = TSMath.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.
            // 如果穿透是负的(这意味着物体还没有接触,但是它们将来会接触),
            // 我们将当前弹跳偏置存储在变量“lostSpeculativeBounce”中,并在下一个框架中应用它,此时投机接触已经解决。
            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;
        }
Example #25
0
        /// <summary>
        /// Hull making.
        /// </summary>
        /// <remarks>Based/Completely from http://www.xbdev.net/physics/MinkowskiDifference/index.php
        /// I don't (100%) see why this should always work.
        /// </remarks>
        /// <param name="triangleList"></param>
        /// <param name="generationThreshold"></param>
        public virtual void MakeHull(ref List <TSVector> triangleList, int generationThreshold)
        {
            FP distanceThreshold = FP.Zero;

            if (generationThreshold < 0)
            {
                generationThreshold = 4;
            }

            Stack <ClipTriangle> activeTriList = new Stack <ClipTriangle>();

            TSVector[] v = new TSVector[] // 6 Array
            {
                new TSVector(-1, 0, 0),
                new TSVector(1, 0, 0),

                new TSVector(0, -1, 0),
                new TSVector(0, 1, 0),

                new TSVector(0, 0, -1),
                new TSVector(0, 0, 1),
            };

            int[,] kTriangleVerts = new int[8, 3] // 8 x 3 Array
            {
                { 5, 1, 3 },
                { 4, 3, 1 },
                { 3, 4, 0 },
                { 0, 5, 3 },

                { 5, 2, 1 },
                { 4, 1, 2 },
                { 2, 0, 4 },
                { 0, 2, 5 }
            };

            for (int i = 0; i < 8; i++)
            {
                ClipTriangle tri = new ClipTriangle();
                tri.n1         = v[kTriangleVerts[i, 0]];
                tri.n2         = v[kTriangleVerts[i, 1]];
                tri.n3         = v[kTriangleVerts[i, 2]];
                tri.generation = 0;
                activeTriList.Push(tri);
            }

            // surfaceTriList
            while (activeTriList.Count > 0)
            {
                ClipTriangle tri = activeTriList.Pop();

                TSVector p1; SupportMapping(ref tri.n1, out p1);
                TSVector p2; SupportMapping(ref tri.n2, out p2);
                TSVector p3; SupportMapping(ref tri.n3, out p3);

                FP d1 = (p2 - p1).sqrMagnitude;
                FP d2 = (p3 - p2).sqrMagnitude;
                FP d3 = (p1 - p3).sqrMagnitude;

                if (TSMath.Max(TSMath.Max(d1, d2), d3) > distanceThreshold && tri.generation < generationThreshold)
                {
                    ClipTriangle tri1 = new ClipTriangle();
                    ClipTriangle tri2 = new ClipTriangle();
                    ClipTriangle tri3 = new ClipTriangle();
                    ClipTriangle tri4 = new ClipTriangle();

                    tri1.generation = tri.generation + 1;
                    tri2.generation = tri.generation + 1;
                    tri3.generation = tri.generation + 1;
                    tri4.generation = tri.generation + 1;

                    tri1.n1 = tri.n1;
                    tri2.n2 = tri.n2;
                    tri3.n3 = tri.n3;

                    TSVector n = FP.Half * (tri.n1 + tri.n2);
                    n.Normalize();

                    tri1.n2 = n;
                    tri2.n1 = n;
                    tri4.n3 = n;

                    n = FP.Half * (tri.n2 + tri.n3);
                    n.Normalize();

                    tri2.n3 = n;
                    tri3.n2 = n;
                    tri4.n1 = n;

                    n = FP.Half * (tri.n3 + tri.n1);
                    n.Normalize();

                    tri1.n3 = n;
                    tri3.n1 = n;
                    tri4.n2 = n;

                    activeTriList.Push(tri1);
                    activeTriList.Push(tri2);
                    activeTriList.Push(tri3);
                    activeTriList.Push(tri4);
                }
                else
                {
                    if (((p3 - p1) % (p2 - p1)).sqrMagnitude > TSMath.Epsilon)
                    {
                        triangleList.Add(p1);
                        triangleList.Add(p2);
                        triangleList.Add(p3);
                    }
                }
            }
        }
Example #26
0
 public void SolveVelocityConstraints()
 {
     for (int i = 0; i < this._count; i++)
     {
         ContactVelocityConstraint contactVelocityConstraint = this._velocityConstraints[i];
         int       indexA     = contactVelocityConstraint.indexA;
         int       indexB     = contactVelocityConstraint.indexB;
         FP        invMassA   = contactVelocityConstraint.invMassA;
         FP        invIA      = contactVelocityConstraint.invIA;
         FP        invMassB   = contactVelocityConstraint.invMassB;
         FP        invIB      = contactVelocityConstraint.invIB;
         int       pointCount = contactVelocityConstraint.pointCount;
         TSVector2 tSVector   = this._velocities[indexA].v;
         FP        fP         = this._velocities[indexA].w;
         TSVector2 tSVector2  = this._velocities[indexB].v;
         FP        fP2        = this._velocities[indexB].w;
         TSVector2 normal     = contactVelocityConstraint.normal;
         TSVector2 tSVector3  = MathUtils.Cross(normal, 1f);
         FP        friction   = contactVelocityConstraint.friction;
         Debug.Assert(pointCount == 1 || pointCount == 2);
         for (int j = 0; j < pointCount; j++)
         {
             VelocityConstraintPoint velocityConstraintPoint = contactVelocityConstraint.points[j];
             TSVector2 value = tSVector2 + MathUtils.Cross(fP2, velocityConstraintPoint.rB) - tSVector - MathUtils.Cross(fP, velocityConstraintPoint.rA);
             FP        x     = TSVector2.Dot(value, tSVector3) - contactVelocityConstraint.tangentSpeed;
             FP        fP3   = velocityConstraintPoint.tangentMass * -x;
             FP        fP4   = friction * velocityConstraintPoint.normalImpulse;
             FP        fP5   = MathUtils.Clamp(velocityConstraintPoint.tangentImpulse + fP3, -fP4, fP4);
             fP3 = fP5 - velocityConstraintPoint.tangentImpulse;
             velocityConstraintPoint.tangentImpulse = fP5;
             TSVector2 tSVector4 = fP3 * tSVector3;
             tSVector  -= invMassA * tSVector4;
             fP        -= invIA * MathUtils.Cross(velocityConstraintPoint.rA, tSVector4);
             tSVector2 += invMassB * tSVector4;
             fP2       += invIB * MathUtils.Cross(velocityConstraintPoint.rB, tSVector4);
         }
         bool flag = contactVelocityConstraint.pointCount == 1;
         if (flag)
         {
             VelocityConstraintPoint velocityConstraintPoint2 = contactVelocityConstraint.points[0];
             TSVector2 value2 = tSVector2 + MathUtils.Cross(fP2, velocityConstraintPoint2.rB) - tSVector - MathUtils.Cross(fP, velocityConstraintPoint2.rA);
             FP        x2     = TSVector2.Dot(value2, normal);
             FP        fP6    = -velocityConstraintPoint2.normalMass * (x2 - velocityConstraintPoint2.velocityBias);
             FP        fP7    = TSMath.Max(velocityConstraintPoint2.normalImpulse + fP6, 0f);
             fP6 = fP7 - velocityConstraintPoint2.normalImpulse;
             velocityConstraintPoint2.normalImpulse = fP7;
             TSVector2 tSVector5 = fP6 * normal;
             tSVector  -= invMassA * tSVector5;
             fP        -= invIA * MathUtils.Cross(velocityConstraintPoint2.rA, tSVector5);
             tSVector2 += invMassB * tSVector5;
             fP2       += invIB * MathUtils.Cross(velocityConstraintPoint2.rB, tSVector5);
         }
         else
         {
             VelocityConstraintPoint velocityConstraintPoint3 = contactVelocityConstraint.points[0];
             VelocityConstraintPoint velocityConstraintPoint4 = contactVelocityConstraint.points[1];
             TSVector2 tSVector6 = new TSVector2(velocityConstraintPoint3.normalImpulse, velocityConstraintPoint4.normalImpulse);
             Debug.Assert(tSVector6.x >= 0f && tSVector6.y >= 0f);
             TSVector2 value3    = tSVector2 + MathUtils.Cross(fP2, velocityConstraintPoint3.rB) - tSVector - MathUtils.Cross(fP, velocityConstraintPoint3.rA);
             TSVector2 value4    = tSVector2 + MathUtils.Cross(fP2, velocityConstraintPoint4.rB) - tSVector - MathUtils.Cross(fP, velocityConstraintPoint4.rA);
             FP        x3        = TSVector2.Dot(value3, normal);
             FP        x4        = TSVector2.Dot(value4, normal);
             TSVector2 tSVector7 = new TSVector2
             {
                 x = x3 - velocityConstraintPoint3.velocityBias,
                 y = x4 - velocityConstraintPoint4.velocityBias
             } -MathUtils.Mul(ref contactVelocityConstraint.K, tSVector6);
             TSVector2 tSVector8 = -MathUtils.Mul(ref contactVelocityConstraint.normalMass, tSVector7);
             bool      flag2     = tSVector8.x >= 0f && tSVector8.y >= 0f;
             if (flag2)
             {
                 TSVector2 tSVector9  = tSVector8 - tSVector6;
                 TSVector2 tSVector10 = tSVector9.x * normal;
                 TSVector2 tSVector11 = tSVector9.y * normal;
                 tSVector  -= invMassA * (tSVector10 + tSVector11);
                 fP        -= invIA * (MathUtils.Cross(velocityConstraintPoint3.rA, tSVector10) + MathUtils.Cross(velocityConstraintPoint4.rA, tSVector11));
                 tSVector2 += invMassB * (tSVector10 + tSVector11);
                 fP2       += invIB * (MathUtils.Cross(velocityConstraintPoint3.rB, tSVector10) + MathUtils.Cross(velocityConstraintPoint4.rB, tSVector11));
                 velocityConstraintPoint3.normalImpulse = tSVector8.x;
                 velocityConstraintPoint4.normalImpulse = tSVector8.y;
             }
             else
             {
                 tSVector8.x = -velocityConstraintPoint3.normalMass * tSVector7.x;
                 tSVector8.y = 0f;
                 x3          = 0f;
                 x4          = contactVelocityConstraint.K.ex.y * tSVector8.x + tSVector7.y;
                 bool flag3 = tSVector8.x >= 0f && x4 >= 0f;
                 if (flag3)
                 {
                     TSVector2 tSVector12 = tSVector8 - tSVector6;
                     TSVector2 tSVector13 = tSVector12.x * normal;
                     TSVector2 tSVector14 = tSVector12.y * normal;
                     tSVector  -= invMassA * (tSVector13 + tSVector14);
                     fP        -= invIA * (MathUtils.Cross(velocityConstraintPoint3.rA, tSVector13) + MathUtils.Cross(velocityConstraintPoint4.rA, tSVector14));
                     tSVector2 += invMassB * (tSVector13 + tSVector14);
                     fP2       += invIB * (MathUtils.Cross(velocityConstraintPoint3.rB, tSVector13) + MathUtils.Cross(velocityConstraintPoint4.rB, tSVector14));
                     velocityConstraintPoint3.normalImpulse = tSVector8.x;
                     velocityConstraintPoint4.normalImpulse = tSVector8.y;
                 }
                 else
                 {
                     tSVector8.x = 0f;
                     tSVector8.y = -velocityConstraintPoint4.normalMass * tSVector7.y;
                     x3          = contactVelocityConstraint.K.ey.x * tSVector8.y + tSVector7.x;
                     x4          = 0f;
                     bool flag4 = tSVector8.y >= 0f && x3 >= 0f;
                     if (flag4)
                     {
                         TSVector2 tSVector15 = tSVector8 - tSVector6;
                         TSVector2 tSVector16 = tSVector15.x * normal;
                         TSVector2 tSVector17 = tSVector15.y * normal;
                         tSVector  -= invMassA * (tSVector16 + tSVector17);
                         fP        -= invIA * (MathUtils.Cross(velocityConstraintPoint3.rA, tSVector16) + MathUtils.Cross(velocityConstraintPoint4.rA, tSVector17));
                         tSVector2 += invMassB * (tSVector16 + tSVector17);
                         fP2       += invIB * (MathUtils.Cross(velocityConstraintPoint3.rB, tSVector16) + MathUtils.Cross(velocityConstraintPoint4.rB, tSVector17));
                         velocityConstraintPoint3.normalImpulse = tSVector8.x;
                         velocityConstraintPoint4.normalImpulse = tSVector8.y;
                     }
                     else
                     {
                         tSVector8.x = 0f;
                         tSVector8.y = 0f;
                         x3          = tSVector7.x;
                         x4          = tSVector7.y;
                         bool flag5 = x3 >= 0f && x4 >= 0f;
                         if (flag5)
                         {
                             TSVector2 tSVector18 = tSVector8 - tSVector6;
                             TSVector2 tSVector19 = tSVector18.x * normal;
                             TSVector2 tSVector20 = tSVector18.y * normal;
                             tSVector  -= invMassA * (tSVector19 + tSVector20);
                             fP        -= invIA * (MathUtils.Cross(velocityConstraintPoint3.rA, tSVector19) + MathUtils.Cross(velocityConstraintPoint4.rA, tSVector20));
                             tSVector2 += invMassB * (tSVector19 + tSVector20);
                             fP2       += invIB * (MathUtils.Cross(velocityConstraintPoint3.rB, tSVector19) + MathUtils.Cross(velocityConstraintPoint4.rB, tSVector20));
                             velocityConstraintPoint3.normalImpulse = tSVector8.x;
                             velocityConstraintPoint4.normalImpulse = tSVector8.y;
                         }
                     }
                 }
             }
         }
         this._velocities[indexA].v = tSVector;
         this._velocities[indexA].w = fP;
         this._velocities[indexB].v = tSVector2;
         this._velocities[indexB].w = fP2;
     }
 }
Example #27
0
        /// <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)
        {
            var dv = CalculateRelativeVelocity();

            var kn = CalcK(body1, relativePos1, normal) +
                     CalcK(body2, relativePos2, normal);

            massNormal = FP.One / kn;

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


            var kt = CalcK(body1, relativePos1, tangent) +
                     CalcK(body2, relativePos2, tangent);

            massTangent = FP.One / kt;

            restitutionBias = lostSpeculativeBounce;

            speculativeVelocity = FP.Zero;

            FP relNormalVel = TSVector.Dot(normal, dv);

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


            FP timeStepRatio = timestep / lastTimeStep;

            accumulatedNormalImpulse  *= timeStepRatio;
            accumulatedTangentImpulse *= timeStepRatio;

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

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

            // 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 = TSMath.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;
            }

            var impulse = normal * accumulatedNormalImpulse + tangent * accumulatedTangentImpulse;

            ApplyImpulse(impulse);

            lastTimeStep = timestep;

            newContact = false;
        }
Example #28
0
        public void Insert(T T)
        {
            int      i = 0;
            QTBound  r = bounds;
            TSVector p = T.position;

            T.next = null;

            maxRadius = TSMath.Max(T.neighbourRadius, maxRadius);

            int      depth = 0;
            TSVector min   = TSVector.zero;
            TSVector max   = TSVector.zero;

            while (true)
            {
                depth++;

                if (nodes[i].childNode1 == i)
                {
                    // Leaf node.
                    if (nodes[i].count < LeafSize || depth > 10)
                    {
                        nodes[i].Add(T);
                        //  nodes[i].count++;
                        break;
                    }
                    else
                    {
                        // Split
                        QTNode node = nodes[i];
                        node.childNode1 = GetNodeIndex();
                        node.childNode2 = GetNodeIndex();
                        node.childNode3 = GetNodeIndex();
                        node.childNode4 = GetNodeIndex();
                        nodes[i]        = node;

                        nodes[i].Distribute(nodes, r);
                    }
                }
                // Note, no else
                if (nodes[i].childNode1 != i)
                {
                    // Not a leaf node
                    TSVector c = r.center;
                    if (p.x > c.x)
                    {
                        if (p.z > c.z)
                        {
                            i = nodes[i].childNode4;
                            r = QTBound.MinMaxQTBound(c, r.max);
                        }
                        else
                        {
                            i = nodes[i].childNode3;
                            min.Set(c.x, 0, r.min.z);
                            max.Set(r.max.x, 0, c.z);
                            r = QTBound.MinMaxQTBound(min, max);
                        }
                    }
                    else
                    {
                        if (p.z > c.z)
                        {
                            i = nodes[i].childNode2;
                            min.Set(r.min.x, 0, c.z);
                            max.Set(c.x, 0, r.max.z);
                            r = QTBound.MinMaxQTBound(min, max);
                        }
                        else
                        {
                            i = nodes[i].childNode1;
                            r = QTBound.MinMaxQTBound(r.min, c);
                        }
                    }
                }
            }
        }
Example #29
0
            /** Creates a VO for avoiding another agent.
             * Note that the segment is directed, the agent will want to be on the left side of the segment.
             */
            public static VO SegmentObstacle(TSVector2 segmentStart, TSVector2 segmentEnd, TSVector2 offset, FP radius, FP inverseDt, FP inverseDeltaTime)
            {
                var vo = new VO();

                // Adjusted so that a parameter weightFactor of 1 will be the default ("natural") weight factor
                vo.weightFactor = 1;
                // Just higher than anything else
                vo.weightBonus = TSMath.Max(radius, 1) * 40;

                var closestOnSegment = CustomMath.ClosestPointOnSegment(segmentStart, segmentEnd, TSVector2.zero);

                // Collision?
                if (closestOnSegment.magnitude <= radius)
                {
                    vo.colliding = true;

                    vo.line1  = closestOnSegment.normalized * (closestOnSegment.magnitude - radius) * 3 / 10 * inverseDeltaTime;
                    vo.dir1   = new TSVector2(vo.line1.y, -vo.line1.x).normalized;
                    vo.line1 += offset;

                    vo.cutoffDir  = TSVector2.zero;
                    vo.cutoffLine = TSVector2.zero;
                    vo.dir2       = TSVector2.zero;
                    vo.line2      = TSVector2.zero;
                    vo.radius     = 0;

                    vo.segmentStart = TSVector2.zero;
                    vo.segmentEnd   = TSVector2.zero;
                    vo.segment      = false;
                }
                else
                {
                    vo.colliding = false;

                    segmentStart *= inverseDt;
                    segmentEnd   *= inverseDt;
                    radius       *= inverseDt;

                    var cutoffTangent = (segmentEnd - segmentStart).normalized;
                    vo.cutoffDir   = cutoffTangent;
                    vo.cutoffLine  = segmentStart + new TSVector2(-cutoffTangent.y, cutoffTangent.x) * radius;
                    vo.cutoffLine += offset;

                    // See documentation for details
                    // The call to Max is just to prevent floating point errors causing NaNs to appear
                    var startSqrMagnitude = segmentStart.LengthSquared();
                    var normal1           = -ComplexMultiply(segmentStart, new TSVector2(radius, TSMath.Sqrt(TSMath.Max(0, startSqrMagnitude - radius * radius)))) / startSqrMagnitude;
                    var endSqrMagnitude   = segmentEnd.LengthSquared();
                    var normal2           = -ComplexMultiply(segmentEnd, new TSVector2(radius, -TSMath.Sqrt(TSMath.Max(0, endSqrMagnitude - radius * radius)))) / endSqrMagnitude;

                    vo.line1 = segmentStart + normal1 * radius + offset;
                    vo.line2 = segmentEnd + normal2 * radius + offset;

                    // Note that the normals are already normalized
                    vo.dir1 = new TSVector2(normal1.y, -normal1.x);
                    vo.dir2 = new TSVector2(normal2.y, -normal2.x);

                    vo.segmentStart = segmentStart;
                    vo.segmentEnd   = segmentEnd;
                    vo.radius       = radius;
                    vo.segment      = true;
                }

                return(vo);
            }
Example #30
0
        //void GenerateObstacleVOs(VOBuffer vos)
        //{
        //    var range = maxSpeed * obstacleTimeHorizon;

        //    // Iterate through all obstacles that we might need to avoid
        //    for (int i = 0; i < simulator.obstacles.Count; i++)
        //    {
        //        var obstacle = simulator.obstacles[i];
        //        var vertex = obstacle;
        //        // Iterate through all edges (defined by vertex and vertex.dir) in the obstacle
        //        do
        //        {
        //            // Ignore the edge if the agent should not collide with it
        //            if (vertex.ignore || (vertex.layer & collidesWith) == 0)
        //            {
        //                vertex = vertex.next;
        //                continue;
        //            }

        //            // Start and end points of the current segment
        //            FP elevation1, elevation2;
        //            var p1 = To2D(vertex.position, out elevation1);
        //            var p2 = To2D(vertex.next.position, out elevation2);

        //            TSVector2 dir = (p2 - p1).normalized;

        //            // Signed distance from the line (not segment, lines are infinite)
        //            // TODO: Can be optimized
        //            FP dist = VO.SignedDistanceFromLine(p1, dir, position);

        //            if (dist >= -FP.One/100 && dist < range)
        //            {
        //                FP factorAlongSegment = TSVector2.Dot(position - p1, p2 - p1) / (p2 - p1).sqrMagnitude;

        //                // Calculate the elevation (y) coordinate of the point on the segment closest to the agent
        //                var segmentY = TSMath.Lerp(elevation1, elevation2, factorAlongSegment);

        //                // Calculate distance from the segment (not line)
        //                var sqrDistToSegment = (TSVector2.Lerp(p1, p2, factorAlongSegment) - position).sqrMagnitude;

        //                // Ignore the segment if it is too far away
        //                // or the agent is too high up (or too far down) on the elevation axis (usually y axis) to avoid it.
        //                // If the XY plane is used then all elevation checks are disabled
        //                if (sqrDistToSegment < range * range && (simulator.movementPlane == MovementPlane.XY || (elevationCoordinate <= segmentY + vertex.height && elevationCoordinate + height >= segmentY)))
        //                {
        //                    vos.Add(VO.SegmentObstacle(p2 - position, p1 - position, TSVector2.zero, radius * FP.One/100, 1 / ObstacleTimeHorizon, 1 / simulator.DeltaTime));
        //                }
        //            }

        //            vertex = vertex.next;
        //        } while (vertex != obstacle && vertex != null && vertex.next != null);
        //    }
        //}
#if  USING_RVO
        void GenerateNeighbourAgentVOs(VOBuffer vos, FP deltaTime)
        {
            FP inverseAgentTimeHorizon = 1 / agentTimeHorizon;

            // The RVO algorithm assumes we will continue to
            // move in roughly the same direction
            TSVector2 optimalVelocity = currentVelocity;
            int       count           = _behaviour.neighbours.Count;

            for (int o = 0; o < count; o++)
            {
                IAgentBehaviour other = _behaviour.neighbours[o];

                // Don't avoid ourselves
                if (other == this)
                {
                    continue;
                }

                // Interval along the y axis in which the agents overlap
                FP maxY = TSMath.Min(elevationCoordinate + height, other.OrcaAgent.elevationCoordinate + other.OrcaAgent.height);
                FP minY = TSMath.Max(elevationCoordinate, other.OrcaAgent.elevationCoordinate);

                // The agents cannot collide since they are on different y-levels
                if (maxY - minY < 0)
                {
                    continue;
                }

                FP totalRadius = radius + other.colliderRadius;

                // Describes a circle on the border of the VO
                TSVector2 voBoundingOrigin = CustomMath.TSVecToVec2(other.position - _behaviour.position);

                FP avoidanceStrength;
                if (other.OrcaAgent.locked || other.OrcaAgent.manuallyControlled)
                {
                    avoidanceStrength = 1;
                }
                else if (other.OrcaAgent.Priority > CustomMath.EPSILON || Priority > CustomMath.EPSILON)
                {
                    avoidanceStrength = other.OrcaAgent.Priority / (Priority + other.OrcaAgent.Priority);
                }
                else
                {
                    // Both this agent's priority and the other agent's priority is zero or negative
                    // Assume they have the same priority
                    avoidanceStrength = CustomMath.FPHalf;
                }

                // We assume that the other agent will continue to move with roughly the same velocity if the priorities for the agents are similar.
                // If the other agent has a higher priority than this agent (avoidanceStrength > 0.5) then we will assume it will move more along its
                // desired velocity. This will have the effect of other agents trying to clear a path for where a high priority agent wants to go.
                // If this is not done then even high priority agents can get stuck when it is really crowded and they have had to slow down.
                TSVector2 otherOptimalVelocity = TSVector2.Lerp(other.OrcaAgent.currentVelocity, other.OrcaAgent.desiredVelocity, 2 * avoidanceStrength - 1);

                var voCenter = TSVector2.Lerp(optimalVelocity, otherOptimalVelocity, avoidanceStrength);

                vos.Add(new VO(voBoundingOrigin, voCenter, totalRadius, inverseAgentTimeHorizon, 1 / deltaTime));
                if (DebugDraw)
                {
                    DrawVO(position + voBoundingOrigin * inverseAgentTimeHorizon + voCenter, totalRadius * inverseAgentTimeHorizon, position + voCenter);
                }
            }
        }