Пример #1
0
        /// <summary>
        /// Set the mass properties to override the mass properties of the fixtures. Note that this changes
        /// the center of mass position. Note that creating or destroying fixtures can also alter the mass.
        /// This function has no effect if the body isn't dynamic.
        /// </summary>
        /// <param name="massData">the mass properties.</param>
        public void SetMassData(MassData massData)
        {
            // TODO_ERIN adjust linear velocity and torque to account for movement of center.
            Debug.Assert(World.Locked == false);
            if (World.Locked)
            {
                return;
            }

            if (m_type != BodyType.Dynamic)
            {
                return;
            }

            InvMass = 0.0f;
            I       = 0.0f;
            InvI    = 0.0f;

            Mass = massData.Mass;
            if (Mass <= 0.0f)
            {
                Mass = 1f;
            }

            InvMass = 1.0f / Mass;

            if (massData.I > 0.0f && (Flags & TypeFlags.FixedRotation) == 0)
            {
                I = massData.I - Mass * Vec2.Dot(massData.Center, massData.Center);
                Debug.Assert(I > 0.0f);
                InvI = 1.0f / I;
            }

            Vec2 oldCenter = World.Pool.PopVec2();

            // Move center of mass.
            oldCenter.Set(Sweep.C);
            Sweep.LocalCenter.Set(massData.Center);
            // m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
            Transform.MulToOutUnsafe(Xf, Sweep.LocalCenter, Sweep.C0);
            Sweep.C.Set(Sweep.C0);

            // Update center of mass velocity.
            // m_linearVelocity += Cross(m_angularVelocity, m_sweep.c - oldCenter);
            Vec2 temp = World.Pool.PopVec2();

            temp.Set(Sweep.C).SubLocal(oldCenter);
            Vec2.CrossToOut(m_angularVelocity, temp, temp);
            m_linearVelocity.AddLocal(temp);

            World.Pool.PushVec2(2);
        }
Пример #2
0
        public override bool TestPoint(Transform transform, Vec2 p)
        {
            Vec2 center = pool1;

            Rot.MulToOutUnsafe(transform.Q, P, center);
            center.AddLocal(transform.P);

            Vec2 d = center.SubLocal(p).NegateLocal();

            return(Vec2.Dot(d, d) <= Radius * Radius);
        }
Пример #3
0
 public void GetWorldToScreen(Vec2 argWorld, Vec2 argScreen)
 {
     argScreen.Set(argWorld);
     argScreen.SubLocal(Box.Center);
     Box.R.MulToOut(argScreen, argScreen);
     if (YFlip)
     {
         yFlipMat.MulToOut(argScreen, argScreen);
     }
     argScreen.AddLocal(Box.Extents);
 }
Пример #4
0
        public override void ComputeAABB(AABB aabb, Transform transform, int childIndex)
        {
            Vec2 p = pool1;

            Rot.MulToOutUnsafe(transform.Q, P, p);
            p.AddLocal(transform.P);

            aabb.LowerBound.X = p.X - Radius;
            aabb.LowerBound.Y = p.Y - Radius;
            aabb.UpperBound.X = p.X + Radius;
            aabb.UpperBound.Y = p.Y + Radius;
        }
Пример #5
0
 public void GetScreenToWorld(Vec2 argScreen, Vec2 argWorld)
 {
     argWorld.Set(argScreen);
     argWorld.SubLocal(Box.Extents);
     Box.R.InvertToOut(inv2);
     inv2.MulToOut(argWorld, argWorld);
     if (YFlip)
     {
         yFlipMatInv.MulToOut(argWorld, argWorld);
     }
     argWorld.AddLocal(Box.Center);
 }
Пример #6
0
        public void WarmStart()
        {
            // Warm start.
            for (int i = 0; i < Count; ++i)
            {
                ContactVelocityConstraint vc = VelocityConstraints[i];

                int   indexA     = vc.IndexA;
                int   indexB     = vc.IndexB;
                float mA         = vc.InvMassA;
                float iA         = vc.InvIA;
                float mB         = vc.InvMassB;
                float iB         = vc.InvIB;
                int   pointCount = vc.PointCount;


                Vec2  vA = Velocities[indexA].V;
                float wA = Velocities[indexA].W;
                Vec2  vB = Velocities[indexB].V;
                float wB = Velocities[indexB].W;

                Vec2 normal = vc.Normal;
                Vec2.CrossToOutUnsafe(normal, 1.0f, tangent);

                for (int j = 0; j < pointCount; ++j)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp = vc.Points[j];
                    //Console.WriteLine("vcp normal impulse is " + vcp.normalImpulse);
                    temp.Set(normal).MulLocal(vcp.NormalImpulse);
                    P.Set(tangent).MulLocal(vcp.TangentImpulse).AddLocal(temp);
                    wA -= iA * Vec2.Cross(vcp.RA, P);
                    vA.SubLocal(temp.Set(P).MulLocal(mA));
                    //Debug.Assert(vA.x == 0);
                    //Debug.Assert(wA == 0);
                    wB += iB * Vec2.Cross(vcp.RB, P);
                    vB.AddLocal(temp.Set(P).MulLocal(mB));
                    //Debug.Assert(vB.x == 0);
                    //Debug.Assert(wB == 0);
                }
                Velocities[indexA].W = wA;
                Velocities[indexB].W = wB;

                //Console.WriteLine("Ending velocity for " + indexA + " is " + vA.x + "," + vA.y + " - " + wA);
                //Console.WriteLine("Ending velocity for " + indexB + " is " + vB.x + "," + vB.y + " - " + wB);
            }
        }
Пример #7
0
        public void ComputeCentroidToOut(Vec2[] vs, int count, Vec2 result)
        {
            Debug.Assert(count >= 3);

            result.Set(0.0f, 0.0f);
            float area = 0.0f;

            // pRef is the reference point for forming triangles.
            // It's location doesn't change the result (except for rounding error).
            Vec2 pRef = pool1;

            pRef.SetZero();

            Vec2 e1 = pool2;
            Vec2 e2 = pool3;

            const float inv3 = 1.0f / 3.0f;

            for (int i = 0; i < count; ++i)
            {
                // Triangle vertices.
                Vec2 p1 = pRef;
                Vec2 p2 = vs[i];
                Vec2 p3 = i + 1 < count ? vs[i + 1] : vs[0];

                e1.Set(p2).SubLocal(p1);
                e2.Set(p3).SubLocal(p1);

                float D = Vec2.Cross(e1, e2);

                float triangleArea = 0.5f * D;
                area += triangleArea;

                // Area weighted centroid
                e1.Set(p1).AddLocal(p2).AddLocal(p3).MulLocal(triangleArea * inv3);
                result.AddLocal(e1);
            }

            // Centroid
            Debug.Assert(area > Settings.EPSILON);
            result.MulLocal(1.0f / area);
        }
