protected internal override int FindOverlappingTriangles(float dt) { BoundingBox boundingBox; convex.Shape.GetLocalBoundingBox(ref convex.worldTransform, ref terrain.worldTransform, out boundingBox); if (convex.entity != null) { Vector3 transformedVelocity; Matrix3x3 inverse; Matrix3x3.Invert(ref terrain.worldTransform.LinearTransform, out inverse); Matrix3x3.Transform(ref convex.entity.linearVelocity, ref inverse, out transformedVelocity); Vector3.Multiply(ref transformedVelocity, dt, out transformedVelocity); if (transformedVelocity.X > 0) { boundingBox.Max.X += transformedVelocity.X; } else { boundingBox.Min.X += transformedVelocity.X; } if (transformedVelocity.Y > 0) { boundingBox.Max.Y += transformedVelocity.Y; } else { boundingBox.Min.Y += transformedVelocity.Y; } if (transformedVelocity.Z > 0) { boundingBox.Max.Z += transformedVelocity.Z; } else { boundingBox.Min.Z += transformedVelocity.Z; } } terrain.Shape.GetOverlaps(boundingBox, ref overlappedTriangles); return(overlappedTriangles.Count); }
/// <summary> /// Calculates necessary information for velocity solving. /// Called by preStep(float dt) /// </summary> /// <param name="dt">Time in seconds since the last update.</param> public override void Update(float dt) { Matrix3x3.Transform(ref localAnchorA, ref connectionA.orientationMatrix, out worldOffsetA); Matrix3x3.Transform(ref localAnchorB, ref connectionB.orientationMatrix, out worldOffsetB); float errorReductionParameter; springSettings.ComputeErrorReductionAndSoftness(dt, 1 / dt, out errorReductionParameter, out softness); //Mass Matrix Matrix3x3 k; Matrix3x3 linearComponent; Matrix3x3.CreateCrossProduct(ref worldOffsetA, out rACrossProduct); Matrix3x3.CreateCrossProduct(ref worldOffsetB, out rBCrossProduct); if (connectionA.isDynamic && connectionB.isDynamic) { Matrix3x3.CreateScale(connectionA.inverseMass + connectionB.inverseMass, out linearComponent); Matrix3x3 angularComponentA, angularComponentB; Matrix3x3.Multiply(ref rACrossProduct, ref connectionA.inertiaTensorInverse, out angularComponentA); Matrix3x3.Multiply(ref rBCrossProduct, ref connectionB.inertiaTensorInverse, out angularComponentB); Matrix3x3.Multiply(ref angularComponentA, ref rACrossProduct, out angularComponentA); Matrix3x3.Multiply(ref angularComponentB, ref rBCrossProduct, out angularComponentB); Matrix3x3.Subtract(ref linearComponent, ref angularComponentA, out k); Matrix3x3.Subtract(ref k, ref angularComponentB, out k); } else if (connectionA.isDynamic && !connectionB.isDynamic) { Matrix3x3.CreateScale(connectionA.inverseMass, out linearComponent); Matrix3x3 angularComponentA; Matrix3x3.Multiply(ref rACrossProduct, ref connectionA.inertiaTensorInverse, out angularComponentA); Matrix3x3.Multiply(ref angularComponentA, ref rACrossProduct, out angularComponentA); Matrix3x3.Subtract(ref linearComponent, ref angularComponentA, out k); } else if (!connectionA.isDynamic && connectionB.isDynamic) { Matrix3x3.CreateScale(connectionB.inverseMass, out linearComponent); Matrix3x3 angularComponentB; Matrix3x3.Multiply(ref rBCrossProduct, ref connectionB.inertiaTensorInverse, out angularComponentB); Matrix3x3.Multiply(ref angularComponentB, ref rBCrossProduct, out angularComponentB); Matrix3x3.Subtract(ref linearComponent, ref angularComponentB, out k); } else { throw new InvalidOperationException("Cannot constrain two kinematic bodies."); } k.M11 += softness; k.M22 += softness; k.M33 += softness; Matrix3x3.Invert(ref k, out massMatrix); Vector3.Add(ref connectionB.position, ref worldOffsetB, out error); Vector3.Subtract(ref error, ref connectionA.position, out error); Vector3.Subtract(ref error, ref worldOffsetA, out error); Vector3.Multiply(ref error, -errorReductionParameter, out biasVelocity); //Ensure that the corrective velocity doesn't exceed the max. float length = biasVelocity.LengthSquared(); if (length > maxCorrectiveVelocitySquared) { float multiplier = maxCorrectiveVelocity / (float)Math.Sqrt(length); biasVelocity.X *= multiplier; biasVelocity.Y *= multiplier; biasVelocity.Z *= multiplier; } }
/// <summary> /// Initializes the constraint for the current frame. /// </summary> /// <param name="dt">Time between frames.</param> public override void Update(float dt) { basis.rotationMatrix = entity.orientationMatrix; basis.ComputeWorldSpaceAxes(); float updateRate = 1 / dt; if (settings.mode == MotorMode.Servomechanism) //Only need to do the bulk of this work if it's a servo. { Quaternion currentRelativeOrientation; var worldTransform = basis.WorldTransform; Quaternion.CreateFromRotationMatrix(ref worldTransform, out currentRelativeOrientation); //Compute the relative orientation R' between R and the target relative orientation. Quaternion errorOrientation; Quaternion.Conjugate(ref currentRelativeOrientation, out errorOrientation); Quaternion.Multiply(ref settings.servo.goal, ref errorOrientation, out errorOrientation); float errorReduction; settings.servo.springSettings.ComputeErrorReductionAndSoftness(dt, updateRate, out errorReduction, out usedSoftness); //Turn this into an axis-angle representation. Quaternion.GetAxisAngleFromQuaternion(ref errorOrientation, out axis, out angle); //Scale the axis by the desired velocity if the angle is sufficiently large (epsilon). if (angle > Toolbox.BigEpsilon) { float velocity = MathHelper.Min(settings.servo.baseCorrectiveSpeed, angle * updateRate) + angle * errorReduction; biasVelocity.X = axis.X * velocity; biasVelocity.Y = axis.Y * velocity; biasVelocity.Z = axis.Z * velocity; //Ensure that the corrective velocity doesn't exceed the max. float length = biasVelocity.LengthSquared(); if (length > settings.servo.maxCorrectiveVelocitySquared) { float multiplier = settings.servo.maxCorrectiveVelocity / (float)Math.Sqrt(length); biasVelocity.X *= multiplier; biasVelocity.Y *= multiplier; biasVelocity.Z *= multiplier; } } else { //Wouldn't want an old frame's bias velocity to sneak in. biasVelocity = new Vector3(); } } else { usedSoftness = settings.velocityMotor.softness * updateRate; angle = 0; //Zero out the error; Matrix3x3 transform = basis.WorldTransform; Matrix3x3.Transform(ref settings.velocityMotor.goalVelocity, ref transform, out biasVelocity); } //Compute effective mass effectiveMassMatrix = entity.inertiaTensorInverse; effectiveMassMatrix.M11 += usedSoftness; effectiveMassMatrix.M22 += usedSoftness; effectiveMassMatrix.M33 += usedSoftness; Matrix3x3.Invert(ref effectiveMassMatrix, out effectiveMassMatrix); //Update the maximum force ComputeMaxForces(settings.maximumForce, dt); }
///<summary> /// Performs the frame's configuration step. ///</summary> ///<param name="dt">Timestep duration.</param> public override void Update(float dt) { //Transform point into world space. Matrix3x3.Transform(ref localPoint, ref entity.orientationMatrix, out r); Vector3.Add(ref r, ref entity.position, out worldPoint); float updateRate = 1 / dt; if (settings.mode == MotorMode.Servomechanism) { Vector3.Subtract(ref settings.servo.goal, ref worldPoint, out error); float separationDistance = error.Length(); if (separationDistance > Toolbox.BigEpsilon) { float errorReduction; settings.servo.springSettings.ComputeErrorReductionAndSoftness(dt, updateRate, out errorReduction, out usedSoftness); //The rate of correction can be based on a constant correction velocity as well as a 'spring like' correction velocity. //The constant correction velocity could overshoot the destination, so clamp it. float correctionSpeed = MathHelper.Min(settings.servo.baseCorrectiveSpeed, separationDistance * updateRate) + separationDistance * errorReduction; Vector3.Multiply(ref error, correctionSpeed / separationDistance, out biasVelocity); //Ensure that the corrective velocity doesn't exceed the max. float length = biasVelocity.LengthSquared(); if (length > settings.servo.maxCorrectiveVelocitySquared) { float multiplier = settings.servo.maxCorrectiveVelocity / (float)Math.Sqrt(length); biasVelocity.X *= multiplier; biasVelocity.Y *= multiplier; biasVelocity.Z *= multiplier; } } else { //Wouldn't want to use a bias from an earlier frame. biasVelocity = new Vector3(); } } else { usedSoftness = settings.velocityMotor.softness * updateRate; biasVelocity = settings.velocityMotor.goalVelocity; error = Vector3.Zero; } //Compute the maximum force that can be applied this frame. ComputeMaxForces(settings.maximumForce, dt); //COMPUTE EFFECTIVE MASS MATRIX //Transforms a change in velocity to a change in momentum when multiplied. Matrix3x3 linearComponent; Matrix3x3.CreateScale(entity.inverseMass, out linearComponent); Matrix3x3 rACrossProduct; Matrix3x3.CreateCrossProduct(ref r, out rACrossProduct); Matrix3x3 angularComponentA; Matrix3x3.Multiply(ref rACrossProduct, ref entity.inertiaTensorInverse, out angularComponentA); Matrix3x3.Multiply(ref angularComponentA, ref rACrossProduct, out angularComponentA); Matrix3x3.Subtract(ref linearComponent, ref angularComponentA, out effectiveMassMatrix); effectiveMassMatrix.M11 += usedSoftness; effectiveMassMatrix.M22 += usedSoftness; effectiveMassMatrix.M33 += usedSoftness; Matrix3x3.Invert(ref effectiveMassMatrix, out effectiveMassMatrix); }