예제 #1
0
        public override bool SolvePositionConstraints(SolverData data)
        {
            if (FrequencyHz > 0.0f)
            {
                return(true);
            }
            Rot  qA = Pool.PopRot();
            Rot  qB = Pool.PopRot();
            Vec2 rA = Pool.PopVec2();
            Vec2 rB = Pool.PopVec2();
            Vec2 u  = Pool.PopVec2();

            Vec2  cA = data.Positions[IndexA].C;
            float aA = data.Positions[IndexA].A;
            Vec2  cB = data.Positions[IndexB].C;
            float aB = data.Positions[IndexB].A;

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

            Rot.MulToOutUnsafe(qA, u.Set(LocalAnchorA).SubLocal(LocalCenterA), rA);
            Rot.MulToOutUnsafe(qB, u.Set(LocalAnchorB).SubLocal(LocalCenterB), rB);
            u.Set(cB).AddLocal(rB).SubLocal(cA).SubLocal(rA);


            float length = u.Normalize();
            float C      = length - Length;

            C = MathUtils.Clamp(C, -Settings.MAX_LINEAR_CORRECTION, Settings.MAX_LINEAR_CORRECTION);

            float impulse = (-Mass) * C;
            float Px      = impulse * u.X;
            float Py      = impulse * u.Y;

            cA.X -= InvMassA * Px;
            cA.Y -= InvMassA * Py;
            aA   -= InvIA * (rA.X * Py - rA.Y * Px);
            cB.X += InvMassB * Px;
            cB.Y += InvMassB * Py;
            aB   += InvIB * (rB.X * Py - rB.Y * Px);

            data.Positions[IndexA].C.Set(cA);
            data.Positions[IndexA].A = aA;
            data.Positions[IndexB].C.Set(cB);
            data.Positions[IndexB].A = aB;

            Pool.PushVec2(3);
            Pool.PushRot(2);

            return(MathUtils.Abs(C) < Settings.LINEAR_SLOP);
        }
예제 #2
0
        internal override bool SolvePositionConstraints(ref SolverData data)
        {
            Vector2 cA = data.Positions[_indexA].C;
            float   aA = data.Positions[_indexA].A;
            Vector2 cB = data.Positions[_indexB].C;
            float   aB = data.Positions[_indexB].A;

            Rot qA = new Rot(aA), qB = new Rot(aB);

            float angularError = 0.0f;
            float positionError;

            bool fixedRotation = (_invIA + _invIB == 0.0f);

            // Solve angular limit constraint.
            if (_enableLimit && _limitState != LimitState.Inactive && fixedRotation == false)
            {
                float angle        = aB - aA - ReferenceAngle;
                float limitImpulse = 0.0f;

                if (_limitState == LimitState.Equal)
                {
                    // Prevent large angular corrections
                    float C = MathUtils.Clamp(angle - _lowerAngle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);
                    limitImpulse = -_motorMass * C;
                    angularError = Math.Abs(C);
                }
                else if (_limitState == LimitState.AtLower)
                {
                    float C = angle - _lowerAngle;
                    angularError = -C;

                    // Prevent large angular corrections and allow some slop.
                    C            = MathUtils.Clamp(C + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f);
                    limitImpulse = -_motorMass * C;
                }
                else if (_limitState == LimitState.AtUpper)
                {
                    float C = angle - _upperAngle;
                    angularError = C;

                    // Prevent large angular corrections and allow some slop.
                    C            = MathUtils.Clamp(C - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection);
                    limitImpulse = -_motorMass * C;
                }

                aA -= _invIA * limitImpulse;
                aB += _invIB * limitImpulse;
            }

            // Solve point-to-point constraint.
            {
                qA.Set(aA);
                qB.Set(aB);
                Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
                Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);

                Vector2 C = cB + rB - cA - rA;
                positionError = C.Length();

                float mA = _invMassA, mB = _invMassB;
                float iA = _invIA, iB = _invIB;

                Mat22 K = new Mat22();
                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;

                Vector2 impulse = -K.Solve(C);

                cA -= mA * impulse;
                aA -= iA * MathUtils.Cross(rA, impulse);

                cB += mB * impulse;
                aB += iB * MathUtils.Cross(rB, impulse);
            }

            data.Positions[_indexA].C = cA;
            data.Positions[_indexA].A = aA;
            data.Positions[_indexB].C = cB;
            data.Positions[_indexB].A = aB;

            return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop);
        }
