예제 #1
0
        internal override bool SolvePositionConstraints(SolverData data)
        {
            var   cA = data.Positions[_indexA];
            float aA = data.Angles[_indexA];
            var   cB = data.Positions[_indexB];
            float aB = data.Angles[_indexB];

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

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

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

            // Solve angular limit constraint
            if (EnableLimit && fixedRotation == false)
            {
                float angle = aB - aA - ReferenceAngle;
                float C     = 0.0f;

                if (Math.Abs(UpperAngle - LowerAngle) < 2.0f * data.AngularSlop)
                {
                    // Prevent large angular corrections
                    C = Math.Clamp(angle - LowerAngle, -data.MaxAngularCorrection, data.MaxAngularCorrection);
                }
                else if (angle <= LowerAngle)
                {
                    // Prevent large angular corrections and allow some slop.
                    C = Math.Clamp(angle - LowerAngle + data.AngularSlop, -data.MaxAngularCorrection, 0.0f);
                }
                else if (angle >= UpperAngle)
                {
                    // Prevent large angular corrections and allow some slop.
                    C = Math.Clamp(angle - UpperAngle - data.AngularSlop, 0.0f, data.MaxAngularCorrection);
                }

                float limitImpulse = -_axialMass * C;
                aA          -= _invIA * limitImpulse;
                aB          += _invIB * limitImpulse;
                angularError = Math.Abs(C);
            }

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

                var C = cB + rB - cA - rA;
                positionError = C.Length;

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

                var K = new Matrix22(
                    mA + mB + iA * rA.Y * rA.Y + iB * rB.Y * rB.Y,
                    -iA * rA.X * rA.Y - iB * rB.X * rB.Y,
                    0f,
                    mA + mB + iA * rA.X * rA.X + iB * rB.X * rB.X);

                K.EY.X = K.EX.Y;

                var impulse = -K.Solve(C);

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

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

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

            return(positionError <= data.LinearSlop && angularError <= data.AngularSlop);
        }
예제 #2
0
        internal override void SolveVelocityConstraints(SolverData data)
        {
            var   vA = data.LinearVelocities[_indexA];
            float wA = data.AngularVelocities[_indexA];
            var   vB = data.LinearVelocities[_indexB];
            float wB = data.AngularVelocities[_indexB];

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

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

            // Solve motor constraint.
            if (EnableMotor && !fixedRotation)
            {
                float Cdot       = wB - wA - MotorSpeed;
                float impulse    = -_axialMass * Cdot;
                float oldImpulse = _motorImpulse;
                float maxImpulse = data.FrameTime * MaxMotorTorque;
                _motorImpulse = Math.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
                impulse       = _motorImpulse - oldImpulse;

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

            if (EnableLimit && fixedRotation == false)
            {
                // Lower limit
                {
                    float C          = _angle - LowerAngle;
                    float Cdot       = wB - wA;
                    float impulse    = -_axialMass * (Cdot + MathF.Max(C, 0.0f) * data.InvDt);
                    float oldImpulse = _lowerImpulse;
                    _lowerImpulse = MathF.Max(_lowerImpulse + impulse, 0.0f);
                    impulse       = _lowerImpulse - oldImpulse;

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

                // Upper limit
                // Note: signs are flipped to keep C positive when the constraint is satisfied.
                // This also keeps the impulse positive when the limit is active.
                {
                    float C          = UpperAngle - _angle;
                    float Cdot       = wA - wB;
                    float impulse    = -_axialMass * (Cdot + MathF.Max(C, 0.0f) * data.InvDt);
                    float oldImpulse = _upperImpulse;
                    _upperImpulse = MathF.Max(_upperImpulse + impulse, 0.0f);
                    impulse       = _upperImpulse - oldImpulse;

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

            // Solve point-to-point constraint
            {
                var Cdot    = vB + Vector2.Cross(wB, _rB) - vA - Vector2.Cross(wA, _rA);
                var impulse = _K.Solve(-Cdot);

                _impulse.X += impulse.X;
                _impulse.Y += impulse.Y;

                vA -= impulse * mA;
                wA -= iA * Vector2.Cross(_rA, impulse);

                vB += impulse * mB;
                wB += iB * Vector2.Cross(_rB, impulse);
            }

            data.LinearVelocities[_indexA]  = vA;
            data.AngularVelocities[_indexA] = wA;
            data.LinearVelocities[_indexB]  = vB;
            data.AngularVelocities[_indexB] = wB;
        }