public float SolveLinearAxis( float timeStep, float jacDiagABInv, RigidBody body1, ref IndexedVector3 pointInA, RigidBody body2, ref IndexedVector3 pointInB, int limit_index, ref IndexedVector3 axis_normal_on_a, ref IndexedVector3 anchorPos) { ///find relative velocity // IndexedVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition(); // IndexedVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition(); IndexedVector3 rel_pos1 = anchorPos - body1.GetCenterOfMassPosition(); IndexedVector3 rel_pos2 = anchorPos - body2.GetCenterOfMassPosition(); IndexedVector3 vel1 = IndexedVector3.Zero; body1.InternalGetVelocityInLocalPointObsolete(ref rel_pos1, ref vel1); IndexedVector3 vel2 = IndexedVector3.Zero; ; body2.InternalGetVelocityInLocalPointObsolete(ref rel_pos2, ref vel2); IndexedVector3 vel = vel1 - vel2; float rel_vel = IndexedVector3.Dot(axis_normal_on_a, vel); /// apply displacement correction //positional error (zeroth order error) float depth = -IndexedVector3.Dot((pointInA - pointInB), axis_normal_on_a); float lo = float.MinValue; float hi = float.MaxValue; float minLimit = m_lowerLimit[limit_index]; float maxLimit = m_upperLimit[limit_index]; //handle the limits if (minLimit < maxLimit) { { if (depth > maxLimit) { depth -= maxLimit; lo = 0f; } else { if (depth < minLimit) { depth -= minLimit; hi = 0f; } else { return 0.0f; } } } } float normalImpulse = m_limitSoftness * (m_restitution * depth / timeStep - m_damping * rel_vel) * jacDiagABInv; float oldNormalImpulse = m_accumulatedImpulse[limit_index]; float sum = oldNormalImpulse + normalImpulse; m_accumulatedImpulse[limit_index] = (sum > hi ? 0f : sum < lo ? 0f : sum); normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse; IndexedVector3 impulse_vector = axis_normal_on_a * normalImpulse; //body1.applyImpulse( impulse_vector, rel_pos1); //body2.applyImpulse(-impulse_vector, rel_pos2); IndexedVector3 ftorqueAxis1 = IndexedVector3.Cross(rel_pos1, axis_normal_on_a); IndexedVector3 ftorqueAxis2 = IndexedVector3.Cross(rel_pos2, axis_normal_on_a); body1.InternalApplyImpulse(axis_normal_on_a * body1.GetInvMass(), body1.GetInvInertiaTensorWorld() * ftorqueAxis1, normalImpulse, "Generic6DoF body1"); body2.InternalApplyImpulse(axis_normal_on_a * body2.GetInvMass(), body2.GetInvInertiaTensorWorld() * ftorqueAxis2, -normalImpulse, "Generic6DoF body2"); return normalImpulse; }
public void solveConstraintObsolete(RigidBody bodyA, RigidBody bodyB, float timeStep) { if (m_useSolveConstraintObsolete) { IndexedVector3 pivotAInW = m_rbA.GetCenterOfMassTransform()*m_rbAFrame._origin; IndexedVector3 pivotBInW = m_rbB.GetCenterOfMassTransform()*m_rbBFrame._origin; float tau = 0.3f; //linear part if (!m_angularOnly) { IndexedVector3 rel_pos1 = pivotAInW - m_rbA.GetCenterOfMassPosition(); IndexedVector3 rel_pos2 = pivotBInW - m_rbB.GetCenterOfMassPosition(); IndexedVector3 vel1 = IndexedVector3.Zero; bodyA.InternalGetVelocityInLocalPointObsolete(ref rel_pos1,ref vel1); IndexedVector3 vel2 = IndexedVector3.Zero; bodyB.InternalGetVelocityInLocalPointObsolete(ref rel_pos2,ref vel2); IndexedVector3 vel = vel1 - vel2; for (int i=0;i<3;i++) { IndexedVector3 normal = m_jac[i].m_linearJointAxis; float jacDiagABInv = 1.0f / m_jac[i].GetDiagonal(); float rel_vel = normal.Dot(ref vel); //positional error (zeroth order error) float depth = -(pivotAInW - pivotBInW).Dot(ref normal); //this is the error projected on the normal float impulse = depth*tau/timeStep * jacDiagABInv - rel_vel * jacDiagABInv; m_appliedImpulse += impulse; IndexedVector3 ftorqueAxis1 = rel_pos1.Cross(ref normal); IndexedVector3 ftorqueAxis2 = rel_pos2.Cross(ref normal); bodyA.InternalApplyImpulse(normal*m_rbA.GetInvMass(), m_rbA.GetInvInertiaTensorWorld()*ftorqueAxis1,impulse,null); bodyB.InternalApplyImpulse(normal*m_rbB.GetInvMass(), m_rbB.GetInvInertiaTensorWorld()*ftorqueAxis2,-impulse,null); } } // apply motor if (m_bMotorEnabled) { // compute current and predicted transforms IndexedMatrix trACur = m_rbA.GetCenterOfMassTransform(); IndexedMatrix trBCur = m_rbB.GetCenterOfMassTransform(); IndexedVector3 omegaA = IndexedVector3.Zero; bodyA.InternalGetAngularVelocity(ref omegaA); IndexedVector3 omegaB = IndexedVector3.Zero; bodyB.InternalGetAngularVelocity(ref omegaB); IndexedMatrix trAPred; IndexedVector3 zerovec = new IndexedVector3(0,0,0); TransformUtil.IntegrateTransform(ref trACur, ref zerovec, ref omegaA, timeStep, out trAPred); IndexedMatrix trBPred; TransformUtil.IntegrateTransform(ref trBCur, ref zerovec, ref omegaB, timeStep, out trBPred); // compute desired transforms in world IndexedMatrix trPose = IndexedMatrix.CreateFromQuaternion(m_qTarget); IndexedMatrix trABDes = m_rbBFrame * trPose * m_rbAFrame.Inverse(); IndexedMatrix trADes = trBPred * trABDes; IndexedMatrix trBDes = trAPred * trABDes.Inverse(); // compute desired omegas in world IndexedVector3 omegaADes, omegaBDes; TransformUtil.CalculateVelocity(ref trACur, ref trADes, timeStep, out zerovec, out omegaADes); TransformUtil.CalculateVelocity(ref trBCur, ref trBDes, timeStep, out zerovec, out omegaBDes); // compute delta omegas IndexedVector3 dOmegaA = omegaADes - omegaA; IndexedVector3 dOmegaB = omegaBDes - omegaB; // compute weighted avg axis of dOmega (weighting based on inertias) IndexedVector3 axisA = IndexedVector3.Zero, axisB = IndexedVector3.Zero; float kAxisAInv = 0, kAxisBInv = 0; if (dOmegaA.LengthSquared() > MathUtil.SIMD_EPSILON) { axisA = dOmegaA.Normalized(); kAxisAInv = GetRigidBodyA().ComputeAngularImpulseDenominator(ref axisA); } if (dOmegaB.LengthSquared() > MathUtil.SIMD_EPSILON) { axisB = dOmegaB.Normalized(); kAxisBInv = GetRigidBodyB().ComputeAngularImpulseDenominator(ref axisB); } IndexedVector3 avgAxis = kAxisAInv * axisA + kAxisBInv * axisB; if (bDoTorque && avgAxis.LengthSquared() > MathUtil.SIMD_EPSILON) { avgAxis.Normalize(); kAxisAInv = GetRigidBodyA().ComputeAngularImpulseDenominator(ref avgAxis); kAxisBInv = GetRigidBodyB().ComputeAngularImpulseDenominator(ref avgAxis); float kInvCombined = kAxisAInv + kAxisBInv; IndexedVector3 impulse = (kAxisAInv * dOmegaA - kAxisBInv * dOmegaB) / (kInvCombined * kInvCombined); if (m_maxMotorImpulse >= 0) { float fMaxImpulse = m_maxMotorImpulse; if (m_bNormalizedMotorStrength) fMaxImpulse = fMaxImpulse/kAxisAInv; IndexedVector3 newUnclampedAccImpulse = m_accMotorImpulse + impulse; float newUnclampedMag = newUnclampedAccImpulse.Length(); if (newUnclampedMag > fMaxImpulse) { newUnclampedAccImpulse.Normalize(); newUnclampedAccImpulse *= fMaxImpulse; impulse = newUnclampedAccImpulse - m_accMotorImpulse; } m_accMotorImpulse += impulse; } float impulseMag = impulse.Length(); IndexedVector3 impulseAxis = impulse / impulseMag; bodyA.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbA.GetInvInertiaTensorWorld()*impulseAxis, impulseMag,null); bodyB.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbB.GetInvInertiaTensorWorld()*impulseAxis, -impulseMag,null); } } else if (m_damping > MathUtil.SIMD_EPSILON) // no motor: do a little damping { IndexedVector3 angVelA = IndexedVector3.Zero; bodyA.InternalGetAngularVelocity(ref angVelA); IndexedVector3 angVelB= IndexedVector3.Zero; bodyB.InternalGetAngularVelocity(ref angVelB); IndexedVector3 relVel = angVelB - angVelA; if (relVel.LengthSquared() > MathUtil.SIMD_EPSILON) { IndexedVector3 relVelAxis = relVel.Normalized(); float m_kDamping = 1.0f / (GetRigidBodyA().ComputeAngularImpulseDenominator(ref relVelAxis) + GetRigidBodyB().ComputeAngularImpulseDenominator(ref relVelAxis)); IndexedVector3 impulse = m_damping * m_kDamping * relVel; float impulseMag = impulse.Length(); IndexedVector3 impulseAxis = impulse / impulseMag; bodyA.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbA.GetInvInertiaTensorWorld()*impulseAxis, impulseMag,null); bodyB.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbB.GetInvInertiaTensorWorld()*impulseAxis, -impulseMag,null); } } // joint limits { ///solve angular part IndexedVector3 angVelA = IndexedVector3.Zero; bodyA.InternalGetAngularVelocity(ref angVelA); IndexedVector3 angVelB= IndexedVector3.Zero; bodyB.InternalGetAngularVelocity(ref angVelB); // solve swing limit if (m_solveSwingLimit) { float amplitude = m_swingLimitRatio * m_swingCorrection*m_biasFactor/timeStep; float relSwingVel = (angVelB - angVelA).Dot(ref m_swingAxis); if (relSwingVel > 0) amplitude += m_swingLimitRatio * relSwingVel * m_relaxationFactor; float impulseMag = amplitude * m_kSwing; // Clamp the accumulated impulse float temp = m_accSwingLimitImpulse; m_accSwingLimitImpulse = Math.Max(m_accSwingLimitImpulse + impulseMag, 0.0f); impulseMag = m_accSwingLimitImpulse - temp; IndexedVector3 impulse = m_swingAxis * impulseMag; // don't let cone response affect twist // (this can happen since body A's twist doesn't match body B's AND we use an elliptical cone limit) { IndexedVector3 impulseTwistCouple = impulse.Dot(ref m_twistAxisA) * m_twistAxisA; IndexedVector3 impulseNoTwistCouple = impulse - impulseTwistCouple; impulse = impulseNoTwistCouple; } impulseMag = impulse.Length(); IndexedVector3 noTwistSwingAxis = impulse / impulseMag; bodyA.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbA.GetInvInertiaTensorWorld()*noTwistSwingAxis, impulseMag,null); bodyB.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbB.GetInvInertiaTensorWorld()*noTwistSwingAxis, -impulseMag,null); } // solve twist limit if (m_solveTwistLimit) { float amplitude = m_twistLimitRatio * m_twistCorrection*m_biasFactor/timeStep; float relTwistVel = (angVelB - angVelA).Dot( ref m_twistAxis ); if (relTwistVel > 0) // only damp when moving towards limit (m_twistAxis flipping is important) amplitude += m_twistLimitRatio * relTwistVel * m_relaxationFactor; float impulseMag = amplitude * m_kTwist; // Clamp the accumulated impulse float temp = m_accTwistLimitImpulse; m_accTwistLimitImpulse = Math.Max(m_accTwistLimitImpulse + impulseMag, 0.0f ); impulseMag = m_accTwistLimitImpulse - temp; IndexedVector3 impulse = m_twistAxis * impulseMag; bodyA.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbA.GetInvInertiaTensorWorld()*m_twistAxis,impulseMag,null); bodyB.InternalApplyImpulse(new IndexedVector3(0,0,0), m_rbB.GetInvInertiaTensorWorld()*m_twistAxis,-impulseMag,null); } } } }