예제 #3
0
        internal override bool SolvePositionConstraints(ref SolverData data)
        {
            FVector2 cA = data.positions[m_indexA].c;
            float aA = data.positions[m_indexA].a;
            FVector2 cB = data.positions[m_indexB].c;
            float aB = data.positions[m_indexB].a;

            Rot qA = new Rot(aA), qB = new Rot(aB);

            float angularError = 0.0f;
            float positionError;

            bool fixedRotation = (m_invIA + m_invIB == 0.0f);

            // Solve angular limit constraint.
            if (_enableLimit && _limitState != LimitState.Inactive && fixedRotation == false)
            {
                float angle = aB - aA - ReferenceAngle;
                float limitImpulse = 0.0f;

                if (_limitState == LimitState.Equal)
                {
                    // Prevent large angular corrections
                    float C = MathUtils.Clamp(angle - _lowerAngle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);
                    limitImpulse = -m_motorMass * C;
                    angularError = Math.Abs(C);
                }
                else if (_limitState == LimitState.AtLower)
                {
                    float C = angle - _lowerAngle;
                    angularError = -C;

                    // Prevent large angular corrections and allow some slop.
                    C = MathUtils.Clamp(C + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f);
                    limitImpulse = -m_motorMass * C;
                }
                else if (_limitState == LimitState.AtUpper)
                {
                    float C = angle - _upperAngle;
                    angularError = C;

                    // Prevent large angular corrections and allow some slop.
                    C = MathUtils.Clamp(C - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection);
                    limitImpulse = -m_motorMass * C;
                }

                aA -= m_invIA * limitImpulse;
                aB += m_invIB * limitImpulse;
            }

            // Solve point-to-point constraint.
            {
                qA.Set(aA);
                qB.Set(aB);
                FVector2 rA = MathUtils.Mul(qA, LocalAnchorA - m_localCenterA);
                FVector2 rB = MathUtils.Mul(qB, LocalAnchorB - m_localCenterB);

                FVector2 C = cB + rB - cA - rA;
                positionError = C.Length();

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

                Mat22 K = new Mat22();
                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;

                FVector2 impulse = -K.Solve(C);

                cA -= mA * impulse;
                aA -= iA * MathUtils.Cross(rA, impulse);

                cB += mB * impulse;
                aB += iB * MathUtils.Cross(rB, impulse);
            }

            data.positions[m_indexA].c = cA;
            data.positions[m_indexA].a = aA;
            data.positions[m_indexB].c = cB;
            data.positions[m_indexB].a = aB;

            return positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;
        }
예제 #4
0
        /// <seealso cref="Joint.solvePositionConstraints(float)"></seealso>
        public override bool SolvePositionConstraints(SolverData data)
        {
            Vec2  cA   = data.Positions[m_indexA].C;
            float aA   = data.Positions[m_indexA].A;
            Vec2  cB   = data.Positions[m_indexB].C;
            float aB   = data.Positions[m_indexB].A;
            Rot   qA   = Pool.PopRot();
            Rot   qB   = Pool.PopRot();
            Vec2  temp = Pool.PopVec2();
            Vec2  rA   = Pool.PopVec2();
            Vec2  rB   = Pool.PopVec2();

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

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

            Rot.MulToOutUnsafe(qA, temp.Set(LocalAnchorA).SubLocal(m_localCenterA), rA);
            Rot.MulToOutUnsafe(qB, temp.Set(LocalAnchorB).SubLocal(m_localCenterB), rB);
            float positionError, angularError;

            Mat33 K  = Pool.PopMat33();
            Vec2  C1 = Pool.PopVec2();
            Vec2  P  = Pool.PopVec2();

            K.Ex.X = mA + mB + rA.Y * rA.Y * iA + rB.Y * rB.Y * iB;
            K.Ey.X = (-rA.Y) * rA.X * iA - rB.Y * rB.X * iB;
            K.Ez.X = (-rA.Y) * iA - rB.Y * iB;
            K.Ex.Y = K.Ey.X;
            K.Ey.Y = mA + mB + rA.X * rA.X * iA + rB.X * rB.X * iB;
            K.Ez.Y = rA.X * iA + rB.X * iB;
            K.Ex.Z = K.Ez.X;
            K.Ey.Z = K.Ez.Y;
            K.Ez.Z = iA + iB;

            if (Frequency > 0.0f)
            {
                C1.Set(cB).AddLocal(rB).SubLocal(cA).SubLocal(rA);

                positionError = C1.Length();
                angularError  = 0.0f;

                K.Solve22ToOut(C1, P);
                P.NegateLocal();

                cA.X -= mA * P.X;
                cA.Y -= mA * P.Y;
                aA   -= iA * Vec2.Cross(rA, P);

                cB.X += mB * P.X;
                cB.Y += mB * P.Y;
                aB   += iB * Vec2.Cross(rB, P);
            }
            else
            {
                C1.Set(cB).AddLocal(rB).SubLocal(cA).SubLocal(rA);
                float C2 = aB - aA - m_referenceAngle;

                positionError = C1.Length();
                angularError  = MathUtils.Abs(C2);

                Vec3 C       = Pool.PopVec3();
                Vec3 impulse = Pool.PopVec3();
                C.Set(C1.X, C1.Y, C2);

                K.Solve33ToOut(C, impulse);
                impulse.NegateLocal();
                P.Set(impulse.X, impulse.Y);

                cA.X -= mA * P.X;
                cA.Y -= mA * P.Y;
                aA   -= iA * (Vec2.Cross(rA, P) + impulse.Z);

                cB.X += mB * P.X;
                cB.Y += mB * P.Y;
                aB   += iB * (Vec2.Cross(rB, P) + impulse.Z);
            }

            data.Positions[m_indexA].C.Set(cA);
            data.Positions[m_indexA].A = aA;
            data.Positions[m_indexB].C.Set(cB);
            data.Positions[m_indexB].A = aB;

            Pool.PushVec2(5);
            Pool.PushRot(2);
            Pool.PushMat33(1);

            return(positionError <= Settings.LINEAR_SLOP && angularError <= Settings.ANGULAR_SLOP);
        }