Пример #8
0
            public void GetWitnessPoints(Vec2 pA, Vec2 pB)
            {
                switch (Count)
                {
                case 0:
                    Debug.Assert(false);
                    break;


                case 1:
                    pA.Set(m_v1.WA);
                    pB.Set(m_v1.WB);
                    break;


                case 2:
                    case2.Set(m_v1.WA).MulLocal(m_v1.A);
                    pA.Set(m_v2.WA).MulLocal(m_v2.A).AddLocal(case2);
                    // m_v1.a * m_v1.wA + m_v2.a * m_v2.wA;
                    // *pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB;
                    case2.Set(m_v1.WB).MulLocal(m_v1.A);
                    pB.Set(m_v2.WB).MulLocal(m_v2.A).AddLocal(case2);

                    break;


                case 3:
                    pA.Set(m_v1.WA).MulLocal(m_v1.A);
                    case3.Set(m_v2.WA).MulLocal(m_v2.A);
                    case33.Set(m_v3.WA).MulLocal(m_v3.A);
                    pA.AddLocal(case3).AddLocal(case33);
                    pB.Set(pA);
                    // *pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;
                    // *pB = *pA;
                    break;


                default:
                    Debug.Assert(false);
                    break;
                }
            }
Пример #9
0
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

            Vec2 vpA = Pool.PopVec2();
            Vec2 vpB = Pool.PopVec2();

            // Cdot = dot(u, v + cross(w, r))
            Vec2.CrossToOutUnsafe(wA, RA, vpA);
            vpA.AddLocal(vA);
            Vec2.CrossToOutUnsafe(wB, RB, vpB);
            vpB.AddLocal(vB);
            float Cdot = Vec2.Dot(U, vpB.SubLocal(vpA));

            float impulse = (-Mass) * (Cdot + Bias + Gamma * Impulse);

            Impulse += impulse;


            float Px = impulse * U.X;
            float Py = impulse * U.Y;

            vA.X -= InvMassA * Px;
            vA.Y -= InvMassA * Py;
            wA   -= InvIA * (RA.X * Py - RA.Y * Px);
            vB.X += InvMassB * Px;
            vB.Y += InvMassB * Py;
            wB   += InvIB * (RB.X * Py - RB.Y * Px);

            data.Velocities[IndexA].V.Set(vA);
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushVec2(2);
        }
Пример #10
0
        // Collision Detection in Interactive 3D Environments by Gino van den Bergen
        // From Section 3.1.2
        // x = s + a * r
        // norm(x) = radius
        public override bool Raycast(RayCastOutput output, RayCastInput input, Transform transform, int childIndex)
        {
            Vec2 position = pool1;
            Vec2 s        = pool2;
            Vec2 r        = pool3;

            Rot.MulToOutUnsafe(transform.Q, P, position);
            position.AddLocal(transform.P);
            s.Set(input.P1).SubLocal(position);
            float b = Vec2.Dot(s, s) - Radius * Radius;

            // Solve quadratic equation.
            r.Set(input.P2).SubLocal(input.P1);
            float c     = Vec2.Dot(s, r);
            float rr    = Vec2.Dot(r, r);
            float sigma = c * c - rr * b;

            // Check for negative discriminant and short segment.
            if (sigma < 0.0f || rr < Settings.EPSILON)
            {
                return(false);
            }

            // Find the point of intersection of the line with the circle.
            float a = -(c + MathUtils.Sqrt(sigma));

            // Is the intersection point on the segment?
            if (0.0f <= a && a <= input.MaxFraction * rr)
            {
                a /= rr;
                output.Fraction = a;
                output.Normal.Set(r).MulLocal(a);
                output.Normal.AddLocal(s);
                output.Normal.Normalize();
                return(true);
            }

            return(false);
        }
Пример #11
0
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

            // Cdot = v + cross(w, r)
            Vec2 Cdot = Pool.PopVec2();

            Vec2.CrossToOutUnsafe(wB, RB, Cdot);
            Cdot.AddLocal(vB);

            Vec2 impulse = Pool.PopVec2();
            Vec2 temp    = Pool.PopVec2();

            temp.Set(m_impulse).MulLocal(m_gamma).AddLocal(m_C).AddLocal(Cdot).NegateLocal();
            Mat22.MulToOutUnsafe(m_mass, temp, impulse);

            Vec2 oldImpulse = temp;

            oldImpulse.Set(m_impulse);
            m_impulse.AddLocal(impulse);
            float maxImpulse = data.Step.Dt * m_maxForce;

            if (m_impulse.LengthSquared() > maxImpulse * maxImpulse)
            {
                m_impulse.MulLocal(maxImpulse / m_impulse.Length());
            }
            impulse.Set(m_impulse).SubLocal(oldImpulse);

            vB.X += InvMassB * m_impulse.X;
            vB.Y += InvMassB * m_impulse.Y;
            wB   += InvIB * Vec2.Cross(RB, impulse);

            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushVec2(3);
        }
Пример #12
0
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

            Vec2 vpA = Pool.PopVec2();
            Vec2 vpB = Pool.PopVec2();
            Vec2 PA  = Pool.PopVec2();
            Vec2 PB  = Pool.PopVec2();

            Vec2.CrossToOutUnsafe(wA, RA, vpA);
            vpA.AddLocal(vA);
            Vec2.CrossToOutUnsafe(wB, RB, vpB);
            vpB.AddLocal(vB);

            float Cdot    = -Vec2.Dot(m_uA, vpA) - m_ratio * Vec2.Dot(m_uB, vpB);
            float impulse = (-m_mass) * Cdot;

            m_impulse += impulse;

            PA.Set(m_uA).MulLocal(-impulse);
            PB.Set(m_uB).MulLocal((-m_ratio) * impulse);
            vA.X += InvMassA * PA.X;
            vA.Y += InvMassA * PA.Y;
            wA   += InvIA * Vec2.Cross(RA, PA);
            vB.X += InvMassB * PB.X;
            vB.Y += InvMassB * PB.Y;
            wB   += InvIB * Vec2.Cross(RB, PB);

            data.Velocities[IndexA].V.Set(vA);
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushVec2(4);
        }
Пример #13
0
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

            float mA = InvMassA, mB = InvMassB;
            float iA = InvIA, iB = InvIB;

            float h = data.Step.Dt;

            // Solve angular friction
            {
                float Cdot    = wB - wA;
                float impulse = (-AngularMass) * Cdot;

                float oldImpulse = m_angularImpulse;
                float maxImpulse = h * m_maxTorque;
                m_angularImpulse = MathUtils.Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
                impulse          = m_angularImpulse - oldImpulse;

                wA -= iA * impulse;
                wB += iB * impulse;
            }

            // Solve linear friction
            {
                Vec2 Cdot = Pool.PopVec2();
                Vec2 temp = Pool.PopVec2();

                Vec2.CrossToOutUnsafe(wA, RA, temp);
                Vec2.CrossToOutUnsafe(wB, RB, Cdot);
                Cdot.AddLocal(vB).SubLocal(vA).SubLocal(temp);

                Vec2 impulse = Pool.PopVec2();
                Mat22.MulToOutUnsafe(LinearMass, Cdot, impulse);
                impulse.NegateLocal();


                Vec2 oldImpulse = Pool.PopVec2();
                oldImpulse.Set(m_linearImpulse);
                m_linearImpulse.AddLocal(impulse);

                float maxImpulse = h * m_maxForce;

                if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
                {
                    m_linearImpulse.Normalize();
                    m_linearImpulse.MulLocal(maxImpulse);
                }

                impulse.Set(m_linearImpulse).SubLocal(oldImpulse);

                temp.Set(impulse).MulLocal(mA);
                vA.SubLocal(temp);
                wA -= iA * Vec2.Cross(RA, impulse);

                temp.Set(impulse).MulLocal(mB);
                vB.AddLocal(temp);
                wB += iB * Vec2.Cross(RB, impulse);
            }

            data.Velocities[IndexA].V.Set(vA);
            if (data.Velocities[IndexA].W != wA)
            {
                Debug.Assert(data.Velocities[IndexA].W != wA);
            }
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushVec2(4);
        }
