internal override void InitVelocityConstraints(ref SolverData data) { _jointError = BodyA.Sweep.A - TargetAngle; _bias = -BiasFactor * data.step.inv_dt * _jointError; _massFactor = (1 - Softness) / (BodyA.InvI); }
internal override void SolveVelocityConstraints(ref SolverData data) { //GABS: NOT A BOTTLENECK float p = (_bias - BodyB.AngularVelocity + BodyA.AngularVelocity) * _massFactor; BodyA.AngularVelocity -= BodyA.InvI * Math.Sign(p) * Math.Min(Math.Abs(p), MaxImpulse); BodyB.AngularVelocity += BodyB.InvI * Math.Sign(p) * Math.Min(Math.Abs(p), MaxImpulse); }
internal override void InitVelocityConstraints(ref SolverData data) { Body b1 = BodyA; Body b2 = BodyB; Transform xf1, xf2; b1.GetTransform(out xf1); b2.GetTransform(out xf2); // Compute the effective mass matrix. FVector2 r1 = MathUtils.Mul(ref xf1.q, LocalAnchorA - b1.LocalCenter); FVector2 r2 = MathUtils.Mul(ref xf2.q, LocalAnchorB - b2.LocalCenter); _u = b2.Sweep.C + r2 - b1.Sweep.C - r1; // Handle singularity. float length = _u.Length(); if (length < MaxLength && length > MinLength) { return; } if (length > Settings.LinearSlop) { _u *= 1.0f / length; } else { _u = FVector2.Zero; } float cr1u = MathUtils.Cross(r1, _u); float cr2u = MathUtils.Cross(r2, _u); float invMass = b1.InvMass + b1.InvI * cr1u * cr1u + b2.InvMass + b2.InvI * cr2u * cr2u; Debug.Assert(invMass > Settings.Epsilon); _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; if (Frequency > 0.0f) { float C = length - MaxLength; // Frequency float omega = 2.0f * Settings.Pi * Frequency; // Damping coefficient float d = 2.0f * _mass * DampingRatio * omega; // Spring stiffness float k = _mass * omega * omega; // magic formulas _gamma = data.step.dt * (d + data.step.dt * k); _gamma = _gamma != 0.0f ? 1.0f / _gamma : 0.0f; _bias = C * data.step.dt * k * _gamma; _mass = invMass + _gamma; _mass = _mass != 0.0f ? 1.0f / _mass : 0.0f; } if (Settings.EnableWarmstarting) { // Scale the impulse to support a variable time step. _impulse *= data.step.dtRatio; FVector2 P = _impulse * _u; b1.LinearVelocityInternal -= b1.InvMass * P; b1.AngularVelocityInternal -= b1.InvI * MathUtils.Cross(r1, P); b2.LinearVelocityInternal += b2.InvMass * P; b2.AngularVelocityInternal += b2.InvI * MathUtils.Cross(r2, P); } else { _impulse = 0.0f; } }
public override void solveVelocityConstraints(SolverData data) { Vec2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vec2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; Vec2 temp = pool.popVec2(); // Solve linear motor constraint. if (m_enableMotor && m_limitState != LimitState.EQUAL) { temp.set_Renamed(vB).subLocal(vA); float Cdot = Vec2.dot(m_axis, temp) + m_a2 * wB - m_a1 * wA; float impulse = m_motorMass * (m_motorSpeed - Cdot); float oldImpulse = m_motorImpulse; float maxImpulse = data.step.dt * m_maxMotorForce; m_motorImpulse = MathUtils.clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; Vec2 P = pool.popVec2(); P.set_Renamed(m_axis).mulLocal(impulse); float LA = impulse * m_a1; float LB = impulse * m_a2; vA.x -= mA * P.x; vA.y -= mA * P.y; wA -= iA * LA; vB.x += mB * P.x; vB.y += mB * P.y; wB += iB * LB; pool.pushVec2(1); } Vec2 Cdot1 = pool.popVec2(); temp.set_Renamed(vB).subLocal(vA); Cdot1.x = Vec2.dot(m_perp, temp) + m_s2 * wB - m_s1 * wA; Cdot1.y = wB - wA; // System.out.println(Cdot1); if (m_enableLimit && m_limitState != LimitState.INACTIVE) { // Solve prismatic and limit constraint in block form. float Cdot2; temp.set_Renamed(vB).subLocal(vA); Cdot2 = Vec2.dot(m_axis, temp) + m_a2 * wB - m_a1 * wA; Vec3 Cdot = pool.popVec3(); Cdot.set_Renamed(Cdot1.x, Cdot1.y, Cdot2); Cdot.negateLocal(); Vec3 f1 = pool.popVec3(); Vec3 df = pool.popVec3(); f1.set_Renamed(m_impulse); m_K.solve33ToOut(Cdot.negateLocal(), df); //Cdot.negateLocal(); not used anymore m_impulse.addLocal(df); if (m_limitState == LimitState.AT_LOWER) { m_impulse.z = MathUtils.max(m_impulse.z, 0.0f); } else if (m_limitState == LimitState.AT_UPPER) { m_impulse.z = MathUtils.min(m_impulse.z, 0.0f); } // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + // f1(1:2) Vec2 b = pool.popVec2(); Vec2 f2r = pool.popVec2(); temp.set_Renamed(m_K.ez.x, m_K.ez.y).mulLocal(m_impulse.z - f1.z); b.set_Renamed(Cdot1).negateLocal().subLocal(temp); temp.set_Renamed(f1.x, f1.y); m_K.solve22ToOut(b, f2r); f2r.addLocal(temp); m_impulse.x = f2r.x; m_impulse.y = f2r.y; df.set_Renamed(m_impulse).subLocal(f1); Vec2 P = pool.popVec2(); temp.set_Renamed(m_axis).mulLocal(df.z); P.set_Renamed(m_perp).mulLocal(df.x).addLocal(temp); float LA = df.x * m_s1 + df.y + df.z * m_a1; float LB = df.x * m_s2 + df.y + df.z * m_a2; vA.x -= mA * P.x; vA.y -= mA * P.y; wA -= iA * LA; vB.x += mB * P.x; vB.y += mB * P.y; wB += iB * LB; pool.pushVec2(3); pool.pushVec3(3); } else { // Limit is inactive, just solve the prismatic constraint in block form. Vec2 df = pool.popVec2(); m_K.solve22ToOut(Cdot1.negateLocal(), df); Cdot1.negateLocal(); m_impulse.x += df.x; m_impulse.y += df.y; Vec2 P = pool.popVec2(); P.set_Renamed(m_perp).mulLocal(df.x); float LA = df.x * m_s1 + df.y; float LB = df.x * m_s2 + df.y; vA.x -= mA * P.x; vA.y -= mA * P.y; wA -= iA * LA; vB.x += mB * P.x; vB.y += mB * P.y; wB += iB * LB; Vec2 Cdot10 = pool.popVec2(); Cdot10.set_Renamed(Cdot1); Cdot1.x = Vec2.dot(m_perp, temp.set_Renamed(vB).subLocal(vA)) + m_s2 * wB - m_s1 * wA; Cdot1.y = wB - wA; if (MathUtils.abs(Cdot1.x) > 0.01f || MathUtils.abs(Cdot1.y) > 0.01f) { // djm note: what's happening here? Mat33.mul22ToOutUnsafe(m_K, df, temp); Cdot1.x += 0.0f; } pool.pushVec2(3); } data.velocities[m_indexA].v.set_Renamed(vA); data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v.set_Renamed(vB); data.velocities[m_indexB].w = wB; pool.pushVec2(2); }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; Vector2 cA = data.Positions[_indexA].C; float aA = data.Positions[_indexA].A; Vector2 vA = data.Velocities[_indexA].V; float wA = data.Velocities[_indexA].W; Vector2 cB = data.Positions[_indexB].C; float aB = data.Positions[_indexB].A; Vector2 vB = data.Velocities[_indexB].V; float wB = data.Velocities[_indexB].W; Rot qA = new Rot(aA), qB = new Rot(aB); // Compute the effective masses. Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); Vector2 d1 = cB + rB - cA - rA; // Point to line constraint { _ay = MathUtils.Mul(qA, _localYAxis); _sAy = MathUtils.Cross(d1 + rA, _ay); _sBy = MathUtils.Cross(rB, _ay); _mass = mA + mB + iA * _sAy * _sAy + iB * _sBy * _sBy; if (_mass > 0.0f) { _mass = 1.0f / _mass; } } // Spring constraint _springMass = 0.0f; _bias = 0.0f; _gamma = 0.0f; if (Frequency > 0.0f) { _ax = MathUtils.Mul(qA, LocalXAxis); _sAx = MathUtils.Cross(d1 + rA, _ax); _sBx = MathUtils.Cross(rB, _ax); float invMass = mA + mB + iA * _sAx * _sAx + iB * _sBx * _sBx; if (invMass > 0.0f) { _springMass = 1.0f / invMass; float C = Vector2.Dot(d1, _ax); // Frequency float omega = 2.0f * Settings.Pi * Frequency; // Damping coefficient float d = 2.0f * _springMass * DampingRatio * omega; // Spring stiffness float k = _springMass * omega * omega; // magic formulas float h = data.Step.dt; _gamma = h * (d + h * k); if (_gamma > 0.0f) { _gamma = 1.0f / _gamma; } _bias = C * h * k * _gamma; _springMass = invMass + _gamma; if (_springMass > 0.0f) { _springMass = 1.0f / _springMass; } } } else { _springImpulse = 0.0f; } // Rotational motor if (_enableMotor) { _motorMass = iA + iB; if (_motorMass > 0.0f) { _motorMass = 1.0f / _motorMass; } } else { _motorMass = 0.0f; _motorImpulse = 0.0f; } #pragma warning disable 162 // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (Settings.EnableWarmstarting) { // Account for variable time step. _impulse *= data.Step.dtRatio; _springImpulse *= data.Step.dtRatio; _motorImpulse *= data.Step.dtRatio; Vector2 P = _impulse * _ay + _springImpulse * _ax; float LA = _impulse * _sAy + _springImpulse * _sAx + _motorImpulse; float LB = _impulse * _sBy + _springImpulse * _sBx + _motorImpulse; vA -= _invMassA * P; wA -= _invIA * LA; vB += _invMassB * P; wB += _invIB * LB; } else { _impulse = 0.0f; _springImpulse = 0.0f; _motorImpulse = 0.0f; } #pragma warning restore 162 data.Velocities[_indexA].V = vA; data.Velocities[_indexA].W = wA; data.Velocities[_indexB].V = vB; data.Velocities[_indexB].W = wB; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA.Sweep.LocalCenter; _localCenterB = BodyB.Sweep.LocalCenter; _invMassA = BodyA.InvMass; _invMassB = BodyB.InvMass; _invIA = BodyA.InvI; _invIB = BodyB.InvI; Vector2 cA = data.positions[_indexA].c; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 cB = data.positions[_indexB].c; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Rot qA = new Rot(aA), qB = new Rot(aB); _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); _u = cB + _rB - cA - _rA; _length = _u.Length(); float C = _length - MaxLength; if (C > 0.0f) { _state = LimitState.AtUpper; } else { _state = LimitState.Inactive; } if (_length > Settings.LinearSlop) { _u *= 1.0f / _length; } else { _u = Vector2.Zero; _mass = 0.0f; _impulse = 0.0f; return; } // Compute effective mass. float crA = MathUtils.Cross(_rA, _u); float crB = MathUtils.Cross(_rB, _u); float invMass = _invMassA + _invIA * crA * crA + _invMassB + _invIB * crB * crB; _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; if (Settings.EnableWarmstarting) { // Scale the impulse to support a variable time step. _impulse *= data.step.dtRatio; Vector2 P = _impulse * _u; vA -= _invMassA * P; wA -= _invIA * MathUtils.Cross(_rA, P); vB += _invMassB * P; wB += _invIB * MathUtils.Cross(_rB, P); } else { _impulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
internal override bool SolvePositionConstraints(ref SolverData data) { if (Frequency > 0.0f) { // There is no position correction for soft distance constraints. return true; } Body b1 = BodyA; Body b2 = BodyB; Transform xf1, xf2; b1.GetTransform(out xf1); b2.GetTransform(out xf2); Vector2 r1 = MathUtils.Mul(ref xf1.q, LocalAnchorA - b1.LocalCenter); Vector2 r2 = MathUtils.Mul(ref xf2.q, LocalAnchorB - b2.LocalCenter); Vector2 d = b2.Sweep.C + r2 - b1.Sweep.C - r1; float length = d.Length(); if (length < MaxLength && length > MinLength) { return true; } if (length == 0.0f) return true; d /= length; float C = length - MaxLength; C = MathUtils.Clamp(C, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection); float impulse = -_mass * C; _u = d; Vector2 P = impulse * _u; b1.Sweep.C -= b1.InvMass * P; b1.Sweep.A -= b1.InvI * MathUtils.Cross(r1, P); b2.Sweep.C += b2.InvMass * P; b2.Sweep.A += b2.InvI * MathUtils.Cross(r2, P); b1.SynchronizeTransform(); b2.SynchronizeTransform(); return Math.Abs(C) < Settings.LinearSlop; }
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(); qA.set(aA); qB.set(aB); temp.set(m_localAnchorA); temp.subLocal(m_localCenterA); Rot.mulToOut(qA, temp, ref rA); temp.set(m_localAnchorB); temp.subLocal(m_localCenterB); Rot.mulToOut(qB, temp , ref rB); d.set(cB); d.subLocal(cA); d.addLocal(rB); d.subLocal(rA); Vec2 ay = pool.popVec2(); Rot.mulToOut(qA, m_localYAxisA, ref ay); temp.set(d); temp.addLocal(rA); float sAy = Vec2.cross(temp, ay); float sBy = Vec2.cross(rB, ay); float C = Vec2.dot(d, ay); float k = m_invMassA + m_invMassB + m_invIA*m_sAy*m_sAy + m_invIB*m_sBy*m_sBy; float impulse; if (k != 0.0f) { impulse = -C/k; } else { impulse = 0.0f; } Vec2 P = pool.popVec2(); P.x = impulse*ay.x; P.y = impulse*ay.y; float LA = impulse*sAy; float LB = impulse*sBy; cA.x -= m_invMassA*P.x; cA.y -= m_invMassA*P.y; aA -= m_invIA*LA; cB.x += m_invMassB*P.x; cB.y += m_invMassB*P.y; aB += m_invIB*LB; pool.pushVec2(3); pool.pushRot(2); // 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 MathUtils.abs(C) <= Settings.linearSlop; }
internal override void SolveVelocityConstraints(ref SolverData data) { Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Vector2 vC = data.velocities[_indexC].v; float wC = data.velocities[_indexC].w; Vector2 vD = data.velocities[_indexD].v; float wD = data.velocities[_indexD].w; float Cdot = Vector2.Dot(_JvAC, vA - vC) + Vector2.Dot(_JvBD, vB - vD); Cdot += (_JwA * wA - _JwC * wC) + (_JwB * wB - _JwD * wD); float impulse = -_mass * Cdot; _impulse += impulse; vA += (_mA * impulse) * _JvAC; wA += _iA * impulse * _JwA; vB += (_mB * impulse) * _JvBD; wB += _iB * impulse * _JwB; vC -= (_mC * impulse) * _JvAC; wC -= _iC * impulse * _JwC; vD -= (_mD * impulse) * _JvBD; wD -= _iD * impulse * _JwD; data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; data.velocities[_indexC].v = vC; data.velocities[_indexC].w = wC; data.velocities[_indexD].v = vD; data.velocities[_indexD].w = wD; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; Vector2 cA = data.positions[_indexA].c; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 cB = data.positions[_indexB].c; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Complex qA = Complex.FromAngle(aA); Complex qB = Complex.FromAngle(aB); _rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA); _rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB); // Get the pulley axes. _uA = cA + _rA - WorldAnchorA; _uB = cB + _rB - WorldAnchorB; float lengthA = _uA.Length(); float lengthB = _uB.Length(); if (lengthA > 10.0f * Settings.LinearSlop) { _uA *= 1.0f / lengthA; } else { _uA = Vector2.Zero; } if (lengthB > 10.0f * Settings.LinearSlop) { _uB *= 1.0f / lengthB; } else { _uB = Vector2.Zero; } // Compute effective mass. float ruA = MathUtils.Cross(ref _rA, ref _uA); float ruB = MathUtils.Cross(ref _rB, ref _uB); float mA = _invMassA + _invIA * ruA * ruA; float mB = _invMassB + _invIB * ruB * ruB; _mass = mA + Ratio * Ratio * mB; if (_mass > 0.0f) { _mass = 1.0f / _mass; } if (data.step.warmStarting) { // Scale impulses to support variable time steps. _impulse *= data.step.dtRatio; // Warm starting. Vector2 PA = -(_impulse) * _uA; Vector2 PB = (-Ratio * _impulse) * _uB; vA += _invMassA * PA; wA += _invIA * MathUtils.Cross(ref _rA, ref PA); vB += _invMassB * PB; wB += _invIB * MathUtils.Cross(ref _rB, ref PB); } else { _impulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
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; Complex qA = Complex.FromAngle(aA); Complex qB = Complex.FromAngle(aB); Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA); Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB); // Get the pulley axes. Vector2 uA = cA + rA - WorldAnchorA; Vector2 uB = cB + rB - WorldAnchorB; float lengthA = uA.Length(); float lengthB = uB.Length(); if (lengthA > 10.0f * Settings.LinearSlop) { uA *= 1.0f / lengthA; } else { uA = Vector2.Zero; } if (lengthB > 10.0f * Settings.LinearSlop) { uB *= 1.0f / lengthB; } else { uB = Vector2.Zero; } // Compute effective mass. float ruA = MathUtils.Cross(ref rA, ref uA); float ruB = MathUtils.Cross(ref rB, ref uB); float mA = _invMassA + _invIA * ruA * ruA; float mB = _invMassB + _invIB * ruB * ruB; float mass = mA + Ratio * Ratio * mB; if (mass > 0.0f) { mass = 1.0f / mass; } float C = Constant - lengthA - Ratio * lengthB; float linearError = Math.Abs(C); float impulse = -mass * C; Vector2 PA = -impulse * uA; Vector2 PB = -Ratio * impulse * uB; cA += _invMassA * PA; aA += _invIA * MathUtils.Cross(ref rA, ref PA); cB += _invMassB * PB; aB += _invIB * MathUtils.Cross(ref rB, ref PB); data.positions[_indexA].c = cA; data.positions[_indexA].a = aA; data.positions[_indexB].c = cB; data.positions[_indexB].a = aB; return(linearError < Settings.LinearSlop); }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; Vector2 cA = data.positions[_indexA].c; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 cB = data.positions[_indexB].c; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Complex qA = Complex.FromAngle(aA); Complex qB = Complex.FromAngle(aB); // Compute the effective masses. Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA); Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB); Vector2 d1 = cB + rB - cA - rA; // Point to line constraint { _ay = Complex.Multiply(ref _localYAxis, ref qA); _sAy = MathUtils.Cross(d1 + rA, _ay); _sBy = MathUtils.Cross(ref rB, ref _ay); _mass = mA + mB + iA * _sAy * _sAy + iB * _sBy * _sBy; if (_mass > 0.0f) { _mass = 1.0f / _mass; } } // Spring constraint _springMass = 0.0f; _bias = 0.0f; _gamma = 0.0f; if (Frequency > 0.0f) { _ax = Complex.Multiply(ref _localXAxis, ref qA); _sAx = MathUtils.Cross(d1 + rA, _ax); _sBx = MathUtils.Cross(ref rB, ref _ax); float invMass = mA + mB + iA * _sAx * _sAx + iB * _sBx * _sBx; if (invMass > 0.0f) { _springMass = 1.0f / invMass; float C = Vector2.Dot(d1, _ax); // Frequency float omega = 2.0f * MathHelper.Pi * Frequency; // Damping coefficient float d = 2.0f * _springMass * DampingRatio * omega; // Spring stiffness float k = _springMass * omega * omega; // magic formulas float h = data.step.dt; _gamma = h * (d + h * k); if (_gamma > 0.0f) { _gamma = 1.0f / _gamma; } _bias = C * h * k * _gamma; _springMass = invMass + _gamma; if (_springMass > 0.0f) { _springMass = 1.0f / _springMass; } } } else { _springImpulse = 0.0f; } // Rotational motor if (_enableMotor) { _motorMass = iA + iB; if (_motorMass > 0.0f) { _motorMass = 1.0f / _motorMass; } } else { _motorMass = 0.0f; _motorImpulse = 0.0f; } if (data.step.warmStarting) { // Account for variable time step. _impulse *= data.step.dtRatio; _springImpulse *= data.step.dtRatio; _motorImpulse *= data.step.dtRatio; Vector2 P = _impulse * _ay + _springImpulse * _ax; float LA = _impulse * _sAy + _springImpulse * _sAx + _motorImpulse; float LB = _impulse * _sBy + _springImpulse * _sBx + _motorImpulse; vA -= _invMassA * P; wA -= _invIA * LA; vB += _invMassB * P; wB += _invIB * LB; } else { _impulse = 0.0f; _springImpulse = 0.0f; _motorImpulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; Vector2 cA = data.Positions[_indexA].C; float aA = data.Positions[_indexA].A; Vector2 vA = data.Velocities[_indexA].V; float wA = data.Velocities[_indexA].W; Vector2 cB = data.Positions[_indexB].C; float aB = data.Positions[_indexB].A; Vector2 vB = data.Velocities[_indexB].V; float wB = data.Velocities[_indexB].W; Rot qA = new Rot(aA), qB = new Rot(aB); _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); // Get the pulley axes. _uA = cA + _rA - WorldAnchorA; _uB = cB + _rB - WorldAnchorB; float lengthA = _uA.Length(); float lengthB = _uB.Length(); if (lengthA > 10.0f * Settings.LinearSlop) { _uA *= 1.0f / lengthA; } else { _uA = Vector2.Zero; } if (lengthB > 10.0f * Settings.LinearSlop) { _uB *= 1.0f / lengthB; } else { _uB = Vector2.Zero; } // Compute effective mass. float ruA = MathUtils.Cross(_rA, _uA); float ruB = MathUtils.Cross(_rB, _uB); float mA = _invMassA + _invIA * ruA * ruA; float mB = _invMassB + _invIB * ruB * ruB; _mass = mA + Ratio * Ratio * mB; if (_mass > 0.0f) { _mass = 1.0f / _mass; } if (Settings.EnableWarmstarting) { // Scale impulses to support variable time steps. _impulse *= data.Step.DeltaTimeRatio; // Warm starting. Vector2 PA = -(_impulse) * _uA; Vector2 PB = (-Ratio * _impulse) * _uB; vA += _invMassA * PA; wA += _invIA * MathUtils.Cross(_rA, PA); vB += _invMassB * PB; wB += _invIB * MathUtils.Cross(_rB, PB); } else { _impulse = 0.0f; } data.Velocities[_indexA].V = vA; data.Velocities[_indexA].W = wA; data.Velocities[_indexB].V = vB; data.Velocities[_indexB].W = wB; }
public override bool SolvePositionConstraints(SolverData data) { return(true); }
public override void SolveVelocityConstraints(SolverData data) { Vec2 vA = data.Velocities[IndexA].V; float wA = data.Velocities[IndexA].W; Vec2 vB = data.Velocities[IndexB].V; float wB = data.Velocities[IndexB].W; float mA = InvMassA, mB = InvMassB; float iA = InvIA, iB = InvIB; float h = data.Step.Dt; // Solve angular friction { float Cdot = wB - wA; float impulse = (-AngularMass) * Cdot; float oldImpulse = m_angularImpulse; float maxImpulse = h * m_maxTorque; m_angularImpulse = MathUtils.Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_angularImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve linear friction { Vec2 Cdot = Pool.PopVec2(); Vec2 temp = Pool.PopVec2(); Vec2.CrossToOutUnsafe(wA, RA, temp); Vec2.CrossToOutUnsafe(wB, RB, Cdot); Cdot.AddLocal(vB).SubLocal(vA).SubLocal(temp); Vec2 impulse = Pool.PopVec2(); Mat22.MulToOutUnsafe(LinearMass, Cdot, impulse); impulse.NegateLocal(); Vec2 oldImpulse = Pool.PopVec2(); oldImpulse.Set(m_linearImpulse); m_linearImpulse.AddLocal(impulse); float maxImpulse = h * m_maxForce; if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) { m_linearImpulse.Normalize(); m_linearImpulse.MulLocal(maxImpulse); } impulse.Set(m_linearImpulse).SubLocal(oldImpulse); temp.Set(impulse).MulLocal(mA); vA.SubLocal(temp); wA -= iA * Vec2.Cross(RA, impulse); temp.Set(impulse).MulLocal(mB); vB.AddLocal(temp); wB += iB * Vec2.Cross(RB, impulse); } data.Velocities[IndexA].V.Set(vA); if (data.Velocities[IndexA].W != wA) { Debug.Assert(data.Velocities[IndexA].W != wA); } data.Velocities[IndexA].W = wA; data.Velocities[IndexB].V.Set(vB); data.Velocities[IndexB].W = wB; Pool.PushVec2(4); }
/// <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); }
public override void initVelocityConstraints(SolverData data) { m_indexA = m_bodyA.m_islandIndex; m_indexB = m_bodyB.m_islandIndex; m_localCenterA.set(m_bodyA.m_sweep.localCenter); m_localCenterB.set(m_bodyB.m_sweep.localCenter); m_invMassA = m_bodyA.m_invMass; m_invMassB = m_bodyB.m_invMass; m_invIA = m_bodyA.m_invI; m_invIB = m_bodyB.m_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. temp.set(m_localAnchorA); temp.subLocal(m_localCenterA); Rot.mulToOutUnsafe(qA, temp, ref m_rA); temp.set(m_localAnchorB); temp.subLocal(m_localCenterB); Rot.mulToOutUnsafe(qB, temp, ref 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; bool fixedRotation = (iA + iB == 0.0f); m_mass.ex.x = mA + mB + m_rA.y*m_rA.y*iA + m_rB.y*m_rB.y*iB; m_mass.ey.x = -m_rA.y*m_rA.x*iA - m_rB.y*m_rB.x*iB; m_mass.ez.x = -m_rA.y*iA - m_rB.y*iB; m_mass.ex.y = m_mass.ey.x; m_mass.ey.y = mA + mB + m_rA.x*m_rA.x*iA + m_rB.x*m_rB.x*iB; m_mass.ez.y = m_rA.x*iA + m_rB.x*iB; m_mass.ex.z = m_mass.ez.x; m_mass.ey.z = m_mass.ez.y; m_mass.ez.z = iA + iB; m_motorMass = iA + iB; if (m_motorMass > 0.0f) { m_motorMass = 1.0f/m_motorMass; } if (m_enableMotor == false || fixedRotation) { m_motorImpulse = 0.0f; } if (m_enableLimit && fixedRotation == false) { float jointAngle = aB - aA - m_referenceAngle; if (MathUtils.abs(m_upperAngle - m_lowerAngle) < 2.0f*Settings.angularSlop) { m_limitState = LimitState.EQUAL; } else if (jointAngle <= m_lowerAngle) { if (m_limitState != LimitState.AT_LOWER) { m_impulse.z = 0.0f; } m_limitState = LimitState.AT_LOWER; } else if (jointAngle >= m_upperAngle) { if (m_limitState != LimitState.AT_UPPER) { m_impulse.z = 0.0f; } m_limitState = LimitState.AT_UPPER; } else { m_limitState = LimitState.INACTIVE; m_impulse.z = 0.0f; } } else { m_limitState = LimitState.INACTIVE; } if (data.step.warmStarting) { Vec2 P = pool.popVec2(); // Scale impulses to support a variable time step. m_impulse.x *= data.step.dtRatio; m_impulse.y *= data.step.dtRatio; m_motorImpulse *= data.step.dtRatio; P.x = m_impulse.x; P.y = m_impulse.y; vA.x -= mA*P.x; vA.y -= mA*P.y; wA -= iA*(Vec2.cross(m_rA, P) + m_motorImpulse + m_impulse.z); vB.x += mB*P.x; vB.y += mB*P.y; wB += iB*(Vec2.cross(m_rB, P) + m_motorImpulse + m_impulse.z); pool.pushVec2(1); } else { m_impulse.setZero(); m_motorImpulse = 0.0f; } // 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); }
internal override void InitVelocityConstraints(ref SolverData data) { m_indexA = BodyA.IslandIndex; m_indexB = BodyB.IslandIndex; m_localCenterA = BodyA.Sweep.LocalCenter; m_localCenterB = BodyB.Sweep.LocalCenter; m_invMassA = BodyA.InvMass; m_invMassB = BodyB.InvMass; m_invIA = BodyA.InvI; m_invIB = BodyB.InvI; float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; Vector2 cA = data.positions[m_indexA].c; float aA = data.positions[m_indexA].a; Vector2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vector2 cB = data.positions[m_indexB].c; float aB = data.positions[m_indexB].a; Vector2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; Rot qA = new Rot(aA), qB = new Rot(aB); // Compute the effective masses. Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - m_localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - m_localCenterB); Vector2 d1 = cB + rB - cA - rA; // Point to line constraint { m_ay = MathUtils.Mul(qA, m_localYAxisA); m_sAy = MathUtils.Cross(d1 + rA, m_ay); m_sBy = MathUtils.Cross(rB, m_ay); m_mass = mA + mB + iA * m_sAy * m_sAy + iB * m_sBy * m_sBy; if (m_mass > 0.0f) { m_mass = 1.0f / m_mass; } } // Spring constraint m_springMass = 0.0f; m_bias = 0.0f; m_gamma = 0.0f; if (SpringFrequencyHz > 0.0f) { m_ax = MathUtils.Mul(qA, m_localXAxisA); m_sAx = MathUtils.Cross(d1 + rA, m_ax); m_sBx = MathUtils.Cross(rB, m_ax); float invMass = mA + mB + iA * m_sAx * m_sAx + iB * m_sBx * m_sBx; if (invMass > 0.0f) { m_springMass = 1.0f / invMass; float C = Vector2.Dot(d1, m_ax); // Frequency float omega = 2.0f * Settings.Pi * SpringFrequencyHz; // Damping coefficient float d = 2.0f * m_springMass * SpringDampingRatio * omega; // Spring stiffness float k = m_springMass * omega * omega; // magic formulas float h = data.step.dt; m_gamma = h * (d + h * k); if (m_gamma > 0.0f) { m_gamma = 1.0f / m_gamma; } m_bias = C * h * k * m_gamma; m_springMass = invMass + m_gamma; if (m_springMass > 0.0f) { m_springMass = 1.0f / m_springMass; } } } else { m_springImpulse = 0.0f; } // Rotational motor if (m_enableMotor) { m_motorMass = iA + iB; if (m_motorMass > 0.0f) { m_motorMass = 1.0f / m_motorMass; } } else { m_motorMass = 0.0f; m_motorImpulse = 0.0f; } if (Settings.EnableWarmstarting) { // Account for variable time step. m_impulse *= data.step.dtRatio; m_springImpulse *= data.step.dtRatio; m_motorImpulse *= data.step.dtRatio; Vector2 P = m_impulse * m_ay + m_springImpulse * m_ax; float LA = m_impulse * m_sAy + m_springImpulse * m_sAx + m_motorImpulse; float LB = m_impulse * m_sBy + m_springImpulse * m_sBx + m_motorImpulse; vA -= m_invMassA * P; wA -= m_invIA * LA; vB += m_invMassB * P; wB += m_invIB * LB; } else { m_impulse = 0.0f; m_springImpulse = 0.0f; m_motorImpulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; }
public override void solveVelocityConstraints(SolverData data) { Vec2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vec2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; bool fixedRotation = (iA + iB == 0.0f); // Solve motor constraint. if (m_enableMotor && m_limitState != LimitState.EQUAL && fixedRotation == false) { float Cdot = wB - wA - m_motorSpeed; float impulse = -m_motorMass*Cdot; float oldImpulse = m_motorImpulse; float maxImpulse = data.step.dt*m_maxMotorTorque; m_motorImpulse = MathUtils.clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; wA -= iA*impulse; wB += iB*impulse; } Vec2 temp = pool.popVec2(); // Solve limit constraint. if (m_enableLimit && m_limitState != LimitState.INACTIVE && fixedRotation == false) { Vec2 Cdot1 = pool.popVec2(); Vec3 Cdot = pool.popVec3(); // Solve point-to-point constraint Vec2.crossToOutUnsafe(wA, m_rA, ref temp); Vec2.crossToOutUnsafe(wB, m_rB, ref Cdot1); Cdot1.addLocal(vB); Cdot1.subLocal(vA); Cdot1.subLocal(temp); float Cdot2 = wB - wA; Cdot.set(Cdot1.x, Cdot1.y, Cdot2); Vec3 impulse = pool.popVec3(); m_mass.solve33ToOut(Cdot, ref impulse); impulse.negateLocal(); if (m_limitState == LimitState.EQUAL) { m_impulse.addLocal(impulse); } else if (m_limitState == LimitState.AT_LOWER) { float newImpulse = m_impulse.z + impulse.z; if (newImpulse < 0.0f) { Vec2 rhs = pool.popVec2(); rhs.set(m_mass.ez.x, m_mass.ez.y); rhs.mulLocal(m_impulse.z); rhs.subLocal(Cdot1); m_mass.solve22ToOut(rhs, ref temp); impulse.x = temp.x; impulse.y = temp.y; impulse.z = -m_impulse.z; m_impulse.x += temp.x; m_impulse.y += temp.y; m_impulse.z = 0.0f; pool.pushVec2(1); } else { m_impulse.addLocal(impulse); } } else if (m_limitState == LimitState.AT_UPPER) { float newImpulse = m_impulse.z + impulse.z; if (newImpulse > 0.0f) { Vec2 rhs = pool.popVec2(); rhs.set(m_mass.ez.x, m_mass.ez.y); rhs.mulLocal(m_impulse.z); rhs.subLocal(Cdot1); m_mass.solve22ToOut(rhs, ref temp); impulse.x = temp.x; impulse.y = temp.y; impulse.z = -m_impulse.z; m_impulse.x += temp.x; m_impulse.y += temp.y; m_impulse.z = 0.0f; pool.pushVec2(1); } else { m_impulse.addLocal(impulse); } } Vec2 P = pool.popVec2(); P.set(impulse.x, impulse.y); vA.x -= mA*P.x; vA.y -= mA*P.y; wA -= iA*(Vec2.cross(m_rA, P) + impulse.z); vB.x += mB*P.x; vB.y += mB*P.y; wB += iB*(Vec2.cross(m_rB, P) + impulse.z); pool.pushVec2(2); pool.pushVec3(2); } else { // Solve point-to-point constraint Vec2 Cdot = pool.popVec2(); Vec2 impulse = pool.popVec2(); Vec2.crossToOutUnsafe(wA, m_rA, ref temp); Vec2.crossToOutUnsafe(wB, m_rB, ref Cdot); Cdot.addLocal(vB); Cdot.subLocal(vA); Cdot.subLocal(temp); Cdot.negateLocal(); m_mass.solve22ToOut(Cdot, ref impulse); // just leave negated m_impulse.x += impulse.x; m_impulse.y += impulse.y; vA.x -= mA*impulse.x; vA.y -= mA*impulse.y; wA -= iA*Vec2.cross(m_rA, impulse); vB.x += mB*impulse.x; vB.y += mB*impulse.y; wB += iB*Vec2.cross(m_rB, impulse); pool.pushVec2(2); } // data.velocities[m_indexA].v.set(vA); data.velocities[m_indexA].w = wA; // data.velocities[m_indexB].v.set(vB); data.velocities[m_indexB].w = wB; pool.pushVec2(1); }
internal override void SolveVelocityConstraints(ref SolverData data) { float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; Vector2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vector2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; // Solve spring constraint { float Cdot = Vector2.Dot(m_ax, vB - vA) + m_sBx * wB - m_sAx * wA; float impulse = -m_springMass * (Cdot + m_bias + m_gamma * m_springImpulse); m_springImpulse += impulse; Vector2 P = impulse * m_ax; float LA = impulse * m_sAx; float LB = impulse * m_sBx; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } // Solve rotational motor constraint { float Cdot = wB - wA - m_motorSpeed; float impulse = -m_motorMass * Cdot; float oldImpulse = m_motorImpulse; float maxImpulse = data.step.dt * m_maxMotorTorque; m_motorImpulse = MathUtils.Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve point to line constraint { float Cdot = Vector2.Dot(m_ay, vB - vA) + m_sBy * wB - m_sAy * wA; float impulse = -m_mass * Cdot; m_impulse += impulse; Vector2 P = impulse * m_ay; float LA = impulse * m_sAy; float LB = impulse * m_sBy; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = _bodyA.IslandIndex; _indexB = _bodyB.IslandIndex; _indexC = _bodyC.IslandIndex; _indexD = _bodyD.IslandIndex; _lcA = _bodyA.Sweep.LocalCenter; _lcB = _bodyB.Sweep.LocalCenter; _lcC = _bodyC.Sweep.LocalCenter; _lcD = _bodyD.Sweep.LocalCenter; _mA = _bodyA.InvMass; _mB = _bodyB.InvMass; _mC = _bodyC.InvMass; _mD = _bodyD.InvMass; _iA = _bodyA.InvI; _iB = _bodyB.InvI; _iC = _bodyC.InvI; _iD = _bodyD.InvI; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; float aC = data.positions[_indexC].a; Vector2 vC = data.velocities[_indexC].v; float wC = data.velocities[_indexC].w; float aD = data.positions[_indexD].a; Vector2 vD = data.velocities[_indexD].v; float wD = data.velocities[_indexD].w; Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD); _mass = 0.0f; if (_typeA == JointType.Revolute) { _JvAC = Vector2.Zero; _JwA = 1.0f; _JwC = 1.0f; _mass += _iA + _iC; } else { Vector2 u = MathUtils.Mul(qC, _localAxisC); Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC); Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA); _JvAC = u; _JwC = MathUtils.Cross(rC, u); _JwA = MathUtils.Cross(rA, u); _mass += _mC + _mA + _iC * _JwC * _JwC + _iA * _JwA * _JwA; } if (_typeB == JointType.Revolute) { _JvBD = Vector2.Zero; _JwB = _ratio; _JwD = _ratio; _mass += _ratio * _ratio * (_iB + _iD); } else { Vector2 u = MathUtils.Mul(qD, _localAxisD); Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD); Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB); _JvBD = _ratio * u; _JwD = _ratio * MathUtils.Cross(rD, u); _JwB = _ratio * MathUtils.Cross(rB, u); _mass += _ratio * _ratio * (_mD + _mB) + _iD * _JwD * _JwD + _iB * _JwB * _JwB; } // Compute effective mass. _mass = _mass > 0.0f ? 1.0f / _mass : 0.0f; if (Settings.EnableWarmstarting) { vA += (_mA * _impulse) * _JvAC; wA += _iA * _impulse * _JwA; vB += (_mB * _impulse) * _JvBD; wB += _iB * _impulse * _JwB; vC -= (_mC * _impulse) * _JvAC; wC -= _iC * _impulse * _JwC; vD -= (_mD * _impulse) * _JvBD; wD -= _iD * _impulse * _JwD; } else { _impulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; data.velocities[_indexC].v = vC; data.velocities[_indexC].w = wC; data.velocities[_indexD].v = vD; data.velocities[_indexD].w = wD; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = _bodyA.IslandIndex; _indexB = _bodyB.IslandIndex; _indexC = _bodyC.IslandIndex; _indexD = _bodyD.IslandIndex; _lcA = _bodyA._sweep.LocalCenter; _lcB = _bodyB._sweep.LocalCenter; _lcC = _bodyC._sweep.LocalCenter; _lcD = _bodyD._sweep.LocalCenter; _mA = _bodyA._invMass; _mB = _bodyB._invMass; _mC = _bodyC._invMass; _mD = _bodyD._invMass; _iA = _bodyA._invI; _iB = _bodyB._invI; _iC = _bodyC._invI; _iD = _bodyD._invI; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; float aC = data.positions[_indexC].a; Vector2 vC = data.velocities[_indexC].v; float wC = data.velocities[_indexC].w; float aD = data.positions[_indexD].a; Vector2 vD = data.velocities[_indexD].v; float wD = data.velocities[_indexD].w; Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD); _mass = 0.0f; if (_typeA == JointType.Revolute) { _JvAC = Vector2.Zero; _JwA = 1.0f; _JwC = 1.0f; _mass += _iA + _iC; } else { Vector2 u = MathUtils.Mul(qC, _localAxisC); Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC); Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA); _JvAC = u; _JwC = MathUtils.Cross(rC, u); _JwA = MathUtils.Cross(rA, u); _mass += _mC + _mA + _iC * _JwC * _JwC + _iA * _JwA * _JwA; } if (_typeB == JointType.Revolute) { _JvBD = Vector2.Zero; _JwB = _ratio; _JwD = _ratio; _mass += _ratio * _ratio * (_iB + _iD); } else { Vector2 u = MathUtils.Mul(qD, _localAxisD); Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD); Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB); _JvBD = _ratio * u; _JwD = _ratio * MathUtils.Cross(rD, u); _JwB = _ratio * MathUtils.Cross(rB, u); _mass += _ratio * _ratio * (_mD + _mB) + _iD * _JwD * _JwD + _iB * _JwB * _JwB; } // Compute effective mass. _mass = _mass > 0.0f ? 1.0f / _mass : 0.0f; if (Settings.EnableWarmstarting) { vA += (_mA * _impulse) * _JvAC; wA += _iA * _impulse * _JwA; vB += (_mB * _impulse) * _JvBD; wB += _iB * _impulse * _JwB; vC -= (_mC * _impulse) * _JvAC; wC -= _iC * _impulse * _JwC; vD -= (_mD * _impulse) * _JvBD; wD -= _iD * _impulse * _JwD; } else { _impulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; data.velocities[_indexC].v = vC; data.velocities[_indexC].w = wC; data.velocities[_indexD].v = vD; data.velocities[_indexD].w = wD; }
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[m_indexA].c; float aA = data.positions[m_indexA].a; Vec2 cB = data.positions[m_indexB].c; float aB = data.positions[m_indexB].a; qA.set_Renamed(aA); qB.set_Renamed(aB); Rot.mulToOutUnsafe(qA, temp.set_Renamed(m_localAnchorA).subLocal(m_localCenterA), rA); Rot.mulToOutUnsafe(qB, temp.set_Renamed(m_localAnchorB).subLocal(m_localCenterB), rB); uA.set_Renamed(cA).addLocal(rA).subLocal(m_groundAnchorA); uB.set_Renamed(cB).addLocal(rB).subLocal(m_groundAnchorB); float lengthA = uA.length(); float lengthB = uB.length(); if (lengthA > 10.0f * Settings.linearSlop) { uA.mulLocal(1.0f / lengthA); } else { uA.setZero(); } if (lengthB > 10.0f * Settings.linearSlop) { 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 = m_invMassA + m_invIA * ruA * ruA; float mB = m_invMassB + m_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_Renamed(uA).mulLocal(-impulse); PB.set_Renamed(uB).mulLocal((-m_ratio) * impulse); cA.x += m_invMassA * PA.x; cA.y += m_invMassA * PA.y; aA += m_invIA * Vec2.cross(rA, PA); cB.x += m_invMassB * PB.x; cB.y += m_invMassB * PB.y; aB += m_invIB * Vec2.cross(rB, PB); data.positions[m_indexA].c.set_Renamed(cA); data.positions[m_indexA].a = aA; data.positions[m_indexB].c.set_Renamed(cB); data.positions[m_indexB].a = aB; pool.pushRot(2); pool.pushVec2(7); return linearError < Settings.linearSlop; }
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; Vector2 cC = data.positions[_indexC].c; float aC = data.positions[_indexC].a; Vector2 cD = data.positions[_indexD].c; float aD = data.positions[_indexD].a; Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD); const float linearError = 0.0f; float coordinateA, coordinateB; Vector2 JvAC, JvBD; float JwA, JwB, JwC, JwD; float mass = 0.0f; if (_typeA == JointType.Revolute) { JvAC = Vector2.Zero; JwA = 1.0f; JwC = 1.0f; mass += _iA + _iC; coordinateA = aA - aC - _referenceAngleA; } else { Vector2 u = MathUtils.Mul(qC, _localAxisC); Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC); Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA); JvAC = u; JwC = MathUtils.Cross(rC, u); JwA = MathUtils.Cross(rA, u); mass += _mC + _mA + _iC * JwC * JwC + _iA * JwA * JwA; Vector2 pC = _localAnchorC - _lcC; Vector2 pA = MathUtils.MulT(qC, rA + (cA - cC)); coordinateA = Vector2.Dot(pA - pC, _localAxisC); } if (_typeB == JointType.Revolute) { JvBD = Vector2.Zero; JwB = _ratio; JwD = _ratio; mass += _ratio * _ratio * (_iB + _iD); coordinateB = aB - aD - _referenceAngleB; } else { Vector2 u = MathUtils.Mul(qD, _localAxisD); Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD); Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB); JvBD = _ratio * u; JwD = _ratio * MathUtils.Cross(rD, u); JwB = _ratio * MathUtils.Cross(rB, u); mass += _ratio * _ratio * (_mD + _mB) + _iD * JwD * JwD + _iB * JwB * JwB; Vector2 pD = _localAnchorD - _lcD; Vector2 pB = MathUtils.MulT(qD, rB + (cB - cD)); coordinateB = Vector2.Dot(pB - pD, _localAxisD); } float C = (coordinateA + _ratio * coordinateB) - _constant; float impulse = 0.0f; if (mass > 0.0f) { impulse = -C / mass; } cA += _mA * impulse * JvAC; aA += _iA * impulse * JwA; cB += _mB * impulse * JvBD; aB += _iB * impulse * JwB; cC -= _mC * impulse * JvAC; aC -= _iC * impulse * JwC; cD -= _mD * impulse * JvBD; aD -= _iD * impulse * JwD; data.positions[_indexA].c = cA; data.positions[_indexA].a = aA; data.positions[_indexB].c = cB; data.positions[_indexB].a = aB; data.positions[_indexC].c = cC; data.positions[_indexC].a = aC; data.positions[_indexD].c = cD; data.positions[_indexD].a = aD; // TODO_ERIN not implemented return(linearError < Settings.LinearSlop); }
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); Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); Vector2 u = cB + rB - cA - rA; float length = u.Length(); u.Normalize(); float C = length - MaxLength; C = MathUtils.Clamp(C, 0.0f, Settings.MaxLinearCorrection); float impulse = -_mass * C; Vector2 P = impulse * u; cA -= _invMassA * P; aA -= _invIA * MathUtils.Cross(rA, P); cB += _invMassB * P; aB += _invIB * MathUtils.Cross(rB, P); data.positions[_indexA].c = cA; data.positions[_indexA].a = aA; data.positions[_indexB].c = cB; data.positions[_indexB].a = aB; return length - MaxLength < Settings.LinearSlop; }
internal override void InitVelocityConstraints(ref SolverData data) { m_indexA = BodyA.IslandIndex; m_indexB = BodyB.IslandIndex; m_localCenterA = BodyA.Sweep.LocalCenter; m_localCenterB = BodyB.Sweep.LocalCenter; m_invMassA = BodyA.InvMass; m_invMassB = BodyB.InvMass; m_invIA = BodyA.InvI; m_invIB = BodyB.InvI; Vector2 cA = data.positions[m_indexA].c; float aA = data.positions[m_indexA].a; Vector2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vector2 cB = data.positions[m_indexB].c; float aB = data.positions[m_indexB].a; Vector2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; Rot qA = new Rot(aA), qB = new Rot(aB); m_rA = MathUtils.Mul(qA, LocalAnchorA - m_localCenterA); m_rB = MathUtils.Mul(qB, LocalAnchorB - m_localCenterB); _u = cB + m_rB - cA - m_rA; // Handle singularity. float length = _u.Length(); if (length > Settings.LinearSlop) { _u *= 1.0f / length; } else { _u = Vector2.Zero; } float crAu = MathUtils.Cross(m_rA, _u); float crBu = MathUtils.Cross(m_rB, _u); float invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu; // Compute the effective mass matrix. _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; if (Frequency > 0.0f) { float C = length - Length; // Frequency float omega = 2.0f * Settings.Pi * Frequency; // 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 (Settings.EnableWarmstarting) { // Scale the impulse to support a variable time step. _impulse *= data.step.dtRatio; Vector2 P = _impulse * _u; vA -= m_invMassA * P; wA -= m_invIA * MathUtils.Cross(m_rA, P); vB += m_invMassB * P; wB += m_invIB * MathUtils.Cross(m_rB, P); } else { _impulse = 0.0f; } data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; }
public override void initVelocityConstraints(SolverData data) { m_indexA = m_bodyA.m_islandIndex; m_indexB = m_bodyB.m_islandIndex; m_localCenterA.set_Renamed(m_bodyA.m_sweep.localCenter); m_localCenterB.set_Renamed(m_bodyB.m_sweep.localCenter); m_invMassA = m_bodyA.m_invMass; m_invMassB = m_bodyB.m_invMass; m_invIA = m_bodyA.m_invI; m_invIB = m_bodyB.m_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 d = pool.popVec2(); Vec2 temp = pool.popVec2(); Vec2 rA = pool.popVec2(); Vec2 rB = pool.popVec2(); qA.set_Renamed(aA); qB.set_Renamed(aB); // Compute the effective masses. Rot.mulToOutUnsafe(qA, d.set_Renamed(m_localAnchorA).subLocal(m_localCenterA), rA); Rot.mulToOutUnsafe(qB, d.set_Renamed(m_localAnchorB).subLocal(m_localCenterB), rB); d.set_Renamed(cB).subLocal(cA).addLocal(rB).subLocal(rA); float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; // Compute motor Jacobian and effective mass. { Rot.mulToOutUnsafe(qA, m_localXAxisA, m_axis); temp.set_Renamed(d).addLocal(rA); m_a1 = Vec2.cross(temp, m_axis); m_a2 = Vec2.cross(rB, m_axis); m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; if (m_motorMass > 0.0f) { m_motorMass = 1.0f / m_motorMass; } } // Prismatic constraint. { Rot.mulToOutUnsafe(qA, m_localYAxisA, m_perp); temp.set_Renamed(d).addLocal(rA); m_s1 = Vec2.cross(temp, m_perp); m_s2 = Vec2.cross(rB, m_perp); float k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; float k12 = iA * m_s1 + iB * m_s2; float k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; float k22 = iA + iB; if (k22 == 0.0f) { // For bodies with fixed rotation. k22 = 1.0f; } float k23 = iA * m_a1 + iB * m_a2; float k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; m_K.ex.set_Renamed(k11, k12, k13); m_K.ey.set_Renamed(k12, k22, k23); m_K.ez.set_Renamed(k13, k23, k33); } // Compute motor and limit terms. if (m_enableLimit) { float jointTranslation = Vec2.dot(m_axis, d); if (MathUtils.abs(m_upperTranslation - m_lowerTranslation) < 2.0f * Settings.linearSlop) { m_limitState = LimitState.EQUAL; } else if (jointTranslation <= m_lowerTranslation) { if (m_limitState != LimitState.AT_LOWER) { m_limitState = LimitState.AT_LOWER; m_impulse.z = 0.0f; } } else if (jointTranslation >= m_upperTranslation) { if (m_limitState != LimitState.AT_UPPER) { m_limitState = LimitState.AT_UPPER; m_impulse.z = 0.0f; } } else { m_limitState = LimitState.INACTIVE; m_impulse.z = 0.0f; } } else { m_limitState = LimitState.INACTIVE; m_impulse.z = 0.0f; } if (m_enableMotor == false) { m_motorImpulse = 0.0f; } if (data.step.warmStarting) { // Account for variable time step. m_impulse.mulLocal(data.step.dtRatio); m_motorImpulse *= data.step.dtRatio; Vec2 P = pool.popVec2(); temp.set_Renamed(m_axis).mulLocal(m_motorImpulse + m_impulse.z); P.set_Renamed(m_perp).mulLocal(m_impulse.x).addLocal(temp); float LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; float LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_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 { m_impulse.setZero(); m_motorImpulse = 0.0f; } data.velocities[m_indexA].v.set_Renamed(vA); data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v.set_Renamed(vB); data.velocities[m_indexB].w = wB; pool.pushRot(2); pool.pushVec2(4); }
public override bool SolvePositionConstraints(SolverData data) { return ConstrainEdges(data.Step); }
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 mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); float positionError, angularError; Mat33 K = new Mat33(); 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 (FrequencyHz > 0.0f) { Vector2 C1 = cB + rB - cA - rA; positionError = C1.Length(); angularError = 0.0f; Vector2 P = -K.Solve22(C1); cA -= mA * P; aA -= iA * MathUtils.Cross(rA, P); cB += mB * P; aB += iB * MathUtils.Cross(rB, P); } else { Vector2 C1 = cB + rB - cA - rA; float C2 = aB - aA - ReferenceAngle; positionError = C1.Length(); angularError = Math.Abs(C2); Vector3 C = new Vector3(C1.X, C1.Y, C2); Vector3 impulse = -K.Solve33(C); Vector2 P = new Vector2(impulse.X, impulse.Y); cA -= mA * P; aA -= iA * (MathUtils.Cross(rA, P) + impulse.Z); cB += mB * P; aB += iB * (MathUtils.Cross(rB, P) + impulse.Z); } 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; }
/// <summary> /// Solves the position constraints. /// </summary> /// <param name="data"></param> /// <returns>returns true if the position errors are within tolerance.</returns> internal abstract bool SolvePositionConstraints(ref SolverData data);
internal override bool SolvePositionConstraints(ref SolverData data) { //no position solving for this joint return(true); }
internal override void SolveVelocityConstraints(ref SolverData data) { float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; Vector2 vA = data.Velocities[_indexA].V; float wA = data.Velocities[_indexA].W; Vector2 vB = data.Velocities[_indexB].V; float wB = data.Velocities[_indexB].W; // Solve spring constraint { float Cdot = Vector2.Dot(_ax, vB - vA) + _sBx * wB - _sAx * wA; float impulse = -_springMass * (Cdot + _bias + _gamma * _springImpulse); _springImpulse += impulse; Vector2 P = impulse * _ax; float LA = impulse * _sAx; float LB = impulse * _sBx; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } // Solve rotational motor constraint { float Cdot = wB - wA - _motorSpeed; float impulse = -_motorMass * Cdot; float oldImpulse = _motorImpulse; float maxImpulse = data.Step.dt * _maxMotorTorque; _motorImpulse = MathUtils.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = _motorImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve point to line constraint { float Cdot = Vector2.Dot(_ay, vB - vA) + _sBy * wB - _sAy * wA; float impulse = -_mass * Cdot; _impulse += impulse; Vector2 P = impulse * _ay; float LA = impulse * _sAy; float LB = impulse * _sBy; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } data.Velocities[_indexA].V = vA; data.Velocities[_indexA].W = wA; data.Velocities[_indexB].V = vB; data.Velocities[_indexB].W = wB; }
public override void SolveVelocityConstraints(SolverData data) { float crossMassSum = 0.0f; float dotMassSum = 0.0f; Vec2[] d = Pool.GetVec2Array(Bodies.Length); for (int i = 0; i < Bodies.Length; ++i) { int prev = (i == 0) ? Bodies.Length - 1 : i - 1; int next = (i == Bodies.Length - 1) ? 0 : i + 1; d[i].Set(Bodies[next].WorldCenter); d[i].SubLocal(Bodies[prev].WorldCenter); dotMassSum += (d[i].LengthSquared()) / Bodies[i].Mass; crossMassSum += Vec2.Cross(Bodies[i].LinearVelocity, d[i]); } float lambda = (-2.0f) * crossMassSum / dotMassSum; // System.out.println(crossMassSum + " " +dotMassSum); // lambda = MathUtils.clamp(lambda, -Settings.maxLinearCorrection, // Settings.maxLinearCorrection); m_impulse += lambda; // System.out.println(m_impulse); for (int i = 0; i < Bodies.Length; ++i) { Bodies[i].LinearVelocity.X += Bodies[i].InvMass * d[i].Y * .5f * lambda; Bodies[i].LinearVelocity.Y += Bodies[i].InvMass * (-d[i].X) * .5f * lambda; } }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; Vector2 cA = data.positions[_indexA].c; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 cB = data.positions[_indexB].c; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Rot qA = new Rot(aA), qB = new Rot(aB); // Compute the effective masses. Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); Vector2 d = (cB - cA) + rB - rA; float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; // Compute motor Jacobian and effective mass. { _axis = MathUtils.Mul(qA, LocalXAxis); _a1 = MathUtils.Cross(d + rA, _axis); _a2 = MathUtils.Cross(rB, _axis); _motorMass = mA + mB + iA * _a1 * _a1 + iB * _a2 * _a2; if (_motorMass > 0.0f) { _motorMass = 1.0f / _motorMass; } } // Prismatic constraint. { _perp = MathUtils.Mul(qA, _localYAxisA); _s1 = MathUtils.Cross(d + rA, _perp); _s2 = MathUtils.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 = new Vector3(k11, k12, k13); _K.ey = new Vector3(k12, k22, k23); _K.ez = new Vector3(k13, k23, k33); } // Compute motor and limit terms. if (_enableLimit) { float jointTranslation = Vector2.Dot(_axis, d); if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop) { _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 (_enableMotor == false) { MotorImpulse = 0.0f; } if (Settings.EnableWarmstarting) { // Account for variable time step. _impulse *= data.step.dtRatio; MotorImpulse *= data.step.dtRatio; Vector2 P = _impulse.X * _perp + (MotorImpulse + _impulse.Z) * _axis; float LA = _impulse.X * _s1 + _impulse.Y + (MotorImpulse + _impulse.Z) * _a1; float LB = _impulse.X * _s2 + _impulse.Y + (MotorImpulse + _impulse.Z) * _a2; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } else { _impulse = Vector3.Zero; MotorImpulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
internal abstract void SolveVelocityConstraints(ref SolverData data);
internal override void SolveVelocityConstraints(ref SolverData data) { Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; // Solve linear motor constraint. if (_enableMotor && _limitState != LimitState.Equal) { float Cdot = Vector2.Dot(_axis, vB - vA) + _a2 * wB - _a1 * wA; float impulse = _motorMass * (_motorSpeed - Cdot); float oldImpulse = MotorImpulse; float maxImpulse = data.step.dt * _maxMotorForce; MotorImpulse = MathUtils.Clamp(MotorImpulse + impulse, -maxImpulse, maxImpulse); impulse = MotorImpulse - oldImpulse; Vector2 P = impulse * _axis; float LA = impulse * _a1; float LB = impulse * _a2; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } Vector2 Cdot1 = new Vector2(); Cdot1.X = Vector2.Dot(_perp, vB - vA) + _s2 * wB - _s1 * wA; Cdot1.Y = wB - wA; if (_enableLimit && _limitState != LimitState.Inactive) { // Solve prismatic and limit constraint in block form. float Cdot2; Cdot2 = Vector2.Dot(_axis, vB - vA) + _a2 * wB - _a1 * wA; Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2); Vector3 f1 = _impulse; Vector3 df = _K.Solve33(-Cdot); _impulse += df; if (_limitState == LimitState.AtLower) { _impulse.Z = Math.Max(_impulse.Z, 0.0f); } else if (_limitState == LimitState.AtUpper) { _impulse.Z = Math.Min(_impulse.Z, 0.0f); } // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) Vector2 b = -Cdot1 - (_impulse.Z - f1.Z) * new Vector2(_K.ez.X, _K.ez.Y); Vector2 f2r = _K.Solve22(b) + new Vector2(f1.X, f1.Y); _impulse.X = f2r.X; _impulse.Y = f2r.Y; df = _impulse - f1; Vector2 P = df.X * _perp + df.Z * _axis; float LA = df.X * _s1 + df.Y + df.Z * _a1; float LB = df.X * _s2 + df.Y + df.Z * _a2; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } else { // Limit is inactive, just solve the prismatic constraint in block form. Vector2 df = _K.Solve22(-Cdot1); _impulse.X += df.X; _impulse.Y += df.Y; Vector2 P = df.X * _perp; float LA = df.X * _s1 + df.Y; float LB = df.X * _s2 + df.Y; vA -= mA * P; wA -= iA * LA; vB += mB * P; wB += iB * LB; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
public override bool solvePositionConstraints(SolverData data) { Rot qA = pool.popRot(); Rot qB = pool.popRot(); 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; qA.set(aA); qB.set(aB); float angularError = 0.0f; float positionError = 0.0f; bool fixedRotation = (m_invIA + m_invIB == 0.0f); // Solve angular limit constraint. if (m_enableLimit && m_limitState != LimitState.INACTIVE && fixedRotation == false) { float angle = aB - aA - m_referenceAngle; float limitImpulse = 0.0f; if (m_limitState == LimitState.EQUAL) { // Prevent large angular corrections float C = MathUtils.clamp(angle - m_lowerAngle, -Settings.maxAngularCorrection, Settings.maxAngularCorrection); limitImpulse = -m_motorMass*C; angularError = MathUtils.abs(C); } else if (m_limitState == LimitState.AT_LOWER) { float C = angle - m_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 (m_limitState == LimitState.AT_UPPER) { float C = angle - m_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); Vec2 rA = pool.popVec2(); Vec2 rB = pool.popVec2(); Vec2 C = pool.popVec2(); Vec2 impulse = pool.popVec2(); C.set(m_localAnchorA); C.subLocal(m_localCenterA); Rot.mulToOutUnsafe(qA, C, ref rA); C.set(m_localAnchorB); C.subLocal(m_localCenterB); Rot.mulToOutUnsafe(qB, C, ref rB); C.set(cB); C.addLocal(rB); C.subLocal(cA); C.subLocal(rA); positionError = C.length(); float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_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, ref 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[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.pushRot(2); return positionError <= Settings.linearSlop && angularError <= Settings.angularSlop; }
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 mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; // Compute fresh Jacobians Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); Vector2 d = cB + rB - cA - rA; Vector2 axis = MathUtils.Mul(qA, LocalXAxis); float a1 = MathUtils.Cross(d + rA, axis); float a2 = MathUtils.Cross(rB, axis); Vector2 perp = MathUtils.Mul(qA, _localYAxisA); float s1 = MathUtils.Cross(d + rA, perp); float s2 = MathUtils.Cross(rB, perp); Vector3 impulse; Vector2 C1 = new Vector2(); C1.X = Vector2.Dot(perp, d); C1.Y = aB - aA - ReferenceAngle; float linearError = Math.Abs(C1.X); float angularError = Math.Abs(C1.Y); bool active = false; float C2 = 0.0f; if (_enableLimit) { float translation = Vector2.Dot(axis, d); if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop) { // Prevent large angular corrections C2 = MathUtils.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection); linearError = Math.Max(linearError, Math.Abs(translation)); active = true; } else if (translation <= _lowerTranslation) { // Prevent large linear corrections and allow some slop. C2 = MathUtils.Clamp(translation - _lowerTranslation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f); linearError = Math.Max(linearError, _lowerTranslation - translation); active = true; } else if (translation >= _upperTranslation) { // Prevent large linear corrections and allow some slop. C2 = MathUtils.Clamp(translation - _upperTranslation - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection); linearError = Math.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 = new Mat33(); K.ex = new Vector3(k11, k12, k13); K.ey = new Vector3(k12, k22, k23); K.ez = new Vector3(k13, k23, k33); Vector3 C = new Vector3(); C.X = C1.X; C.Y = C1.Y; C.Z = C2; impulse = K.Solve33(-C); } 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 = new Mat22(); K.ex = new Vector2(k11, k12); K.ey = new Vector2(k12, k22); Vector2 impulse1 = K.Solve(-C1); impulse = new Vector3(); impulse.X = impulse1.X; impulse.Y = impulse1.Y; impulse.Z = 0.0f; } Vector2 P = impulse.X * perp + impulse.Z * axis; float LA = impulse.X * s1 + impulse.Y + impulse.Z * a1; float LB = impulse.X * s2 + impulse.Y + impulse.Z * a2; cA -= mA * P; aA -= iA * LA; cB += mB * P; aB += iB * LB; data.positions[_indexA].c = cA; data.positions[_indexA].a = aA; data.positions[_indexB].c = cB; data.positions[_indexB].a = aB; return(linearError <= Settings.LinearSlop && angularError <= Settings.AngularSlop); }
public override void initVelocityConstraints(SolverData data) { m_indexA = m_bodyA.m_islandIndex; m_indexB = m_bodyB.m_islandIndex; m_localCenterA.set(m_bodyA.m_sweep.localCenter); m_localCenterB.set(m_bodyB.m_sweep.localCenter); m_invMassA = m_bodyA.m_invMass; m_invMassB = m_bodyB.m_invMass; m_invIA = m_bodyA.m_invI; m_invIB = m_bodyB.m_invI; float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; 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. temp.set(m_localAnchorA); temp.subLocal(m_localCenterA); Rot.mulToOutUnsafe(qA, temp , ref rA); temp.set(m_localAnchorB); temp.subLocal(m_localCenterB); Rot.mulToOutUnsafe(qB, temp, ref rB); d.set(cB); d.addLocal(rB); d.subLocal(cA); d.subLocal(rA); // Point to line constraint { Rot.mulToOut(qA, m_localYAxisA, ref m_ay); temp.set(d); temp.addLocal(rA); m_sAy = Vec2.cross(temp, m_ay); m_sBy = Vec2.cross(rB, m_ay); m_mass = mA + mB + iA*m_sAy*m_sAy + iB*m_sBy*m_sBy; if (m_mass > 0.0f) { m_mass = 1.0f/m_mass; } } // Spring constraint m_springMass = 0.0f; m_bias = 0.0f; m_gamma = 0.0f; if (m_frequencyHz > 0.0f) { Rot.mulToOut(qA, m_localXAxisA, ref m_ax); temp.set(d); temp.addLocal(rA); m_sAx = Vec2.cross(temp, m_ax); m_sBx = Vec2.cross(rB, m_ax); float invMass = mA + mB + iA*m_sAx*m_sAx + iB*m_sBx*m_sBx; if (invMass > 0.0f) { m_springMass = 1.0f/invMass; float C = Vec2.dot(d, m_ax); // Frequency float omega = 2.0f*MathUtils.PI*m_frequencyHz; // Damping coefficient float da = 2.0f*m_springMass*m_dampingRatio*omega; // Spring stiffness float k = m_springMass*omega*omega; // magic formulas float h = data.step.dt; m_gamma = h*(da + h*k); if (m_gamma > 0.0f) { m_gamma = 1.0f/m_gamma; } m_bias = C*h*k*m_gamma; m_springMass = invMass + m_gamma; if (m_springMass > 0.0f) { m_springMass = 1.0f/m_springMass; } } } else { m_springImpulse = 0.0f; } // Rotational motor if (m_enableMotor) { m_motorMass = iA + iB; if (m_motorMass > 0.0f) { m_motorMass = 1.0f/m_motorMass; } } else { m_motorMass = 0.0f; m_motorImpulse = 0.0f; } if (data.step.warmStarting) { Vec2 P = pool.popVec2(); // Account for variable time step. m_impulse *= data.step.dtRatio; m_springImpulse *= data.step.dtRatio; m_motorImpulse *= data.step.dtRatio; P.x = m_impulse*m_ay.x + m_springImpulse*m_ax.x; P.y = m_impulse*m_ay.y + m_springImpulse*m_ax.y; float LA = m_impulse*m_sAy + m_springImpulse*m_sAx + m_motorImpulse; float LB = m_impulse*m_sBy + m_springImpulse*m_sBx + m_motorImpulse; vA.x -= m_invMassA*P.x; vA.y -= m_invMassA*P.y; wA -= m_invIA*LA; vB.x += m_invMassB*P.x; vB.y += m_invMassB*P.y; wB += m_invIB*LB; pool.pushVec2(1); } else { m_impulse = 0.0f; m_springImpulse = 0.0f; m_motorImpulse = 0.0f; } pool.pushRot(2); pool.pushVec2(1); // data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; // data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; Vector2 cA = data.positions[_indexA].c; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 cB = data.positions[_indexB].c; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Complex qA = Complex.FromAngle(aA); Complex qB = Complex.FromAngle(aB); // Compute the effective mass matrix. _rA = -Complex.Multiply(ref _localCenterA, ref qA); _rB = -Complex.Multiply(ref _localCenterB, ref qB); // 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 = 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; _linearMass = K.Inverse; _angularMass = iA + iB; if (_angularMass > 0.0f) { _angularMass = 1.0f / _angularMass; } _linearError = cB + _rB - cA - _rA - Complex.Multiply(ref _linearOffset, ref qA); _angularError = aB - aA - _angularOffset; if (data.step.warmStarting) { // Scale impulses to support a variable time step. _linearImpulse *= data.step.dtRatio; _angularImpulse *= data.step.dtRatio; Vector2 P = new Vector2(_linearImpulse.X, _linearImpulse.Y); vA -= mA * P; wA -= iA * (MathUtils.Cross(ref _rA, ref P) + _angularImpulse); vB += mB * P; wB += iB * (MathUtils.Cross(ref _rB, ref P) + _angularImpulse); } else { _linearImpulse = Vector2.Zero; _angularImpulse = 0.0f; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
public override void solveVelocityConstraints(SolverData data) { float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; Vec2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vec2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; Vec2 temp = pool.popVec2(); Vec2 P = pool.popVec2(); // Solve spring constraint { temp.set(vB); temp.subLocal(vA); float Cdot = Vec2.dot(m_ax, temp) + m_sBx*wB - m_sAx*wA; float impulse = -m_springMass*(Cdot + m_bias + m_gamma*m_springImpulse); m_springImpulse += impulse; P.x = impulse*m_ax.x; P.y = impulse*m_ax.y; float LA = impulse*m_sAx; float LB = impulse*m_sBx; 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; } // Solve rotational motor constraint { float Cdot = wB - wA - m_motorSpeed; float impulse = -m_motorMass*Cdot; float oldImpulse = m_motorImpulse; float maxImpulse = data.step.dt*m_maxMotorTorque; m_motorImpulse = MathUtils.clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = m_motorImpulse - oldImpulse; wA -= iA*impulse; wB += iB*impulse; } // Solve point to line constraint { temp.set(vB); temp.subLocal(vA); float Cdot = Vec2.dot(m_ay, temp) + m_sBy*wB - m_sAy*wA; float impulse = -m_mass*Cdot; m_impulse += impulse; P.x = impulse*m_ay.x; P.y = impulse*m_ay.y; float LA = impulse*m_sAy; float LB = impulse*m_sBy; 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(2); // data.velocities[m_indexA].v = vA; data.velocities[m_indexA].w = wA; // data.velocities[m_indexB].v = vB; data.velocities[m_indexB].w = wB; }
internal override bool SolvePositionConstraints(ref SolverData data) { return(true); }
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; Vector2 cC = data.positions[_indexC].c; float aC = data.positions[_indexC].a; Vector2 cD = data.positions[_indexD].c; float aD = data.positions[_indexD].a; Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD); const float linearError = 0.0f; float coordinateA, coordinateB; Vector2 JvAC, JvBD; float JwA, JwB, JwC, JwD; float mass = 0.0f; if (_typeA == JointType.Revolute) { JvAC = Vector2.Zero; JwA = 1.0f; JwC = 1.0f; mass += _iA + _iC; coordinateA = aA - aC - _referenceAngleA; } else { Vector2 u = MathUtils.Mul(qC, _localAxisC); Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC); Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA); JvAC = u; JwC = MathUtils.Cross(rC, u); JwA = MathUtils.Cross(rA, u); mass += _mC + _mA + _iC * JwC * JwC + _iA * JwA * JwA; Vector2 pC = _localAnchorC - _lcC; Vector2 pA = MathUtils.MulT(qC, rA + (cA - cC)); coordinateA = Vector2.Dot(pA - pC, _localAxisC); } if (_typeB == JointType.Revolute) { JvBD = Vector2.Zero; JwB = _ratio; JwD = _ratio; mass += _ratio * _ratio * (_iB + _iD); coordinateB = aB - aD - _referenceAngleB; } else { Vector2 u = MathUtils.Mul(qD, _localAxisD); Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD); Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB); JvBD = _ratio * u; JwD = _ratio * MathUtils.Cross(rD, u); JwB = _ratio * MathUtils.Cross(rB, u); mass += _ratio * _ratio * (_mD + _mB) + _iD * JwD * JwD + _iB * JwB * JwB; Vector2 pD = _localAnchorD - _lcD; Vector2 pB = MathUtils.MulT(qD, rB + (cB - cD)); coordinateB = Vector2.Dot(pB - pD, _localAxisD); } float C = (coordinateA + _ratio * coordinateB) - _constant; float impulse = 0.0f; if (mass > 0.0f) { impulse = -C / mass; } cA += _mA * impulse * JvAC; aA += _iA * impulse * JwA; cB += _mB * impulse * JvBD; aB += _iB * impulse * JwB; cC -= _mC * impulse * JvAC; aC -= _iC * impulse * JwC; cD -= _mD * impulse * JvBD; aD -= _iD * impulse * JwD; data.positions[_indexA].c = cA; data.positions[_indexA].a = aA; data.positions[_indexB].c = cB; data.positions[_indexB].a = aB; data.positions[_indexC].c = cC; data.positions[_indexC].a = aC; data.positions[_indexD].c = cD; data.positions[_indexD].a = aD; // TODO_ERIN not implemented return linearError < Settings.LinearSlop; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; float aA = data.Positions[_indexA].A; Vector2 vA = data.Velocities[_indexA].V; float wA = data.Velocities[_indexA].W; float aB = data.Positions[_indexB].A; Vector2 vB = data.Velocities[_indexB].V; float wB = data.Velocities[_indexB].W; Rot qA = new Rot(aA), qB = new Rot(aB); _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); // 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 (_enableMotor == false || fixedRotation) { _motorImpulse = 0.0f; } if (_enableLimit && fixedRotation == false) { float jointAngle = aB - aA - ReferenceAngle; if (Math.Abs(_upperAngle - _lowerAngle) < 2.0f * Settings.AngularSlop) { _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 (Settings.EnableWarmstarting) { // Scale impulses to support a variable time step. _impulse *= data.Step.dtRatio; _motorImpulse *= data.Step.dtRatio; Vector2 P = new Vector2(_impulse.X, _impulse.Y); vA -= mA * P; wA -= iA * (MathUtils.Cross(_rA, P) + MotorImpulse + _impulse.Z); vB += mB * P; wB += iB * (MathUtils.Cross(_rB, P) + MotorImpulse + _impulse.Z); } else { _impulse = Vector3.Zero; _motorImpulse = 0.0f; } data.Velocities[_indexA].V = vA; data.Velocities[_indexA].W = wA; data.Velocities[_indexB].V = vB; data.Velocities[_indexB].W = wB; }
public override void initVelocityConstraints(SolverData data) { m_indexA = m_bodyA.m_islandIndex; m_indexB = m_bodyB.m_islandIndex; m_localCenterA.set_Renamed(m_bodyA.m_sweep.localCenter); m_localCenterB.set_Renamed(m_bodyB.m_sweep.localCenter); m_invMassA = m_bodyA.m_invMass; m_invMassB = m_bodyB.m_invMass; m_invIA = m_bodyA.m_invI; m_invIB = m_bodyB.m_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_Renamed(aA); qB.set_Renamed(aB); // Compute the effective masses. Rot.mulToOutUnsafe(qA, temp.set_Renamed(m_localAnchorA).subLocal(m_localCenterA), m_rA); Rot.mulToOutUnsafe(qB, temp.set_Renamed(m_localAnchorB).subLocal(m_localCenterB), m_rB); m_uA.set_Renamed(cA).addLocal(m_rA).subLocal(m_groundAnchorA); m_uB.set_Renamed(cB).addLocal(m_rB).subLocal(m_groundAnchorB); float lengthA = m_uA.length(); float lengthB = m_uB.length(); if (lengthA > 10f * Settings.linearSlop) { m_uA.mulLocal(1.0f / lengthA); } else { m_uA.setZero(); } if (lengthB > 10f * Settings.linearSlop) { m_uB.mulLocal(1.0f / lengthB); } else { m_uB.setZero(); } // Compute effective mass. float ruA = Vec2.cross(m_rA, m_uA); float ruB = Vec2.cross(m_rB, m_uB); float mA = m_invMassA + m_invIA * ruA * ruA; float mB = m_invMassB + m_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_Renamed(m_uA).mulLocal(-m_impulse); PB.set_Renamed(m_uB).mulLocal((-m_ratio) * m_impulse); vA.x += m_invMassA * PA.x; vA.y += m_invMassA * PA.y; wA += m_invIA * Vec2.cross(m_rA, PA); vB.x += m_invMassB * PB.x; vB.y += m_invMassB * PB.y; wB += m_invIB * Vec2.cross(m_rB, PB); pool.pushVec2(2); } else { m_impulse = 0.0f; } data.velocities[m_indexA].v.set_Renamed(vA); data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v.set_Renamed(vB); data.velocities[m_indexB].w = wB; pool.pushVec2(1); pool.pushRot(2); }
internal override void SolveVelocityConstraints(ref SolverData data) { Vector2 vA = data.Velocities[_indexA].V; float wA = data.Velocities[_indexA].W; Vector2 vB = data.Velocities[_indexB].V; float wB = data.Velocities[_indexB].W; float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; bool fixedRotation = (iA + iB == 0.0f); // Solve motor constraint. if (_enableMotor && _limitState != LimitState.Equal && fixedRotation == false) { float Cdot = wB - wA - _motorSpeed; float impulse = _motorMass * (-Cdot); float oldImpulse = _motorImpulse; float maxImpulse = data.Step.dt * _maxMotorTorque; _motorImpulse = MathUtils.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse); impulse = _motorImpulse - oldImpulse; wA -= iA * impulse; wB += iB * impulse; } // Solve limit constraint. if (_enableLimit && _limitState != LimitState.Inactive && fixedRotation == false) { Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA); float Cdot2 = wB - wA; Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2); Vector3 impulse = -_mass.Solve33(Cdot); if (_limitState == LimitState.Equal) { _impulse += impulse; } else if (_limitState == LimitState.AtLower) { float newImpulse = _impulse.Z + impulse.Z; if (newImpulse < 0.0f) { Vector2 rhs = -Cdot1 + _impulse.Z * new Vector2(_mass.ez.X, _mass.ez.Y); Vector2 reduced = _mass.Solve22(rhs); impulse.X = reduced.X; impulse.Y = reduced.Y; impulse.Z = -_impulse.Z; _impulse.X += reduced.X; _impulse.Y += reduced.Y; _impulse.Z = 0.0f; } else { _impulse += impulse; } } else if (_limitState == LimitState.AtUpper) { float newImpulse = _impulse.Z + impulse.Z; if (newImpulse > 0.0f) { Vector2 rhs = -Cdot1 + _impulse.Z * new Vector2(_mass.ez.X, _mass.ez.Y); Vector2 reduced = _mass.Solve22(rhs); impulse.X = reduced.X; impulse.Y = reduced.Y; impulse.Z = -_impulse.Z; _impulse.X += reduced.X; _impulse.Y += reduced.Y; _impulse.Z = 0.0f; } else { _impulse += impulse; } } Vector2 P = new Vector2(impulse.X, impulse.Y); vA -= mA * P; wA -= iA * (MathUtils.Cross(_rA, P) + impulse.Z); vB += mB * P; wB += iB * (MathUtils.Cross(_rB, P) + impulse.Z); } else { // Solve point-to-point constraint Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA); Vector2 impulse = _mass.Solve22(-Cdot); _impulse.X += impulse.X; _impulse.Y += impulse.Y; vA -= mA * impulse; wA -= iA * MathUtils.Cross(_rA, impulse); vB += mB * impulse; wB += iB * MathUtils.Cross(_rB, impulse); } data.Velocities[_indexA].V = vA; data.Velocities[_indexA].W = wA; data.Velocities[_indexB].V = vB; data.Velocities[_indexB].W = wB; }
public override void solveVelocityConstraints(SolverData data) { Vec2 vA = data.velocities[m_indexA].v; float wA = data.velocities[m_indexA].w; Vec2 vB = data.velocities[m_indexB].v; float wB = data.velocities[m_indexB].w; Vec2 vpA = pool.popVec2(); Vec2 vpB = pool.popVec2(); Vec2 PA = pool.popVec2(); Vec2 PB = pool.popVec2(); Vec2.crossToOutUnsafe(wA, m_rA, vpA); vpA.addLocal(vA); Vec2.crossToOutUnsafe(wB, m_rB, vpB); vpB.addLocal(vB); float Cdot = -Vec2.dot(m_uA, vpA) - m_ratio * Vec2.dot(m_uB, vpB); float impulse = (-m_mass) * Cdot; m_impulse += impulse; PA.set_Renamed(m_uA).mulLocal(-impulse); PB.set_Renamed(m_uB).mulLocal((-m_ratio) * impulse); vA.x += m_invMassA * PA.x; vA.y += m_invMassA * PA.y; wA += m_invIA * Vec2.cross(m_rA, PA); vB.x += m_invMassB * PB.x; vB.y += m_invMassB * PB.y; wB += m_invIB * Vec2.cross(m_rB, PB); data.velocities[m_indexA].v.set_Renamed(vA); data.velocities[m_indexA].w = wA; data.velocities[m_indexB].v.set_Renamed(vB); data.velocities[m_indexB].w = wB; pool.pushVec2(4); }
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 void SolveVelocityConstraints(ref SolverData data) { Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; // Cdot = dot(u, v + cross(w, r)) Vector2 vpA = vA + MathUtils.Cross(wA, _rA); Vector2 vpB = vB + MathUtils.Cross(wB, _rB); float C = _length - MaxLength; float Cdot = Vector2.Dot(_u, vpB - vpA); // Predictive constraint. if (C < 0.0f) { Cdot += data.step.inv_dt * C; } float impulse = -_mass * Cdot; float oldImpulse = _impulse; _impulse = Math.Min(0.0f, _impulse + impulse); impulse = _impulse - oldImpulse; Vector2 P = impulse * _u; vA -= _invMassA * P; wA -= _invIA * MathUtils.Cross(_rA, P); vB += _invMassB * P; wB += _invIB * MathUtils.Cross(_rB, P); data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
internal override void InitVelocityConstraints(ref SolverData data) { Body b1 = BodyA; Body b2 = BodyB; Transform xf1, xf2; b1.GetTransform(out xf1); b2.GetTransform(out xf2); // Compute the effective mass matrix. Vector2 r1 = MathUtils.Mul(ref xf1.q, LocalAnchorA - b1.LocalCenter); Vector2 r2 = MathUtils.Mul(ref xf2.q, LocalAnchorB - b2.LocalCenter); _u = b2.Sweep.C + r2 - b1.Sweep.C - r1; // Handle singularity. float length = _u.Length(); if (length < MaxLength && length > MinLength) { return; } if (length > Settings.LinearSlop) { _u *= 1.0f / length; } else { _u = Vector2.Zero; } float cr1u = MathUtils.Cross(r1, _u); float cr2u = MathUtils.Cross(r2, _u); float invMass = b1.InvMass + b1.InvI * cr1u * cr1u + b2.InvMass + b2.InvI * cr2u * cr2u; Debug.Assert(invMass > Settings.Epsilon); _mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; if (Frequency > 0.0f) { float C = length - MaxLength; // Frequency float omega = 2.0f * Settings.Pi * Frequency; // Damping coefficient float d = 2.0f * _mass * DampingRatio * omega; // Spring stiffness float k = _mass * omega * omega; // magic formulas _gamma = data.step.dt * (d + data.step.dt * k); _gamma = _gamma != 0.0f ? 1.0f / _gamma : 0.0f; _bias = C * data.step.dt * k * _gamma; _mass = invMass + _gamma; _mass = _mass != 0.0f ? 1.0f / _mass : 0.0f; } if (Settings.EnableWarmstarting) { // Scale the impulse to support a variable time step. _impulse *= data.step.dtRatio; Vector2 P = _impulse * _u; b1.LinearVelocityInternal -= b1.InvMass * P; b1.AngularVelocityInternal -= b1.InvI * MathUtils.Cross(r1, P); b2.LinearVelocityInternal += b2.InvMass * P; b2.AngularVelocityInternal += b2.InvI * MathUtils.Cross(r2, P); } else { _impulse = 0.0f; } }
internal override void SolveVelocityConstraints(ref SolverData data) { Body b1 = BodyA; Body b2 = BodyB; Transform xf1, xf2; b1.GetTransform(out xf1); b2.GetTransform(out xf2); Vector2 r1 = MathUtils.Mul(ref xf1.q, LocalAnchorA - b1.LocalCenter); Vector2 r2 = MathUtils.Mul(ref xf2.q, LocalAnchorB - b2.LocalCenter); Vector2 d = b2.Sweep.C + r2 - b1.Sweep.C - r1; float length = d.Length(); if (length < MaxLength && length > MinLength) { return; } // Cdot = dot(u, v + cross(w, r)) Vector2 v1 = b1.LinearVelocityInternal + MathUtils.Cross(b1.AngularVelocityInternal, r1); Vector2 v2 = b2.LinearVelocityInternal + MathUtils.Cross(b2.AngularVelocityInternal, r2); float Cdot = Vector2.Dot(_u, v2 - v1); float impulse = -_mass * (Cdot + _bias + _gamma * _impulse); _impulse += impulse; Vector2 P = impulse * _u; b1.LinearVelocityInternal -= b1.InvMass * P; b1.AngularVelocityInternal -= b1.InvI * MathUtils.Cross(r1, P); b2.LinearVelocityInternal += b2.InvMass * P; b2.AngularVelocityInternal += b2.InvI * MathUtils.Cross(r2, P); }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = KinematicBodyB ? 0.0f : BodyB._invMass; _invIA = BodyA._invI; _invIB = KinematicBodyB ? 0.0f : BodyB._invI; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Rot qA = new Rot(aA), qB = new Rot(aB); _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); // 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; Mat33 K = new Mat33(); 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 (FrequencyHz > 0.0f) { K.GetInverse22(ref _mass); float invM = iA + iB; float m = invM > 0.0f ? 1.0f / invM : 0.0f; float C = aB - aA - ReferenceAngle; // Frequency float omega = 2.0f * Settings.Pi * FrequencyHz; // Damping coefficient float d = 2.0f * m * DampingRatio * omega; // Spring stiffness float k = m * 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; invM += _gamma; _mass.ez.Z = invM != 0.0f ? 1.0f / invM : 0.0f; } else { K.GetSymInverse33(ref _mass); _gamma = 0.0f; _bias = 0.0f; } if (Settings.EnableWarmstarting) { // Scale impulses to support a variable time step. _impulse *= data.step.dtRatio; Vector2 P = new Vector2(_impulse.X, _impulse.Y); vA -= mA * P; wA -= iA * (MathUtils.Cross(_rA, P) + _impulse.Z); vB += mB * P; wB += iB * (MathUtils.Cross(_rB, P) + _impulse.Z); } else { _impulse = Vector3.Zero; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
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[m_indexA].c; float aA = data.positions[m_indexA].a; Vec2 cB = data.positions[m_indexB].c; float aB = data.positions[m_indexB].a; qA.set_Renamed(aA); qB.set_Renamed(aB); float mA = m_invMassA, mB = m_invMassB; float iA = m_invIA, iB = m_invIB; // Compute fresh Jacobians Rot.mulToOutUnsafe(qA, temp.set_Renamed(m_localAnchorA).subLocal(m_localCenterA), rA); Rot.mulToOutUnsafe(qB, temp.set_Renamed(m_localAnchorB).subLocal(m_localCenterB), rB); d.set_Renamed(cB).addLocal(rB).subLocal(cA).subLocal(rA); Rot.mulToOutUnsafe(qA, m_localXAxisA, axis); float a1 = Vec2.cross(temp.set_Renamed(d).addLocal(rA), axis); float a2 = Vec2.cross(rB, axis); Rot.mulToOutUnsafe(qA, m_localYAxisA, perp); float s1 = Vec2.cross(temp.set_Renamed(d).addLocal(rA), perp); float s2 = Vec2.cross(rB, perp); C1.x = Vec2.dot(perp, d); C1.y = aB - aA - m_referenceAngle; float linearError = MathUtils.abs(C1.x); float angularError = MathUtils.abs(C1.y); bool active = false; float C2 = 0.0f; if (m_enableLimit) { float translation = Vec2.dot(axis, d); if (MathUtils.abs(m_upperTranslation - m_lowerTranslation) < 2.0f * Settings.linearSlop) { // Prevent large angular corrections C2 = MathUtils.clamp(translation, -Settings.maxLinearCorrection, Settings.maxLinearCorrection); linearError = MathUtils.max(linearError, MathUtils.abs(translation)); active = true; } else if (translation <= m_lowerTranslation) { // Prevent large linear corrections and allow some slop. C2 = MathUtils.clamp(translation - m_lowerTranslation + Settings.linearSlop, -Settings.maxLinearCorrection, 0.0f); linearError = MathUtils.max(linearError, m_lowerTranslation - translation); active = true; } else if (translation >= m_upperTranslation) { // Prevent large linear corrections and allow some slop. C2 = MathUtils.clamp(translation - m_upperTranslation - Settings.linearSlop, 0.0f, Settings.maxLinearCorrection); linearError = MathUtils.max(linearError, translation - m_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_Renamed(k11, k12, k13); K.ey.set_Renamed(k12, k22, k23); K.ez.set_Renamed(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_Renamed(k11, k12); K.ey.set_Renamed(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[m_indexA].c.set_Renamed(cA); data.positions[m_indexA].a = aA; data.positions[m_indexB].c.set_Renamed(cB); data.positions[m_indexB].a = aB; pool.pushVec2(7); pool.pushVec3(1); pool.pushRot(2); return linearError <= Settings.linearSlop && angularError <= Settings.angularSlop; }
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 mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); float positionError, angularError; Mat33 K = new Mat33(); 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 (FrequencyHz > 0.0f) { Vector2 C1 = cB + rB - cA - rA; positionError = C1.Length(); angularError = 0.0f; Vector2 P = -K.Solve22(C1); cA -= mA * P; aA -= iA * MathUtils.Cross(rA, P); cB += mB * P; aB += iB * MathUtils.Cross(rB, P); } else { Vector2 C1 = cB + rB - cA - rA; float C2 = aB - aA - ReferenceAngle; positionError = C1.Length(); angularError = Math.Abs(C2); Vector3 C = new Vector3(C1.X, C1.Y, C2); Vector3 impulse = -K.Solve33(C); Vector2 P = new Vector2(impulse.X, impulse.Y); cA -= mA * P; aA -= iA * (MathUtils.Cross(rA, P) + impulse.Z); cB += mB * P; aB += iB * (MathUtils.Cross(rB, P) + impulse.Z); } 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 void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _indexB = BodyB.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _localCenterB = BodyB._sweep.LocalCenter; _invMassA = BodyA._invMass; _invMassB = BodyB._invMass; _invIA = BodyA._invI; _invIB = BodyB._invI; float aA = data.positions[_indexA].a; Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; float aB = data.positions[_indexB].a; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; Rot qA = new Rot(aA), qB = new Rot(aB); _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); _rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB); // 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; Mat33 K = new Mat33(); 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 (FrequencyHz > 0.0f) { K.GetInverse22(ref _mass); float invM = iA + iB; float m = invM > 0.0f ? 1.0f / invM : 0.0f; float C = aB - aA - ReferenceAngle; // Frequency float omega = 2.0f * Settings.Pi * FrequencyHz; // Damping coefficient float d = 2.0f * m * DampingRatio * omega; // Spring stiffness float k = m * 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; invM += _gamma; _mass.ez.Z = invM != 0.0f ? 1.0f / invM : 0.0f; } else { K.GetSymInverse33(ref _mass); _gamma = 0.0f; _bias = 0.0f; } if (Settings.EnableWarmstarting) { // Scale impulses to support a variable time step. _impulse *= data.step.dtRatio; Vector2 P = new Vector2(_impulse.X, _impulse.Y); vA -= mA * P; wA -= iA * (MathUtils.Cross(_rA, P) + _impulse.Z); vB += mB * P; wB += iB * (MathUtils.Cross(_rB, P) + _impulse.Z); } else { _impulse = Vector3.Zero; } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
internal override void InitVelocityConstraints(ref SolverData data) { _indexA = BodyA.IslandIndex; _localCenterA = BodyA._sweep.LocalCenter; _invMassA = BodyA._invMass; _invIA = BodyA._invI; Vector2 cA = data.Positions[_indexA].C; float aA = data.Positions[_indexA].A; Vector2 vA = data.Velocities[_indexA].V; float wA = data.Velocities[_indexA].W; Rot qA = new Rot(aA); float mass = BodyA.Mass; // Frequency float omega = 2.0f * Settings.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); _gamma = h * (d + h * k); if (_gamma != 0.0f) { _gamma = 1.0f / _gamma; } _beta = h * k * _gamma; // Compute the effective mass matrix. _rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA); // 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 = new Mat22(); K.ex.X = _invMassA + _invIA * _rA.Y * _rA.Y + _gamma; K.ex.Y = -_invIA * _rA.X * _rA.Y; K.ey.X = K.ex.Y; K.ey.Y = _invMassA + _invIA * _rA.X * _rA.X + _gamma; _mass = K.Inverse; _C = cA + _rA - _worldAnchor; _C *= _beta; // Cheat with some damping wA *= 0.98f; if (Settings.EnableWarmstarting) { _impulse *= data.Step.dtRatio; vA += _invMassA * _impulse; wA += _invIA * MathUtils.Cross(_rA, _impulse); } else { _impulse = Vector2.Zero; } data.Velocities[_indexA].V = vA; data.Velocities[_indexA].W = wA; }
internal override void SolveVelocityConstraints(ref SolverData data) { Vector2 vA = data.velocities[_indexA].v; float wA = data.velocities[_indexA].w; Vector2 vB = data.velocities[_indexB].v; float wB = data.velocities[_indexB].w; float mA = _invMassA, mB = _invMassB; float iA = _invIA, iB = _invIB; if (FrequencyHz > 0.0f) { float Cdot2 = wB - wA; float impulse2 = -_mass.ez.Z * (Cdot2 + _bias + _gamma * _impulse.Z); _impulse.Z += impulse2; wA -= iA * impulse2; wB += iB * impulse2; Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA); Vector2 impulse1 = -MathUtils.Mul22(_mass, Cdot1); _impulse.X += impulse1.X; _impulse.Y += impulse1.Y; Vector2 P = impulse1; vA -= mA * P; wA -= iA * MathUtils.Cross(_rA, P); vB += mB * P; wB += iB * MathUtils.Cross(_rB, P); } else { Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA); float Cdot2 = wB - wA; Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2); Vector3 impulse = -MathUtils.Mul(_mass, Cdot); _impulse += impulse; Vector2 P = new Vector2(impulse.X, impulse.Y); vA -= mA * P; wA -= iA * (MathUtils.Cross(_rA, P) + impulse.Z); vB += mB * P; wB += iB * (MathUtils.Cross(_rB, P) + impulse.Z); } data.velocities[_indexA].v = vA; data.velocities[_indexA].w = wA; data.velocities[_indexB].v = vB; data.velocities[_indexB].w = wB; }
public override bool solvePositionConstraints(SolverData data) { Vec2 cA = data.positions[m_indexA].c; double aA = data.positions[m_indexA].a; Vec2 cB = data.positions[m_indexB].c; double 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); double mA = m_invMassA, mB = m_invMassB; double iA = m_invIA, iB = m_invIB; Rot.mulToOutUnsafe(qA, temp.set(m_localAnchorA).subLocal(m_localCenterA), rA); Rot.mulToOutUnsafe(qB, temp.set(m_localAnchorB).subLocal(m_localCenterB), rB); double 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 (m_frequencyHz > 0.0d) { C1.set(cB).addLocal(rB).subLocal(cA).subLocal(rA); positionError = C1.length(); angularError = 0.0d; 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); double 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); pool.pushVec3(2); } // 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.linearSlop && angularError <= Settings.angularSlop); }