예제 #5
0
        /// <seealso cref="Joint.initVelocityConstraints(TimeStep)"></seealso>
        public override void InitVelocityConstraints(SolverData data)
        {
            m_indexA = BodyA.IslandIndex;
            m_indexB = BodyB.IslandIndex;
            m_localCenterA.Set(BodyA.Sweep.LocalCenter);
            m_localCenterB.Set(BodyB.Sweep.LocalCenter);
            m_invMassA = BodyA.InvMass;
            m_invMassB = BodyB.InvMass;
            m_invIA    = BodyA.InvI;
            m_invIB    = BodyB.InvI;

            //    Vec2 cA = data.positions[m_indexA].c;
            float aA = data.Positions[m_indexA].A;
            Vec2  vA = data.Velocities[m_indexA].V;
            float wA = data.Velocities[m_indexA].W;

            //    Vec2 cB = data.positions[m_indexB].c;
            float aB = data.Positions[m_indexB].A;
            Vec2  vB = data.Velocities[m_indexB].V;
            float wB = data.Velocities[m_indexB].W;

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

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

            // Compute the effective masses.
            Rot.MulToOutUnsafe(qA, temp.Set(LocalAnchorA).SubLocal(m_localCenterA), m_rA);
            Rot.MulToOutUnsafe(qB, temp.Set(LocalAnchorB).SubLocal(m_localCenterB), m_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 = m_invMassA, mB = m_invMassB;
            float iA = m_invIA, iB = m_invIB;

            Mat33 K = Pool.PopMat33();

            K.Ex.X = mA + mB + m_rA.Y * m_rA.Y * iA + m_rB.Y * m_rB.Y * iB;
            K.Ey.X = (-m_rA.Y) * m_rA.X * iA - m_rB.Y * m_rB.X * iB;
            K.Ez.X = (-m_rA.Y) * iA - m_rB.Y * iB;
            K.Ex.Y = K.Ey.X;
            K.Ey.Y = mA + mB + m_rA.X * m_rA.X * iA + m_rB.X * m_rB.X * iB;
            K.Ez.Y = m_rA.X * iA + m_rB.X * iB;
            K.Ex.Z = K.Ez.X;
            K.Ey.Z = K.Ez.Y;
            K.Ez.Z = iA + iB;

            if (Frequency > 0.0f)
            {
                K.GetInverse22(m_mass);

                float invM = iA + iB;
                float m    = invM > 0.0f ? 1.0f / invM : 0.0f;

                float C = aB - aA - m_referenceAngle;

                // Frequency
                float omega = 2.0f * MathUtils.PI * Frequency;

                // Damping coefficient
                float d = 2.0f * m * DampingRatio * omega;

                // Spring stiffness
                float k = m * omega * omega;

                // magic formulas
                float h = data.Step.Dt;
                m_gamma = h * (d + h * k);
                m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
                m_bias  = C * h * k * m_gamma;

                invM       += m_gamma;
                m_mass.Ez.Z = invM != 0.0f ? 1.0f / invM : 0.0f;
            }
            else
            {
                K.GetSymInverse33(m_mass);
                m_gamma = 0.0f;
                m_bias  = 0.0f;
            }

            if (data.Step.WarmStarting)
            {
                Vec2 P = Pool.PopVec2();
                // Scale impulses to support a variable time step.
                m_impulse.MulLocal(data.Step.DtRatio);

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

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

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * (Vec2.Cross(m_rB, P) + m_impulse.Z);
                Pool.PushVec2(1);
            }
            else
            {
                m_impulse.SetZero();
            }

            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(1);
            Pool.PushRot(2);
            Pool.PushMat33(1);
        }
예제 #6
0
        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;

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

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

            Rot qA = Pool.PopRot();
            Rot qB = Pool.PopRot();

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

            // use m_u as temporary variable
            Rot.MulToOutUnsafe(qA, U.Set(LocalAnchorA).SubLocal(LocalCenterA), RA);
            Rot.MulToOutUnsafe(qB, U.Set(LocalAnchorB).SubLocal(LocalCenterB), RB);
            U.Set(cB).AddLocal(RB).SubLocal(cA).SubLocal(RA);

            Pool.PushRot(2);

            // Handle singularity.
            float length = U.Length();

            if (length > Settings.LINEAR_SLOP)
            {
                U.X *= 1.0f / length;
                U.Y *= 1.0f / length;
            }
            else
            {
                U.Set(0.0f, 0.0f);
            }


            float crAu    = Vec2.Cross(RA, U);
            float crBu    = Vec2.Cross(RB, U);
            float invMass = InvMassA + InvIA * crAu * crAu + InvMassB + InvIB * crBu * crBu;

            // Compute the effective mass matrix.
            Mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;

            if (FrequencyHz > 0.0f)
            {
                float C = length - Length;

                // Frequency
                float omega = 2.0f * MathUtils.PI * FrequencyHz;

                // Damping coefficient
                float d = 2.0f * Mass * DampingRatio * omega;

                // Spring stiffness
                float k = Mass * omega * omega;

                // magic formulas
                float h = data.Step.Dt;
                Gamma = h * (d + h * k);
                Gamma = Gamma != 0.0f ? 1.0f / Gamma : 0.0f;
                Bias  = C * h * k * Gamma;

                invMass += Gamma;
                Mass     = invMass != 0.0f ? 1.0f / invMass : 0.0f;
            }
            else
            {
                Gamma = 0.0f;
                Bias  = 0.0f;
            }
            if (data.Step.WarmStarting)
            {
                // Scale the impulse to support a variable time step.
                Impulse *= data.Step.DtRatio;

                Vec2 P = Pool.PopVec2();
                P.Set(U).MulLocal(Impulse);

                vA.X -= InvMassA * P.X;
                vA.Y -= InvMassA * P.Y;
                wA   -= InvIA * Vec2.Cross(RA, P);

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

                Pool.PushVec2(1);
            }
            else
            {
                Impulse = 0.0f;
            }
            data.Velocities[IndexA].V.Set(vA);
            data.Velocities[IndexA].W = wA;
            data.Velocities[IndexB].V.Set(vB);
            data.Velocities[IndexB].W = wB;
        }