Пример #14
0
        // Sequential position solver for position constraints.
        public bool SolveTOIPositionConstraints(int toiIndexA, int toiIndexB)
        {
            float minSeparation = 0.0f;

            for (int i = 0; i < Count; ++i)
            {
                ContactPositionConstraint pc = PositionConstraints[i];

                int  indexA       = pc.IndexA;
                int  indexB       = pc.IndexB;
                Vec2 localCenterA = pc.LocalCenterA;
                Vec2 localCenterB = pc.LocalCenterB;
                int  pointCount   = pc.PointCount;

                float mA = 0.0f;
                float iA = 0.0f;
                if (indexA == toiIndexA || indexA == toiIndexB)
                {
                    mA = pc.InvMassA;
                    iA = pc.InvIA;
                }

                float mB = pc.InvMassB;
                float iB = pc.InvIB;
                if (indexB == toiIndexA || indexB == toiIndexB)
                {
                    mB = pc.InvMassB;
                    iB = pc.InvIB;
                }

                Vec2  cA = Positions[indexA].C;
                float aA = Positions[indexA].A;

                Vec2  cB = Positions[indexB].C;
                float aB = Positions[indexB].A;

                // Solve normal constraints
                for (int j = 0; j < pointCount; ++j)
                {
                    xfA.Q.Set(aA);
                    xfB.Q.Set(aB);
                    Rot.MulToOutUnsafe(xfA.Q, localCenterA, xfA.P);
                    xfA.P.NegateLocal().AddLocal(cA);
                    Rot.MulToOutUnsafe(xfB.Q, localCenterB, xfB.P);
                    xfB.P.NegateLocal().AddLocal(cB);

                    PositionSolverManifold psm = psolver;
                    psm.Initialize(pc, xfA, xfB, j);
                    Vec2 normal = psm.Normal;

                    Vec2  point      = psm.Point;
                    float separation = psm.Separation;

                    rA.Set(point).SubLocal(cA);
                    rB.Set(point).SubLocal(cB);

                    // Track max constraint error.
                    minSeparation = MathUtils.Min(minSeparation, separation);

                    // Prevent large corrections and allow slop.
                    float C = MathUtils.Clamp(Settings.TOI_BAUGARTE * (separation + Settings.LINEAR_SLOP), -Settings.MAX_LINEAR_CORRECTION, 0.0f);

                    // Compute the effective mass.
                    float rnA = Vec2.Cross(rA, normal);
                    float rnB = Vec2.Cross(rB, normal);
                    float K   = mA + mB + iA * rnA * rnA + iB * rnB * rnB;

                    // Compute normal impulse
                    float impulse = K > 0.0f ? (-C) / K : 0.0f;

                    P.Set(normal).MulLocal(impulse);

                    cA.SubLocal(temp.Set(P).MulLocal(mA));
                    aA -= iA * Vec2.Cross(rA, P);

                    cB.AddLocal(temp.Set(P).MulLocal(mB));
                    aB += iB * Vec2.Cross(rB, P);
                }

                Positions[indexA].C.Set(cA);
                Positions[indexA].A = aA;

                Positions[indexB].C.Set(cB);
                Positions[indexB].A = aB;
            }

            // We can't expect minSpeparation >= -_linearSlop because we don't
            // push the separation above -_linearSlop.
            return(minSeparation >= (-1.5f) * Settings.LINEAR_SLOP);
        }
