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); }
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); }
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; }
/// <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); }
/// <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); }
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; }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
/// <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); }