예제 #7
0
        public override void InitVelocityConstraints(SolverData data)
        {
            IndexA = BodyA.IslandIndex;
            IndexB = BodyB.IslandIndex;
            m_localCenterA.Set(BodyA.Sweep.LocalCenter);
            m_localCenterB.Set(BodyB.Sweep.LocalCenter);
            InvMassA = BodyA.InvMass;
            InvMassB = BodyB.InvMass;
            InvIA    = BodyA.InvI;
            InvIB    = BodyB.InvI;

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

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

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

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

            // Compute the effective masses.
            Rot.MulToOutUnsafe(qA, temp.Set(LocalAnchorA).SubLocal(m_localCenterA), RA);
            Rot.MulToOutUnsafe(qB, temp.Set(LocalAnchorB).SubLocal(m_localCenterB), RB);

            m_uA.Set(cA).AddLocal(RA).SubLocal(m_groundAnchorA);
            m_uB.Set(cB).AddLocal(RB).SubLocal(m_groundAnchorB);

            float lengthA = m_uA.Length();
            float lengthB = m_uB.Length();

            if (lengthA > 10f * Settings.LINEAR_SLOP)
            {
                m_uA.MulLocal(1.0f / lengthA);
            }
            else
            {
                m_uA.SetZero();
            }

            if (lengthB > 10f * Settings.LINEAR_SLOP)
            {
                m_uB.MulLocal(1.0f / lengthB);
            }
            else
            {
                m_uB.SetZero();
            }

            // Compute effective mass.
            float ruA = Vec2.Cross(RA, m_uA);
            float ruB = Vec2.Cross(RB, m_uB);

            float mA = InvMassA + InvIA * ruA * ruA;
            float mB = InvMassB + InvIB * ruB * ruB;

            m_mass = mA + m_ratio * m_ratio * mB;

            if (m_mass > 0.0f)
            {
                m_mass = 1.0f / m_mass;
            }

            if (data.Step.WarmStarting)
            {
                // Scale impulses to support variable time steps.
                m_impulse *= data.Step.DtRatio;

                // Warm starting.
                Vec2 PA = Pool.PopVec2();
                Vec2 PB = Pool.PopVec2();

                PA.Set(m_uA).MulLocal(-m_impulse);
                PB.Set(m_uB).MulLocal((-m_ratio) * m_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);

                Pool.PushVec2(2);
            }
            else
            {
                m_impulse = 0.0f;
            }
            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);
            Pool.PushRot(2);
        }
예제 #8
0
        public override bool SolvePositionConstraints(SolverData data)
        {
            Rot  qA   = Pool.PopRot();
            Rot  qB   = Pool.PopRot();
            Vec2 rA   = Pool.PopVec2();
            Vec2 rB   = Pool.PopVec2();
            Vec2 uA   = Pool.PopVec2();
            Vec2 uB   = Pool.PopVec2();
            Vec2 temp = Pool.PopVec2();
            Vec2 PA   = Pool.PopVec2();
            Vec2 PB   = Pool.PopVec2();

            Vec2  cA = data.Positions[IndexA].C;
            float aA = data.Positions[IndexA].A;
            Vec2  cB = data.Positions[IndexB].C;
            float aB = data.Positions[IndexB].A;

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

            Rot.MulToOutUnsafe(qA, temp.Set(LocalAnchorA).SubLocal(m_localCenterA), rA);
            Rot.MulToOutUnsafe(qB, temp.Set(LocalAnchorB).SubLocal(m_localCenterB), rB);

            uA.Set(cA).AddLocal(rA).SubLocal(m_groundAnchorA);
            uB.Set(cB).AddLocal(rB).SubLocal(m_groundAnchorB);

            float lengthA = uA.Length();
            float lengthB = uB.Length();

            if (lengthA > 10.0f * Settings.LINEAR_SLOP)
            {
                uA.MulLocal(1.0f / lengthA);
            }
            else
            {
                uA.SetZero();
            }

            if (lengthB > 10.0f * Settings.LINEAR_SLOP)
            {
                uB.MulLocal(1.0f / lengthB);
            }
            else
            {
                uB.SetZero();
            }

            // Compute effective mass.
            float ruA = Vec2.Cross(rA, uA);
            float ruB = Vec2.Cross(rB, uB);

            float mA = InvMassA + InvIA * ruA * ruA;
            float mB = InvMassB + InvIB * ruB * ruB;

            float mass = mA + m_ratio * m_ratio * mB;

            if (mass > 0.0f)
            {
                mass = 1.0f / mass;
            }

            float C           = m_constant - lengthA - m_ratio * lengthB;
            float linearError = MathUtils.Abs(C);

            float impulse = (-mass) * C;

            PA.Set(uA).MulLocal(-impulse);
            PB.Set(uB).MulLocal((-m_ratio) * impulse);

            cA.X += InvMassA * PA.X;
            cA.Y += InvMassA * PA.Y;
            aA   += InvIA * Vec2.Cross(rA, PA);
            cB.X += InvMassB * PB.X;
            cB.Y += InvMassB * PB.Y;
            aB   += InvIB * Vec2.Cross(rB, PB);

            data.Positions[IndexA].C.Set(cA);
            data.Positions[IndexA].A = aA;
            data.Positions[IndexB].C.Set(cB);
            data.Positions[IndexB].A = aB;

            Pool.PushRot(2);
            Pool.PushVec2(7);

            return(linearError < Settings.LINEAR_SLOP);
        }