Пример #15
0
        public void SolveVelocityConstraints()
        {
            for (int i = 0; i < Count; ++i)
            {
                ContactVelocityConstraint vc = VelocityConstraints[i];

                int indexA = vc.IndexA;
                int indexB = vc.IndexB;

                float mA         = vc.InvMassA;
                float mB         = vc.InvMassB;
                float iA         = vc.InvIA;
                float iB         = vc.InvIB;
                int   pointCount = vc.PointCount;

                Vec2  vA = Velocities[indexA].V;
                float wA = Velocities[indexA].W;
                Vec2  vB = Velocities[indexB].V;
                float wB = Velocities[indexB].W;
                //Debug.Assert(wA == 0);
                //Debug.Assert(wB == 0);

                Vec2 normal = vc.Normal;
                //Vec2.crossToOutUnsafe(normal, 1f, tangent);
                tangent.X = 1.0f * vc.Normal.Y;
                tangent.Y = (-1.0f) * vc.Normal.X;
                float friction = vc.Friction;

                Debug.Assert(pointCount == 1 || pointCount == 2);

                // Solve tangent constraints
                for (int j = 0; j < pointCount; ++j)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp = vc.Points[j];
                    //Vec2.crossToOutUnsafe(wA, vcp.rA, temp);
                    //Vec2.crossToOutUnsafe(wB, vcp.rB, dv);
                    //dv.addLocal(vB).subLocal(vA).subLocal(temp);
                    Vec2 a = vcp.RA;

                    dv.X = (-wB) * vcp.RB.Y + vB.X - vA.X + wA * a.Y;
                    dv.Y = wB * vcp.RB.X + vB.Y - vA.Y - wA * a.X;

                    // Compute tangent force
                    float vt     = dv.X * tangent.X + dv.Y * tangent.Y - vc.TangentSpeed;
                    float lambda = vcp.TangentMass * (-vt);

                    // Clamp the accumulated force
                    float maxFriction = friction * vcp.NormalImpulse;
                    float newImpulse  = MathUtils.Clamp(vcp.TangentImpulse + lambda, -maxFriction, maxFriction);
                    lambda             = newImpulse - vcp.TangentImpulse;
                    vcp.TangentImpulse = newImpulse;

                    // Apply contact impulse
                    // Vec2 P = lambda * tangent;

                    float Px = tangent.X * lambda;
                    float Py = tangent.Y * lambda;

                    // vA -= invMassA * P;
                    vA.X -= Px * mA;
                    vA.Y -= Py * mA;
                    wA   -= iA * (vcp.RA.X * Py - vcp.RA.Y * Px);

                    // vB += invMassB * P;
                    vB.X += Px * mB;
                    vB.Y += Py * mB;
                    wB   += iB * (vcp.RB.X * Py - vcp.RB.Y * Px);

                    //Console.WriteLine("tangent solve velocity (point "+j+") for " + indexA + " is " + vA.x + "," + vA.y + " rot " + wA);
                    //Console.WriteLine("tangent solve velocity (point "+j+") for " + indexB + " is " + vB.x + "," + vB.y + " rot " + wB);
                }

                // Solve normal constraints
                if (vc.PointCount == 1)
                {
                    ContactVelocityConstraint.VelocityConstraintPoint vcp = vc.Points[0];
                    Vec2 a1 = vcp.RA;

                    // Relative velocity at contact
                    //Vec2 dv = vB + Cross(wB, vcp.rB) - vA - Cross(wA, vcp.rA);

                    //Vec2.crossToOut(wA, vcp.rA, temp1);
                    //Vec2.crossToOut(wB, vcp.rB, dv);
                    //dv.addLocal(vB).subLocal(vA).subLocal(temp1);

                    dv.X = (-wB) * vcp.RB.Y + vB.X - vA.X + wA * a1.Y;
                    dv.Y = wB * vcp.RB.X + vB.Y - vA.Y - wA * a1.X;

                    // Compute normal impulse
                    float vn     = dv.X * normal.X + dv.Y * normal.Y;
                    float lambda = (-vcp.NormalMass) * (vn - vcp.VelocityBias);

                    // Clamp the accumulated impulse
                    float a          = vcp.NormalImpulse + lambda;
                    float newImpulse = (a > 0.0f ? a : 0.0f);
                    lambda = newImpulse - vcp.NormalImpulse;
                    //Debug.Assert(newImpulse == 0);
                    vcp.NormalImpulse = newImpulse;

                    // Apply contact impulse
                    float Px = normal.X * lambda;
                    float Py = normal.Y * lambda;

                    // vA -= invMassA * P;
                    vA.X -= Px * mA;
                    vA.Y -= Py * mA;
                    wA   -= iA * (vcp.RA.X * Py - vcp.RA.Y * Px);
                    //Debug.Assert(vA.x == 0);

                    // vB += invMassB * P;
                    vB.X += Px * mB;
                    vB.Y += Py * mB;
                    wB   += iB * (vcp.RB.X * Py - vcp.RB.Y * Px);
                    //Debug.Assert(vB.x == 0);
                }
                else
                {
                    // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on
                    // Box2D_Lite).
                    // Build the mini LCP for this contact patch
                    //
                    // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
                    //
                    // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
                    // b = vn_0 - velocityBias
                    //
                    // The system is solved using the "Total enumeration method" (s. Murty). The complementary
                    // constraint vn_i * x_i
                    // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D
                    // contact problem the cases
                    // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be
                    // tested. The first valid
                    // solution that satisfies the problem is chosen.
                    //
                    // In order to account of the accumulated impulse 'a' (because of the iterative nature of
                    // the solver which only requires
                    // that the accumulated impulse is clamped and not the incremental impulse) we change the
                    // impulse variable (x_i).
                    //
                    // Substitute:
                    //
                    // x = a + d
                    //
                    // a := old total impulse
                    // x := new total impulse
                    // d := incremental impulse
                    //
                    // For the current iteration we extend the formula for the incremental impulse
                    // to compute the new total impulse:
                    //
                    // vn = A * d + b
                    // = A * (x - a) + b
                    // = A * x + b - A * a
                    // = A * x + b'
                    // b' = b - A * a;

                    ContactVelocityConstraint.VelocityConstraintPoint cp1 = vc.Points[0];
                    ContactVelocityConstraint.VelocityConstraintPoint cp2 = vc.Points[1];
                    a.X = cp1.NormalImpulse;
                    a.Y = cp2.NormalImpulse;

                    Debug.Assert(a.X >= 0.0f && a.Y >= 0.0f);
                    // Relative velocity at contact
                    // Vec2 dv1 = vB + Cross(wB, cp1.rB) - vA - Cross(wA, cp1.rA);
                    dv1.X = (-wB) * cp1.RB.Y + vB.X - vA.X + wA * cp1.RA.Y;
                    dv1.Y = wB * cp1.RB.X + vB.Y - vA.Y - wA * cp1.RA.X;

                    // Vec2 dv2 = vB + Cross(wB, cp2.rB) - vA - Cross(wA, cp2.rA);
                    dv2.X = (-wB) * cp2.RB.Y + vB.X - vA.X + wA * cp2.RA.Y;
                    dv2.Y = wB * cp2.RB.X + vB.Y - vA.Y - wA * cp2.RA.X;

                    // Compute normal velocity
                    float vn1 = dv1.X * normal.X + dv1.Y * normal.Y;
                    float vn2 = dv2.X * normal.X + dv2.Y * normal.Y;

                    b.X = vn1 - cp1.VelocityBias;
                    b.Y = vn2 - cp2.VelocityBias;
                    //Console.WriteLine("b is " + b.x + "," + b.y);

                    // Compute b'
                    Mat22 R = vc.K;
                    b.X -= (R.Ex.X * a.X + R.Ey.X * a.Y);
                    b.Y -= (R.Ex.Y * a.X + R.Ey.Y * a.Y);
                    //Console.WriteLine("b' is " + b.x + "," + b.y);

                    // final float k_errorTol = 1e-3f;
                    // B2_NOT_USED(k_errorTol);
                    for (; ;)
                    {
                        //
                        // Case 1: vn = 0
                        //
                        // 0 = A * x' + b'
                        //
                        // Solve for x':
                        //
                        // x' = - inv(A) * b'
                        //
                        // Vec2 x = - Mul(c.normalMass, b);
                        Mat22.MulToOutUnsafe(vc.NormalMass, b, x);
                        x.MulLocal(-1);

                        if (x.X >= 0.0f && x.Y >= 0.0f)
                        {
                            //Console.WriteLine("case 1");
                            // Get the incremental impulse
                            // Vec2 d = x - a;
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse
                            // Vec2 P1 = d.x * normal;
                            // Vec2 P2 = d.y * normal;
                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            /*
                             * vA -= invMassA * (P1 + P2); wA -= invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));

                            // Accumulate
                            cp1.NormalImpulse = x.X;
                            cp2.NormalImpulse = x.Y;

                            /*
                             * #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = vB + Cross(wB, cp1.rB) - vA -
                             * Cross(wA, cp1.rA); dv2 = vB + Cross(wB, cp2.rB) - vA - Cross(wA, cp2.rA);
                             *
                             * // Compute normal velocity vn1 = Dot(dv1, normal); vn2 = Dot(dv2, normal);
                             *
                             * Debug.Assert(Abs(vn1 - cp1.velocityBias) < k_errorTol); Debug.Assert(Abs(vn2 - cp2.velocityBias)
                             * < k_errorTol); #endif
                             */
                            if (DEBUG_SOLVER)
                            {
                                // Postconditions
                                Vec2 _dv1 = vB.Add(Vec2.Cross(wB, cp1.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp1.RA)));
                                Vec2 _dv2 = vB.Add(Vec2.Cross(wB, cp2.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp2.RA)));
                                // Compute normal velocity
                                vn1 = Vec2.Dot(_dv1, normal);
                                vn2 = Vec2.Dot(_dv2, normal);

                                Debug.Assert(MathUtils.Abs(vn1 - cp1.VelocityBias) < ERROR_TO_I);
                                Debug.Assert(MathUtils.Abs(vn2 - cp2.VelocityBias) < ERROR_TO_I);
                            }
                            break;
                        }

                        //
                        // Case 2: vn1 = 0 and x2 = 0
                        //
                        // 0 = a11 * x1' + a12 * 0 + b1'
                        // vn2 = a21 * x1' + a22 * 0 + '
                        //
                        x.X = (-cp1.NormalMass) * b.X;
                        x.Y = 0.0f;
                        vn1 = 0.0f;
                        vn2 = vc.K.Ex.Y * x.X + b.Y;

                        if (x.X >= 0.0f && vn2 >= 0.0f)
                        {
                            //Console.WriteLine("case 2");
                            // Get the incremental impulse
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse
                            // Vec2 P1 = d.x * normal;
                            // Vec2 P2 = d.y * normal;
                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            /*
                             * Vec2 P1 = d.x * normal; Vec2 P2 = d.y * normal; vA -= invMassA * (P1 + P2); wA -=
                             * invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));


                            // Accumulate
                            //Debug.Assert(x.x == 0 && x.y == 0);
                            cp1.NormalImpulse = x.X;
                            cp2.NormalImpulse = x.Y;

                            /*
                             * #if B2_DEBUG_SOLVER == 1 // Postconditions dv1 = vB + Cross(wB, cp1.rB) - vA -
                             * Cross(wA, cp1.rA);
                             *
                             * // Compute normal velocity vn1 = Dot(dv1, normal);
                             *
                             * Debug.Assert(Abs(vn1 - cp1.velocityBias) < k_errorTol); #endif
                             */
                            if (DEBUG_SOLVER)
                            {
                                // Postconditions
                                Vec2 _dv1 = vB.Add(Vec2.Cross(wB, cp1.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp1.RA)));
                                // Compute normal velocity
                                vn1 = Vec2.Dot(_dv1, normal);

                                Debug.Assert(MathUtils.Abs(vn1 - cp1.VelocityBias) < ERROR_TO_I);
                            }
                            break;
                        }


                        //
                        // Case 3: wB = 0 and x1 = 0
                        //
                        // vn1 = a11 * 0 + a12 * x2' + b1'
                        // 0 = a21 * 0 + a22 * x2' + '
                        //
                        x.X = 0.0f;
                        x.Y = (-cp2.NormalMass) * b.Y;
                        vn1 = vc.K.Ey.X * x.Y + b.X;
                        vn2 = 0.0f;

                        if (x.Y >= 0.0f && vn1 >= 0.0f)
                        {
                            //Console.WriteLine("case 3");
                            // Resubstitute for the incremental impulse
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse

                            /*
                             * Vec2 P1 = d.x * normal; Vec2 P2 = d.y * normal; vA -= invMassA * (P1 + P2); wA -=
                             * invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));

                            // Accumulate
                            //Debug.Assert(x.x == 0 && x.y == 0);
                            cp1.NormalImpulse = x.X;
                            cp2.NormalImpulse = x.Y;

                            /*
                             * #if B2_DEBUG_SOLVER == 1 // Postconditions dv2 = vB + Cross(wB, cp2.rB) - vA -
                             * Cross(wA, cp2.rA);
                             *
                             * // Compute normal velocity vn2 = Dot(dv2, normal);
                             *
                             * Debug.Assert(Abs(vn2 - cp2.velocityBias) < k_errorTol); #endif
                             */
                            if (DEBUG_SOLVER)
                            {
                                // Postconditions
                                Vec2 _dv2 =
                                    vB.Add(Vec2.Cross(wB, cp2.RB).SubLocal(vA).SubLocal(Vec2.Cross(wA, cp2.RA)));
                                // Compute normal velocity
                                vn2 = Vec2.Dot(_dv2, normal);

                                Debug.Assert(MathUtils.Abs(vn2 - cp2.VelocityBias) < ERROR_TO_I);
                            }
                            break;
                        }

                        //
                        // Case 4: x1 = 0 and x2 = 0
                        //
                        // vn1 = b1
                        // vn2 = ;
                        x.X = 0.0f;
                        x.Y = 0.0f;
                        vn1 = b.X;
                        vn2 = b.Y;

                        if (vn1 >= 0.0f && vn2 >= 0.0f)
                        {
                            //Console.WriteLine("case 4");
                            // Resubstitute for the incremental impulse
                            d.Set(x).SubLocal(a);

                            // Apply incremental impulse

                            /*
                             * Vec2 P1 = d.x * normal; Vec2 P2 = d.y * normal; vA -= invMassA * (P1 + P2); wA -=
                             * invIA * (Cross(cp1.rA, P1) + Cross(cp2.rA, P2));
                             *
                             * vB += invMassB * (P1 + P2); wB += invIB * (Cross(cp1.rB, P1) + Cross(cp2.rB, P2));
                             */

                            P1.Set(normal).MulLocal(d.X);
                            P2.Set(normal).MulLocal(d.Y);

                            temp1.Set(P1).AddLocal(P2);
                            temp2.Set(temp1).MulLocal(mA);
                            vA.SubLocal(temp2);
                            temp2.Set(temp1).MulLocal(mB);
                            vB.AddLocal(temp2);
                            //Debug.Assert(vA.x == 0);
                            //Debug.Assert(vB.x == 0);

                            wA -= iA * (Vec2.Cross(cp1.RA, P1) + Vec2.Cross(cp2.RA, P2));
                            wB += iB * (Vec2.Cross(cp1.RB, P1) + Vec2.Cross(cp2.RB, P2));


                            // Accumulate
                            //Debug.Assert(x.x == 0 && x.y == 0);
                            cp1.NormalImpulse = x.X;
                            cp2.NormalImpulse = x.Y;

                            break;
                        }

                        // No solution, give up. This is hit sometimes, but it doesn't seem to matter.
                        break;
                    }
                }

                Velocities[indexA].V.Set(vA);
                Velocities[indexA].W = wA;
                Velocities[indexB].V.Set(vB);
                Velocities[indexB].W = wB;

                //Console.WriteLine("Ending velocity for " + indexA + " is " + vA.x + "," + vA.y + " rot " + wA);
                //Console.WriteLine("Ending velocity for " + indexB + " is " + vB.x + "," + vB.y + " rot " + wB);
            }
        }
