public static void Prestep(ref Vector3Wide tangentX, ref Vector3Wide tangentY, ref Vector3Wide offsetA, ref Vector3Wide offsetB, ref BodyInertias inertiaA, ref BodyInertias inertiaB, out TangentFriction.Projection projection) { ComputeJacobians(ref tangentX, ref tangentY, ref offsetA, ref offsetB, out var jacobians); //Compute effective mass matrix contributions. Triangular2x2Wide.SandwichScale(ref jacobians.LinearA, ref inertiaA.InverseMass, out var linearContributionA); Triangular2x2Wide.SandwichScale(ref jacobians.LinearA, ref inertiaB.InverseMass, out var linearContributionB); Triangular3x3Wide.MatrixSandwich(ref jacobians.AngularA, ref inertiaA.InverseInertiaTensor, out var angularContributionA); Triangular3x3Wide.MatrixSandwich(ref jacobians.AngularB, ref inertiaB.InverseInertiaTensor, out var angularContributionB); //No softening; this constraint is rigid by design. (It does support a maximum force, but that is distinct from a proper damping ratio/natural frequency.) Triangular2x2Wide.Add(ref linearContributionA, ref linearContributionB, out var linear); Triangular2x2Wide.Add(ref angularContributionA, ref angularContributionB, out var angular); Triangular2x2Wide.Add(ref linear, ref angular, out var inverseEffectiveMass); Triangular2x2Wide.InvertWithoutOverlap(ref inverseEffectiveMass, out projection.EffectiveMass); projection.OffsetA = offsetA; projection.OffsetB = offsetB; //Note that friction constraints have no bias velocity. They target zero velocity. }
public static void Solve(ref Vector3Wide tangentX, ref Vector3Wide tangentY, ref TangentFriction.Projection projection, ref BodyInertias inertiaA, ref BodyInertias inertiaB, ref Vector <float> maximumImpulse, ref Vector2Wide accumulatedImpulse, ref BodyVelocities wsvA, ref BodyVelocities wsvB) { ComputeJacobians(ref tangentX, ref tangentY, ref projection.OffsetA, ref projection.OffsetB, out var jacobians); ComputeCorrectiveImpulse(ref wsvA, ref wsvB, ref projection, ref jacobians, ref maximumImpulse, ref accumulatedImpulse, out var correctiveCSI); ApplyImpulse(ref jacobians, ref inertiaA, ref inertiaB, ref correctiveCSI, ref wsvA, ref wsvB); }
public static void ComputeCorrectiveImpulse(ref BodyVelocities wsvA, ref BodyVelocities wsvB, ref TangentFriction.Projection data, ref Jacobians jacobians, ref Vector <float> maximumImpulse, ref Vector2Wide accumulatedImpulse, out Vector2Wide correctiveCSI) { Matrix2x3Wide.TransformByTransposeWithoutOverlap(wsvA.Linear, jacobians.LinearA, out var csvaLinear); Matrix2x3Wide.TransformByTransposeWithoutOverlap(wsvA.Angular, jacobians.AngularA, out var csvaAngular); Matrix2x3Wide.TransformByTransposeWithoutOverlap(wsvB.Linear, jacobians.LinearA, out var csvbLinear); Matrix2x3Wide.TransformByTransposeWithoutOverlap(wsvB.Angular, jacobians.AngularB, out var csvbAngular); //Note that the velocity in constraint space is (csvaLinear - csvbLinear + csvaAngular + csvbAngular). //The subtraction there is due to sharing the linear jacobian between both bodies. //In the following, we need to compute the constraint space *violating* velocity- which is the negation of the above velocity in constraint space. //So, (csvbLinear - csvaLinear - (csvaAngular + csvbAngular)). Vector2Wide.Subtract(csvbLinear, csvaLinear, out var csvLinear); Vector2Wide.Add(csvaAngular, csvbAngular, out var csvAngular); Vector2Wide.Subtract(csvLinear, csvAngular, out var csv); Symmetric2x2Wide.TransformWithoutOverlap(csv, data.EffectiveMass, out var csi); var previousAccumulated = accumulatedImpulse; Vector2Wide.Add(accumulatedImpulse, csi, out accumulatedImpulse); //The maximum force of friction depends upon the normal impulse. The maximum is supplied per iteration. Vector2Wide.Length(accumulatedImpulse, out var accumulatedMagnitude); //Note division by zero guard. var scale = Vector.Min(Vector <float> .One, maximumImpulse / Vector.Max(new Vector <float>(1e-16f), accumulatedMagnitude)); Vector2Wide.Scale(accumulatedImpulse, scale, out accumulatedImpulse); Vector2Wide.Subtract(accumulatedImpulse, previousAccumulated, out correctiveCSI); }
public static void WarmStart(ref Vector3Wide tangentX, ref Vector3Wide tangentY, ref TangentFriction.Projection projection, ref BodyInertias inertiaA, ref BodyInertias inertiaB, ref Vector2Wide accumulatedImpulse, ref BodyVelocities wsvA, ref BodyVelocities wsvB) { ComputeJacobians(ref tangentX, ref tangentY, ref projection.OffsetA, ref projection.OffsetB, out var jacobians); //TODO: If the previous frame and current frame are associated with different time steps, the previous frame's solution won't be a good solution anymore. //To compensate for this, the accumulated impulse should be scaled if dt changes. ApplyImpulse(ref jacobians, ref inertiaA, ref inertiaB, ref accumulatedImpulse, ref wsvA, ref wsvB); }