예제 #9
0
        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;

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

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

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

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

            // Compute the effective masses.
            Rot.MulToOutUnsafe(qA, d.Set(LocalAnchorA).SubLocal(LocalCenterA), rA);
            Rot.MulToOutUnsafe(qB, d.Set(LocalAnchorB).SubLocal(LocalCenterB), rB);
            d.Set(cB).SubLocal(cA).AddLocal(rB).SubLocal(rA);

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

            // Compute motor Jacobian and effective mass.
            {
                Rot.MulToOutUnsafe(qA, LocalXAxisA, Axis);
                temp.Set(d).AddLocal(rA);
                A1 = Vec2.Cross(temp, Axis);
                A2 = Vec2.Cross(rB, Axis);

                MotorMass = mA + mB + iA * A1 * A1 + iB * A2 * A2;
                if (MotorMass > 0.0f)
                {
                    MotorMass = 1.0f / MotorMass;
                }
            }

            // Prismatic constraint.
            {
                Rot.MulToOutUnsafe(qA, LocalYAxisA, Perp);

                temp.Set(d).AddLocal(rA);
                S1 = Vec2.Cross(temp, Perp);
                S2 = Vec2.Cross(rB, Perp);

                float k11 = mA + mB + iA * S1 * S1 + iB * S2 * S2;
                float k12 = iA * S1 + iB * S2;
                float k13 = iA * S1 * A1 + iB * S2 * A2;
                float k22 = iA + iB;
                if (k22 == 0.0f)
                {
                    // For bodies with fixed rotation.
                    k22 = 1.0f;
                }
                float k23 = iA * A1 + iB * A2;
                float k33 = mA + mB + iA * A1 * A1 + iB * A2 * A2;

                K.Ex.Set(k11, k12, k13);
                K.Ey.Set(k12, k22, k23);
                K.Ez.Set(k13, k23, k33);
            }

            // Compute motor and limit terms.
            if (m_limitEnabled)
            {
                float jointTranslation = Vec2.Dot(Axis, d);
                if (MathUtils.Abs(UpperTranslation - LowerTranslation) < 2.0f * Settings.LINEAR_SLOP)
                {
                    LimitState = LimitState.Equal;
                }
                else if (jointTranslation <= LowerTranslation)
                {
                    if (LimitState != LimitState.AtLower)
                    {
                        LimitState = LimitState.AtLower;
                        Impulse.Z  = 0.0f;
                    }
                }
                else if (jointTranslation >= UpperTranslation)
                {
                    if (LimitState != LimitState.AtUpper)
                    {
                        LimitState = LimitState.AtUpper;
                        Impulse.Z  = 0.0f;
                    }
                }
                else
                {
                    LimitState = LimitState.Inactive;
                    Impulse.Z  = 0.0f;
                }
            }
            else
            {
                LimitState = LimitState.Inactive;
                Impulse.Z  = 0.0f;
            }

            if (m_motorEnabled == false)
            {
                MotorImpulse = 0.0f;
            }

            if (data.Step.WarmStarting)
            {
                // Account for variable time step.
                Impulse.MulLocal(data.Step.DtRatio);
                MotorImpulse *= data.Step.DtRatio;

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

                float LA = Impulse.X * S1 + Impulse.Y + (MotorImpulse + Impulse.Z) * A1;
                float LB = Impulse.X * S2 + Impulse.Y + (MotorImpulse + Impulse.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(1);
            }
            else
            {
                Impulse.SetZero();
                MotorImpulse = 0.0f;
            }

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

            Pool.PushRot(2);
            Pool.PushVec2(4);
        }