Пример #16
0
        public override void ComputeMass(MassData massData, float density)
        {
            // Polygon mass, centroid, and inertia.
            // Let rho be the polygon density in mass per unit area.
            // Then:
            // mass = rho * int(dA)
            // centroid.x = (1/mass) * rho * int(x * dA)
            // centroid.y = (1/mass) * rho * int(y * dA)
            // I = rho * int((x*x + y*y) * dA)
            //
            // We can compute these integrals by summing all the integrals
            // for each triangle of the polygon. To evaluate the integral
            // for a single triangle, we make a change of variables to
            // the (u,v) coordinates of the triangle:
            // x = x0 + e1x * u + e2x * v
            // y = y0 + e1y * u + e2y * v
            // where 0 <= u && 0 <= v && u + v <= 1.
            //
            // We integrate u from [0,1-v] and then v from [0,1].
            // We also need to use the Jacobian of the transformation:
            // D = cross(e1, e2)
            //
            // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
            //
            // The rest of the derivation is handled by computer algebra.

            Debug.Assert(VertexCount >= 3);

            Vec2 center = pool1;

            center.SetZero();
            float area = 0.0f;
            float I    = 0.0f;

            // pRef is the reference point for forming triangles.
            // It's location doesn't change the result (except for rounding error).
            Vec2 s = pool2;

            s.SetZero();
            // This code would put the reference point inside the polygon.
            for (int i = 0; i < VertexCount; ++i)
            {
                s.AddLocal(Vertices[i]);
            }
            s.MulLocal(1.0f / VertexCount);

            const float k_inv3 = 1.0f / 3.0f;

            Vec2 e1 = pool3;
            Vec2 e2 = pool4;

            for (int i = 0; i < VertexCount; ++i)
            {
                // Triangle vertices.
                e1.Set(Vertices[i]).SubLocal(s);
                e2.Set(s).NegateLocal().AddLocal(i + 1 < VertexCount ? Vertices[i + 1] : Vertices[0]);

                float D = Vec2.Cross(e1, e2);

                float triangleArea = 0.5f * D;
                area += triangleArea;

                // Area weighted centroid
                center.X += triangleArea * k_inv3 * (e1.X + e2.X);
                center.Y += triangleArea * k_inv3 * (e1.Y + e2.Y);

                float ex1 = e1.X;
                float ey1 = e1.Y;
                float ex2 = e2.X;
                float ey2 = e2.Y;

                float intx2 = ex1 * ex1 + ex2 * ex1 + ex2 * ex2;
                float inty2 = ey1 * ey1 + ey2 * ey1 + ey2 * ey2;

                I += (0.25f * k_inv3 * D) * (intx2 + inty2);
            }

            // Total mass
            massData.Mass = density * area;

            // Center of mass
            Debug.Assert(area > Settings.EPSILON);
            center.MulLocal(1.0f / area);
            massData.Center.Set(center).AddLocal(s);

            // Inertia tensor relative to the local origin (point s)
            massData.I = I * density;

            // Shift to center of mass then to original body origin.
            massData.I += massData.Mass * (Vec2.Dot(massData.Center, massData.Center));
        }
Пример #17
0
 public void GetScreenToWorld(Vec2 argScreen, Vec2 argWorld)
 {
     argWorld.Set(argScreen);
     argWorld.SubLocal(Box.Extents);
     Box.R.InvertToOut(inv2);
     inv2.MulToOut(argWorld, argWorld);
     if (YFlip)
     {
         yFlipMatInv.MulToOut(argWorld, argWorld);
     }
     argWorld.AddLocal(Box.Center);
 }
Пример #18
0
 public void GetWorldToScreen(Vec2 argWorld, Vec2 argScreen)
 {
     argScreen.Set(argWorld);
     argScreen.SubLocal(Box.Center);
     Box.R.MulToOut(argScreen, argScreen);
     if (YFlip)
     {
         yFlipMat.MulToOut(argScreen, argScreen);
     }
     argScreen.AddLocal(Box.Extents);
 }
Пример #19
0
        /// <seealso cref="Joint.solveVelocityConstraints(TimeStep)"></seealso>
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vA = data.Velocities[m_indexA].V;
            float wA = data.Velocities[m_indexA].W;
            Vec2  vB = data.Velocities[m_indexB].V;
            float wB = data.Velocities[m_indexB].W;

            float mA = m_invMassA, mB = m_invMassB;
            float iA = m_invIA, iB = m_invIB;

            Vec2 Cdot1 = Pool.PopVec2();
            Vec2 P     = Pool.PopVec2();
            Vec2 temp  = Pool.PopVec2();

            if (Frequency > 0.0f)
            {
                float Cdot2 = wB - wA;

                float impulse2 = (-m_mass.Ez.Z) * (Cdot2 + m_bias + m_gamma * m_impulse.Z);
                m_impulse.Z += impulse2;

                wA -= iA * impulse2;
                wB += iB * impulse2;

                Vec2.CrossToOutUnsafe(wB, m_rB, Cdot1);
                Vec2.CrossToOutUnsafe(wA, m_rA, temp);
                Cdot1.AddLocal(vB).SubLocal(vA).SubLocal(temp);

                Vec2 impulse1 = P;
                Mat33.Mul22ToOutUnsafe(m_mass, Cdot1, impulse1);
                impulse1.NegateLocal();

                m_impulse.X += impulse1.X;
                m_impulse.Y += impulse1.Y;

                vA.X -= mA * P.X;
                vA.Y -= mA * P.Y;
                wA   -= iA * Vec2.Cross(m_rA, P);

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * Vec2.Cross(m_rB, P);
            }
            else
            {
                Vec2.CrossToOutUnsafe(wA, m_rA, temp);
                Vec2.CrossToOutUnsafe(wB, m_rB, Cdot1);
                Cdot1.AddLocal(vB).SubLocal(vA).SubLocal(temp);
                float Cdot2 = wB - wA;

                Vec3 Cdot = Pool.PopVec3();
                Cdot.Set(Cdot1.X, Cdot1.Y, Cdot2);

                Vec3 impulse = Pool.PopVec3();
                Mat33.MulToOutUnsafe(m_mass, Cdot, impulse);
                impulse.NegateLocal();
                m_impulse.AddLocal(impulse);

                P.Set(impulse.X, impulse.Y);

                vA.X -= mA * P.X;
                vA.Y -= mA * P.Y;
                wA   -= iA * (Vec2.Cross(m_rA, P) + impulse.Z);

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * (Vec2.Cross(m_rB, P) + impulse.Z);

                Pool.PushVec3(2);
            }

            data.Velocities[m_indexA].V.Set(vA);
            data.Velocities[m_indexA].W = wA;
            data.Velocities[m_indexB].V.Set(vB);
            data.Velocities[m_indexB].W = wB;

            Pool.PushVec2(3);
        }