예제 #10
0
        public override bool SolvePositionConstraints(SolverData data)
        {
            Rot  qA   = Pool.PopRot();
            Rot  qB   = Pool.PopRot();
            Vec2 rA   = Pool.PopVec2();
            Vec2 rB   = Pool.PopVec2();
            Vec2 d    = Pool.PopVec2();
            Vec2 axis = Pool.PopVec2();
            Vec2 perp = Pool.PopVec2();
            Vec2 temp = Pool.PopVec2();
            Vec2 C1   = Pool.PopVec2();

            Vec3 impulse = Pool.PopVec3();

            Vec2  cA = data.Positions[IndexA].C;
            float aA = data.Positions[IndexA].A;
            Vec2  cB = data.Positions[IndexB].C;
            float aB = data.Positions[IndexB].A;

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

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

            // Compute fresh Jacobians
            Rot.MulToOutUnsafe(qA, temp.Set(LocalAnchorA).SubLocal(LocalCenterA), rA);
            Rot.MulToOutUnsafe(qB, temp.Set(LocalAnchorB).SubLocal(LocalCenterB), rB);
            d.Set(cB).AddLocal(rB).SubLocal(cA).SubLocal(rA);

            Rot.MulToOutUnsafe(qA, LocalXAxisA, axis);
            float a1 = Vec2.Cross(temp.Set(d).AddLocal(rA), axis);
            float a2 = Vec2.Cross(rB, axis);

            Rot.MulToOutUnsafe(qA, LocalYAxisA, perp);

            float s1 = Vec2.Cross(temp.Set(d).AddLocal(rA), perp);
            float s2 = Vec2.Cross(rB, perp);

            C1.X = Vec2.Dot(perp, d);
            C1.Y = aB - aA - ReferenceAngle;

            float linearError  = MathUtils.Abs(C1.X);
            float angularError = MathUtils.Abs(C1.Y);

            bool  active = false;
            float C2     = 0.0f;

            if (m_limitEnabled)
            {
                float translation = Vec2.Dot(axis, d);
                if (MathUtils.Abs(UpperTranslation - LowerTranslation) < 2.0f * Settings.LINEAR_SLOP)
                {
                    // Prevent large angular corrections
                    C2          = MathUtils.Clamp(translation, -Settings.MAX_LINEAR_CORRECTION, Settings.MAX_LINEAR_CORRECTION);
                    linearError = MathUtils.Max(linearError, MathUtils.Abs(translation));
                    active      = true;
                }
                else if (translation <= LowerTranslation)
                {
                    // Prevent large linear corrections and allow some slop.
                    C2          = MathUtils.Clamp(translation - LowerTranslation + Settings.LINEAR_SLOP, -Settings.MAX_LINEAR_CORRECTION, 0.0f);
                    linearError = MathUtils.Max(linearError, LowerTranslation - translation);
                    active      = true;
                }
                else if (translation >= UpperTranslation)
                {
                    // Prevent large linear corrections and allow some slop.
                    C2          = MathUtils.Clamp(translation - UpperTranslation - Settings.LINEAR_SLOP, 0.0f, Settings.MAX_LINEAR_CORRECTION);
                    linearError = MathUtils.Max(linearError, translation - UpperTranslation);
                    active      = true;
                }
            }

            if (active)
            {
                float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
                float k12 = iA * s1 + iB * s2;
                float k13 = iA * s1 * a1 + iB * s2 * a2;
                float k22 = iA + iB;
                if (k22 == 0.0f)
                {
                    // For fixed rotation
                    k22 = 1.0f;
                }
                float k23 = iA * a1 + iB * a2;
                float k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;

                Mat33 K = Pool.PopMat33();
                K.Ex.Set(k11, k12, k13);
                K.Ey.Set(k12, k22, k23);
                K.Ez.Set(k13, k23, k33);

                Vec3 C = Pool.PopVec3();
                C.X = C1.X;
                C.Y = C1.Y;
                C.Z = C2;

                K.Solve33ToOut(C.NegateLocal(), impulse);
                Pool.PushVec3(1);
                Pool.PushMat33(1);
            }
            else
            {
                float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
                float k12 = iA * s1 + iB * s2;
                float k22 = iA + iB;
                if (k22 == 0.0f)
                {
                    k22 = 1.0f;
                }

                Mat22 K = Pool.PopMat22();
                K.Ex.Set(k11, k12);
                K.Ey.Set(k12, k22);

                // temp is impulse1
                K.SolveToOut(C1.NegateLocal(), temp);
                C1.NegateLocal();

                impulse.X = temp.X;
                impulse.Y = temp.Y;
                impulse.Z = 0.0f;

                Pool.PushMat22(1);
            }

            float Px = impulse.X * perp.X + impulse.Z * axis.X;
            float Py = impulse.X * perp.Y + impulse.Z * axis.Y;
            float LA = impulse.X * s1 + impulse.Y + impulse.Z * a1;
            float LB = impulse.X * s2 + impulse.Y + impulse.Z * a2;

            cA.X -= mA * Px;
            cA.Y -= mA * Py;
            aA   -= iA * LA;
            cB.X += mB * Px;
            cB.Y += mB * Py;
            aB   += iB * LB;

            data.Positions[IndexA].C.Set(cA);
            data.Positions[IndexA].A = aA;
            data.Positions[IndexB].C.Set(cB);
            data.Positions[IndexB].A = aB;

            Pool.PushVec2(7);
            Pool.PushVec3(1);
            Pool.PushRot(2);

            return(linearError <= Settings.LINEAR_SLOP && angularError <= Settings.ANGULAR_SLOP);
        }