Пример #20
0
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

            float mA = InvMassA, mB = InvMassB;
            float iA = InvIA, iB = InvIB;

            Vec2 temp = Pool.PopVec2();

            // Solve linear motor constraint.
            if (m_motorEnabled && LimitState != LimitState.Equal)
            {
                temp.Set(vB).SubLocal(vA);
                float Cdot       = Vec2.Dot(Axis, temp) + A2 * wB - A1 * wA;
                float impulse    = MotorMass * (m_motorSpeed - Cdot);
                float oldImpulse = MotorImpulse;
                float maxImpulse = data.Step.Dt * m_maxMotorForce;
                MotorImpulse = MathUtils.Clamp(MotorImpulse + impulse, -maxImpulse, maxImpulse);
                impulse      = MotorImpulse - oldImpulse;

                Vec2 P = Pool.PopVec2();
                P.Set(Axis).MulLocal(impulse);
                float LA = impulse * A1;
                float LB = impulse * A2;

                vA.X -= mA * P.X;
                vA.Y -= mA * P.Y;
                wA   -= iA * LA;

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * LB;

                Pool.PushVec2(1);
            }

            Vec2 Cdot1 = Pool.PopVec2();

            temp.Set(vB).SubLocal(vA);
            Cdot1.X = Vec2.Dot(Perp, temp) + S2 * wB - S1 * wA;
            Cdot1.Y = wB - wA;
            // System.out.println(Cdot1);

            if (m_limitEnabled && LimitState != LimitState.Inactive)
            {
                // Solve prismatic and limit constraint in block form.
                float Cdot2;
                temp.Set(vB).SubLocal(vA);
                Cdot2 = Vec2.Dot(Axis, temp) + A2 * wB - A1 * wA;

                Vec3 Cdot = Pool.PopVec3();
                Cdot.Set(Cdot1.X, Cdot1.Y, Cdot2);
                Cdot.NegateLocal();

                Vec3 f1 = Pool.PopVec3();
                Vec3 df = Pool.PopVec3();

                f1.Set(Impulse);
                K.Solve33ToOut(Cdot.NegateLocal(), df);
                //Cdot.negateLocal(); not used anymore
                Impulse.AddLocal(df);

                if (LimitState == LimitState.AtLower)
                {
                    Impulse.Z = MathUtils.Max(Impulse.Z, 0.0f);
                }
                else if (LimitState == LimitState.AtUpper)
                {
                    Impulse.Z = MathUtils.Min(Impulse.Z, 0.0f);
                }

                // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) +
                // f1(1:2)
                Vec2 b   = Pool.PopVec2();
                Vec2 f2r = Pool.PopVec2();

                temp.Set(K.Ez.X, K.Ez.Y).MulLocal(Impulse.Z - f1.Z);
                b.Set(Cdot1).NegateLocal().SubLocal(temp);

                temp.Set(f1.X, f1.Y);
                K.Solve22ToOut(b, f2r);
                f2r.AddLocal(temp);
                Impulse.X = f2r.X;
                Impulse.Y = f2r.Y;

                df.Set(Impulse).SubLocal(f1);

                Vec2 P = Pool.PopVec2();
                temp.Set(Axis).MulLocal(df.Z);
                P.Set(Perp).MulLocal(df.X).AddLocal(temp);

                float LA = df.X * S1 + df.Y + df.Z * A1;
                float LB = df.X * S2 + df.Y + df.Z * A2;

                vA.X -= mA * P.X;
                vA.Y -= mA * P.Y;
                wA   -= iA * LA;

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * LB;

                Pool.PushVec2(3);
                Pool.PushVec3(3);
            }
            else
            {
                // Limit is inactive, just solve the prismatic constraint in block form.
                Vec2 df = Pool.PopVec2();
                K.Solve22ToOut(Cdot1.NegateLocal(), df);
                Cdot1.NegateLocal();

                Impulse.X += df.X;
                Impulse.Y += df.Y;

                Vec2 P = Pool.PopVec2();
                P.Set(Perp).MulLocal(df.X);
                float LA = df.X * S1 + df.Y;
                float LB = df.X * S2 + df.Y;

                vA.X -= mA * P.X;
                vA.Y -= mA * P.Y;
                wA   -= iA * LA;

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * LB;

                Vec2 Cdot10 = Pool.PopVec2();
                Cdot10.Set(Cdot1);

                Cdot1.X = Vec2.Dot(Perp, temp.Set(vB).SubLocal(vA)) + S2 * wB - S1 * wA;
                Cdot1.Y = wB - wA;

                if (MathUtils.Abs(Cdot1.X) > 0.01f || MathUtils.Abs(Cdot1.Y) > 0.01f)
                {
                    // djm note: what's happening here?
                    Mat33.Mul22ToOutUnsafe(K, df, temp);
                    Cdot1.X += 0.0f;
                }

                Pool.PushVec2(3);
            }

            data.Velocities[IndexA].V.Set(vA);
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushVec2(2);
        }
Пример #21
0
        /// <summary>
        /// This resets the mass properties to the sum of the mass properties of the fixtures. This
        /// normally does not need to be called unless you called setMassData to override the mass and you
        /// later want to reset the mass.
        /// </summary>
        public void ResetMassData()
        {
            // Compute mass data from shapes. Each shape has its own density.
            Mass    = 0.0f;
            InvMass = 0.0f;
            I       = 0.0f;
            InvI    = 0.0f;
            Sweep.LocalCenter.SetZero();

            // Static and kinematic bodies have zero mass.
            if (m_type == BodyType.Static || m_type == BodyType.Kinematic)
            {
                // m_sweep.c0 = m_sweep.c = m_xf.position;
                Sweep.C0.Set(Xf.P);
                Sweep.C.Set(Xf.P);
                Sweep.A0 = Sweep.A;
                return;
            }

            Debug.Assert(m_type == BodyType.Dynamic);

            // Accumulate mass over all fixtures.
            Vec2 localCenter = World.Pool.PopVec2();

            localCenter.SetZero();
            Vec2     temp     = World.Pool.PopVec2();
            MassData massData = pmd;

            for (Fixture f = FixtureList; f != null; f = f.Next)
            {
                if (f.Density == 0.0f)
                {
                    continue;
                }
                f.GetMassData(massData);
                Mass += massData.Mass;
                // center += massData.mass * massData.center;
                temp.Set(massData.Center).MulLocal(massData.Mass);
                localCenter.AddLocal(temp);
                I += massData.I;
            }

            // Compute center of mass.
            if (Mass > 0.0f)
            {
                InvMass = 1.0f / Mass;
                localCenter.MulLocal(InvMass);
            }
            else
            {
                // Force all dynamic bodies to have a positive mass.
                Mass    = 1.0f;
                InvMass = 1.0f;
            }

            if (I > 0.0f && (Flags & TypeFlags.FixedRotation) == 0)
            {
                // Center the inertia about the center of mass.
                I -= Mass * Vec2.Dot(localCenter, localCenter);
                Debug.Assert(I > 0.0f);
                InvI = 1.0f / I;
            }
            else
            {
                I    = 0.0f;
                InvI = 0.0f;
            }

            Vec2 oldCenter = World.Pool.PopVec2();

            // Move center of mass.
            oldCenter.Set(Sweep.C);
            Sweep.LocalCenter.Set(localCenter);
            // m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
            Transform.MulToOutUnsafe(Xf, Sweep.LocalCenter, Sweep.C0);
            Sweep.C.Set(Sweep.C0);

            // Update center of mass velocity.
            // m_linearVelocity += Cross(m_angularVelocity, m_sweep.c - oldCenter);
            temp.Set(Sweep.C).SubLocal(oldCenter);

            Vec2 temp2 = oldCenter;

            Vec2.CrossToOutUnsafe(m_angularVelocity, temp, temp2);
            m_linearVelocity.AddLocal(temp2);

            World.Pool.PushVec2(3);
        }
Пример #22
0
        /// <seealso cref="Joint.initVelocityConstraints(TimeStep)"></seealso>
        public override void InitVelocityConstraints(SolverData data)
        {
            IndexA = BodyA.IslandIndex;
            IndexB = BodyB.IslandIndex;
            LocalCenterA.Set(BodyA.Sweep.LocalCenter);
            LocalCenterB.Set(BodyB.Sweep.LocalCenter);
            InvMassA = BodyA.InvMass;
            InvMassB = BodyB.InvMass;
            InvIA    = BodyA.InvI;
            InvIB    = BodyB.InvI;

            float aA = data.Positions[IndexA].A;
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;

            float aB = data.Positions[IndexB].A;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;


            Vec2 temp = Pool.PopVec2();
            Rot  qA   = Pool.PopRot();
            Rot  qB   = Pool.PopRot();

            qA.Set(aA);
            qB.Set(aB);

            // Compute the effective mass matrix.
            Rot.MulToOutUnsafe(qA, temp.Set(m_localAnchorA).SubLocal(LocalCenterA), RA);
            Rot.MulToOutUnsafe(qB, temp.Set(m_localAnchorB).SubLocal(LocalCenterB), RB);

            // J = [-I -r1_skew I r2_skew]
            // [ 0 -1 0 1]
            // r_skew = [-ry; rx]

            // Matlab
            // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
            // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
            // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]

            float mA = InvMassA, mB = InvMassB;
            float iA = InvIA, iB = InvIB;

            Mat22 K = Pool.PopMat22();

            K.Ex.X = mA + mB + iA * RA.Y * RA.Y + iB * RB.Y * RB.Y;
            K.Ex.Y = (-iA) * RA.X * RA.Y - iB * RB.X * RB.Y;
            K.Ey.X = K.Ex.Y;
            K.Ey.Y = mA + mB + iA * RA.X * RA.X + iB * RB.X * RB.X;

            K.InvertToOut(LinearMass);

            AngularMass = iA + iB;
            if (AngularMass > 0.0f)
            {
                AngularMass = 1.0f / AngularMass;
            }

            if (data.Step.WarmStarting)
            {
                // Scale impulses to support a variable time step.
                m_linearImpulse.MulLocal(data.Step.DtRatio);
                m_angularImpulse *= data.Step.DtRatio;

                Vec2 P = Pool.PopVec2();
                P.Set(m_linearImpulse);

                temp.Set(P).MulLocal(mA);
                vA.SubLocal(temp);
                wA -= iA * (Vec2.Cross(RA, P) + m_angularImpulse);

                temp.Set(P).MulLocal(mB);
                vB.AddLocal(temp);
                wB += iB * (Vec2.Cross(RB, P) + m_angularImpulse);

                Pool.PushVec2(1);
            }
            else
            {
                m_linearImpulse.SetZero();
                m_angularImpulse = 0.0f;
            }
            data.Velocities[IndexA].V.Set(vA);
            if (data.Velocities[IndexA].W != wA)
            {
                Debug.Assert(data.Velocities[IndexA].W != wA);
            }
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushRot(2);
            Pool.PushVec2(1);
            Pool.PushMat22(1);
        }
Пример #23
0
 public void GetLinearVelocityFromWorldPointToOut(Vec2 worldPoint, Vec2 result)
 {
     result.Set(worldPoint).SubLocal(Sweep.C);
     Vec2.CrossToOut(m_angularVelocity, result, result);
     result.AddLocal(m_linearVelocity);
 }
Пример #24
0
        public override void SolveVelocityConstraints(SolverData data)
        {
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

            float mA = InvMassA, mB = InvMassB;
            float iA = InvIA, iB = InvIB;

            bool fixedRotation = (iA + iB == 0.0f);

            // Solve motor constraint.
            if (m_motorEnabled && LimitState != LimitState.Equal && fixedRotation == false)
            {
                float Cdot       = wB - wA - m_motorSpeed;
                float impulse    = (-MotorMass) * Cdot;
                float oldImpulse = MotorImpulse;
                float maxImpulse = data.Step.Dt * m_maxMotorTorque;
                MotorImpulse = MathUtils.Clamp(MotorImpulse + impulse, -maxImpulse, maxImpulse);
                impulse      = MotorImpulse - oldImpulse;

                wA -= iA * impulse;
                wB += iB * impulse;
            }
            Vec2 temp = Pool.PopVec2();

            // Solve limit constraint.
            if (m_limitEnabled && LimitState != LimitState.Inactive && fixedRotation == false)
            {
                Vec2 Cdot1 = Pool.PopVec2();
                Vec3 Cdot  = Pool.PopVec3();

                // Solve point-to-point constraint
                Vec2.CrossToOutUnsafe(wA, RA, temp);
                Vec2.CrossToOutUnsafe(wB, RB, Cdot1);
                Cdot1.AddLocal(vB).SubLocal(vA).SubLocal(temp);
                float Cdot2 = wB - wA;
                Cdot.Set(Cdot1.X, Cdot1.Y, Cdot2);

                Vec3 impulse = Pool.PopVec3();
                Mass.Solve33ToOut(Cdot, impulse);
                impulse.NegateLocal();

                if (LimitState == LimitState.Equal)
                {
                    Impulse.AddLocal(impulse);
                }
                else if (LimitState == LimitState.AtLower)
                {
                    float newImpulse = Impulse.Z + impulse.Z;
                    if (newImpulse < 0.0f)
                    {
                        //UPGRADE_NOTE: Final was removed from the declaration of 'rhs '. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"
                        Vec2 rhs = Pool.PopVec2();
                        rhs.Set(Mass.Ez.X, Mass.Ez.Y).MulLocal(Impulse.Z).SubLocal(Cdot1);
                        Mass.Solve22ToOut(rhs, temp);
                        impulse.X  = temp.X;
                        impulse.Y  = temp.Y;
                        impulse.Z  = -Impulse.Z;
                        Impulse.X += temp.X;
                        Impulse.Y += temp.Y;
                        Impulse.Z  = 0.0f;
                        Pool.PushVec2(1);
                    }
                    else
                    {
                        Impulse.AddLocal(impulse);
                    }
                }
                else if (LimitState == LimitState.AtUpper)
                {
                    float newImpulse = Impulse.Z + impulse.Z;
                    if (newImpulse > 0.0f)
                    {
                        Vec2 rhs = Pool.PopVec2();
                        rhs.Set(Mass.Ez.X, Mass.Ez.Y).MulLocal(Impulse.Z).SubLocal(Cdot1);
                        Mass.Solve22ToOut(rhs, temp);
                        impulse.X  = temp.X;
                        impulse.Y  = temp.Y;
                        impulse.Z  = -Impulse.Z;
                        Impulse.X += temp.X;
                        Impulse.Y += temp.Y;
                        Impulse.Z  = 0.0f;
                        Pool.PushVec2(1);
                    }
                    else
                    {
                        Impulse.AddLocal(impulse);
                    }
                }
                Vec2 P = Pool.PopVec2();

                P.Set(impulse.X, impulse.Y);

                vA.X -= mA * P.X;
                vA.Y -= mA * P.Y;
                wA   -= iA * (Vec2.Cross(RA, P) + impulse.Z);

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * (Vec2.Cross(RB, P) + impulse.Z);

                Pool.PushVec2(2);
                Pool.PushVec3(2);
            }
            else
            {
                // Solve point-to-point constraint
                Vec2 Cdot    = Pool.PopVec2();
                Vec2 impulse = Pool.PopVec2();

                Vec2.CrossToOutUnsafe(wA, RA, temp);
                Vec2.CrossToOutUnsafe(wB, RB, Cdot);
                Cdot.AddLocal(vB).SubLocal(vA).SubLocal(temp);
                Mass.Solve22ToOut(Cdot.NegateLocal(), impulse); // just leave negated

                Impulse.X += impulse.X;
                Impulse.Y += impulse.Y;

                vA.X -= mA * impulse.X;
                vA.Y -= mA * impulse.Y;
                wA   -= iA * Vec2.Cross(RA, impulse);

                vB.X += mB * impulse.X;
                vB.Y += mB * impulse.Y;
                wB   += iB * Vec2.Cross(RB, impulse);

                Pool.PushVec2(2);
            }

            data.Velocities[IndexA].V.Set(vA);
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;

            Pool.PushVec2(1);
        }