예제 #11
0
        internal override bool SolvePositionConstraints()
        {
            Vector2 cA  = _bodyA.GetRelativePoint(m_LocalCenterA);
            Vector2 cA0 = cA;
            float   aA  = _bodyA.rotation * Mathf.Deg2Rad;
            Vector2 cB  = _bodyB.GetRelativePoint(m_LocalCenterB);
            Vector2 cB0 = cB;
            float   aB  = _bodyB.rotation * Mathf.Deg2Rad;

            Rot qA = new Rot(aA), qB = new Rot(aB);

            float angularError = 0.0f;
            float positionError;

            bool fixedRotation = (m_InvIA + m_InvIB == 0.0f);

            // Solve angular limit constraint.
            if (m_EnableLimit && limitState != JointLimitState2D.Inactive && fixedRotation == false)
            {
                float angle        = aB - aA - referenceAngle;
                float limitImpulse = 0.0f;

                if (limitState == JointLimitState2D.EqualLimits)
                {
                    // Prevent large angular corrections
                    float C = Mathf.Clamp(angle - m_LowerAngle, -Constants.maxAngularCorrection, Constants.maxAngularCorrection);
                    limitImpulse = -m_MotorMass * C;
                    angularError = Mathf.Abs(C);
                }
                else if (limitState == JointLimitState2D.LowerLimit)
                {
                    float C = angle - m_LowerAngle;
                    angularError = -C;

                    // Prevent large angular corrections and allow some slop.
                    C            = Mathf.Clamp(C + Constants.angularSlop, -Constants.maxAngularCorrection, 0.0f);
                    limitImpulse = -m_MotorMass * C;
                }
                else if (limitState == JointLimitState2D.UpperLimit)
                {
                    float C = angle - m_UpperAngle;
                    angularError = C;

                    // Prevent large angular corrections and allow some slop.
                    C            = Mathf.Clamp(C - Constants.angularSlop, 0.0f, Constants.maxAngularCorrection);
                    limitImpulse = -m_MotorMass * C;
                }

                aA -= m_InvIA * limitImpulse;
                aB += m_InvIB * limitImpulse;
            }

            // Solve point-to-point constraint.
            {
                qA.Set(aA);
                qB.Set(aB);
                Vector2 rA = MathUtils.Mul(qA, _localAnchorA - m_LocalCenterA);
                Vector2 rB = MathUtils.Mul(qB, _localAnchorB - m_LocalCenterB);

                Vector2 C = cB + rB - cA - rA;
                positionError = C.magnitude;

                float mA = m_InvMassA, mB = m_InvMassB;
                float iA = m_InvIA, iB = m_InvIB;

                Mat22 K = new Mat22();
                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;

                Vector2 impulse = -K.Solve(C);

                cA -= mA * impulse;
                aA -= iA * MathUtils.Cross(rA, impulse);

                cB += mB * impulse;
                aB += iB * MathUtils.Cross(rB, impulse);
            }

            if (!_bodyA.isKinematic)
            {
                var dcA = cA0 - cA;
                _bodyA.position -= dcA;
                if (!_bodyA.fixedAngle)
                {
                    _bodyA.rotation = aA * Mathf.Rad2Deg;
                }
            }
            if (!_bodyB.isKinematic)
            {
                var dcB = cB0 - cB;
                _bodyB.position -= dcB;
                if (!_bodyB.fixedAngle)
                {
                    _bodyB.rotation = aB * Mathf.Rad2Deg;
                }
            }
            return(positionError <= Constants.linearSlop && angularError <= Constants.angularSlop);
        }
예제 #12
0
        public override void InitVelocityConstraints(SolverData data)
        {
            IndexA = BodyA.IslandIndex;
            IndexB = BodyB.IslandIndex;
            LocalCenterB.Set(BodyB.Sweep.LocalCenter);
            InvMassB = BodyB.InvMass;
            InvIB    = BodyB.InvI;

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

            Rot qB = Pool.PopRot();

            qB.Set(aB);

            float mass = BodyB.Mass;

            // Frequency
            float omega = 2.0f * MathUtils.PI * Frequency;

            // Damping coefficient
            float d = 2.0f * mass * DampingRatio * omega;

            // Spring stiffness
            float k = mass * (omega * omega);

            // magic formulas
            // gamma has units of inverse mass.
            // beta has units of inverse time.
            float h = data.Step.Dt;

            Debug.Assert(d + h * k > Settings.EPSILON);
            m_gamma = h * (d + h * k);
            if (m_gamma != 0.0f)
            {
                m_gamma = 1.0f / m_gamma;
            }
            m_beta = h * k * m_gamma;

            Vec2 temp = Pool.PopVec2();

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

            // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
            // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
            // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
            Mat22 K = Pool.PopMat22();

            K.Ex.X = InvMassB + InvIB * RB.Y * RB.Y + m_gamma;
            K.Ex.Y = (-InvIB) * RB.X * RB.Y;
            K.Ey.X = K.Ex.Y;
            K.Ey.Y = InvMassB + InvIB * RB.X * RB.X + m_gamma;

            K.InvertToOut(m_mass);

            m_C.Set(cB).AddLocal(RB).SubLocal(m_targetA);
            m_C.MulLocal(m_beta);

            // Cheat with some damping
            wB *= 0.98f;

            if (data.Step.WarmStarting)
            {
                m_impulse.MulLocal(data.Step.DtRatio);
                vB.X += InvMassB * m_impulse.X;
                vB.Y += InvMassB * m_impulse.Y;
                wB   += InvIB * Vec2.Cross(RB, m_impulse);
            }
            else
            {
                m_impulse.SetZero();
            }

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

            Pool.PushVec2(1);
            Pool.PushMat22(1);
            Pool.PushRot(1);
        }
예제 #13
0
        public override bool SolvePositionConstraints(SolverData data)
        {
            Rot   qA = Pool.PopRot();
            Rot   qB = Pool.PopRot();
            Vec2  cA = data.Positions[IndexA].C;
            float aA = data.Positions[IndexA].A;
            Vec2  cB = data.Positions[IndexB].C;
            float aB = data.Positions[IndexB].A;

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

            float angularError  = 0.0f;
            float positionError = 0.0f;

            bool fixedRotation = (InvIA + InvIB == 0.0f);

            // Solve angular limit constraint.
            if (m_limitEnabled && LimitState != LimitState.Inactive && fixedRotation == false)
            {
                float angle        = aB - aA - ReferenceAngle;
                float limitImpulse = 0.0f;

                if (LimitState == LimitState.Equal)
                {
                    // Prevent large angular corrections
                    float C = MathUtils.Clamp(angle - LowerAngle, -Settings.MAX_ANGULAR_CORRECTION, Settings.MAX_ANGULAR_CORRECTION);
                    limitImpulse = (-MotorMass) * C;
                    angularError = MathUtils.Abs(C);
                }
                else if (LimitState == LimitState.AtLower)
                {
                    float C = angle - LowerAngle;
                    angularError = -C;

                    // Prevent large angular corrections and allow some slop.
                    C            = MathUtils.Clamp(C + Settings.ANGULAR_SLOP, -Settings.MAX_ANGULAR_CORRECTION, 0.0f);
                    limitImpulse = (-MotorMass) * C;
                }
                else if (LimitState == LimitState.AtUpper)
                {
                    float C = angle - UpperAngle;
                    angularError = C;

                    // Prevent large angular corrections and allow some slop.
                    C            = MathUtils.Clamp(C - Settings.ANGULAR_SLOP, 0.0f, Settings.MAX_ANGULAR_CORRECTION);
                    limitImpulse = (-MotorMass) * C;
                }

                aA -= InvIA * limitImpulse;
                aB += InvIB * limitImpulse;
            }
            // Solve point-to-point constraint.
            {
                qA.Set(aA);
                qB.Set(aB);

                Vec2 rA      = Pool.PopVec2();
                Vec2 rB      = Pool.PopVec2();
                Vec2 C       = Pool.PopVec2();
                Vec2 impulse = Pool.PopVec2();

                Rot.MulToOutUnsafe(qA, C.Set(LocalAnchorA).SubLocal(LocalCenterA), rA);
                Rot.MulToOutUnsafe(qB, C.Set(LocalAnchorB).SubLocal(LocalCenterB), rB);
                C.Set(cB).AddLocal(rB).SubLocal(cA).SubLocal(rA);
                positionError = C.Length();

                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.SolveToOut(C, impulse);
                impulse.NegateLocal();

                cA.X -= mA * impulse.X;
                cA.Y -= mA * impulse.Y;
                aA   -= iA * Vec2.Cross(rA, impulse);

                cB.X += mB * impulse.X;
                cB.Y += mB * impulse.Y;
                aB   += iB * Vec2.Cross(rB, impulse);

                Pool.PushVec2(4);
                Pool.PushMat22(1);
            }
            data.Positions[IndexA].C.Set(cA);
            data.Positions[IndexA].A = aA;
            data.Positions[IndexB].C.Set(cB);
            data.Positions[IndexB].A = aB;

            Pool.PushRot(2);

            return(positionError <= Settings.LINEAR_SLOP && angularError <= Settings.ANGULAR_SLOP);
        }
예제 #14
0
        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;

            // Vec2 cA = data.positions[m_indexA].c;
            float aA = data.Positions[IndexA].A;
            Vec2  vA = data.Velocities[IndexA].V;
            float wA = data.Velocities[IndexA].W;

            // Vec2 cB = data.positions[m_indexB].c;
            float aB = data.Positions[IndexB].A;
            Vec2  vB = data.Velocities[IndexB].V;
            float wB = data.Velocities[IndexB].W;

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

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

            // Compute the effective masses.
            Rot.MulToOutUnsafe(qA, temp.Set(LocalAnchorA).SubLocal(LocalCenterA), RA);
            Rot.MulToOutUnsafe(qB, temp.Set(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;

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

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

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

            if (m_motorEnabled == false || fixedRotation)
            {
                MotorImpulse = 0.0f;
            }

            if (m_limitEnabled && fixedRotation == false)
            {
                float jointAngle = aB - aA - ReferenceAngle;
                if (MathUtils.Abs(UpperAngle - LowerAngle) < 2.0f * Settings.ANGULAR_SLOP)
                {
                    LimitState = LimitState.Equal;
                }
                else if (jointAngle <= LowerAngle)
                {
                    if (LimitState != LimitState.AtLower)
                    {
                        Impulse.Z = 0.0f;
                    }
                    LimitState = LimitState.AtLower;
                }
                else if (jointAngle >= UpperAngle)
                {
                    if (LimitState != LimitState.AtUpper)
                    {
                        Impulse.Z = 0.0f;
                    }
                    LimitState = LimitState.AtUpper;
                }
                else
                {
                    LimitState = LimitState.Inactive;
                    Impulse.Z  = 0.0f;
                }
            }
            else
            {
                LimitState = LimitState.Inactive;
            }

            if (data.Step.WarmStarting)
            {
                Vec2 P = Pool.PopVec2();
                // Scale impulses to support a variable time step.
                Impulse.X    *= data.Step.DtRatio;
                Impulse.Y    *= data.Step.DtRatio;
                MotorImpulse *= data.Step.DtRatio;

                P.X = Impulse.X;
                P.Y = Impulse.Y;

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

                vB.X += mB * P.X;
                vB.Y += mB * P.Y;
                wB   += iB * (Vec2.Cross(RB, P) + MotorImpulse + Impulse.Z);
                Pool.PushVec2(1);
            }
            else
            {
                Impulse.SetZero();
                MotorImpulse = 0.0f;
            }

            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);
            Pool.PushRot(2);
        }
예제 #15
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);
        }