/// <summary> /// Lerps a rotation by time. /// </summary> /// <param name="aTime">The time.</param> /// <returns>The rotation.</returns> public BEPUutilities.Quaternion LerpRotate(double aTime) { if (Rotations.Count == 0) { return(BEPUutilities.Quaternion.Identity); } if (Rotations.Count == 1) { return(Rotations[0]); } int index = FindRotate(aTime); int nextIndex = index + 1; if (nextIndex >= Rotations.Count) { return(Rotations[0]); } double deltaT = RotTimes[nextIndex] - RotTimes[index]; double factor = (aTime - RotTimes[index]) / deltaT; if (factor < 0 || factor > 1) { return(Rotations[0]); } BEPUutilities.Quaternion start = Rotations[index]; BEPUutilities.Quaternion end = Rotations[nextIndex]; BEPUutilities.Quaternion res = BEPUutilities.Quaternion.Slerp(start, end, (double)factor); res.Normalize(); return(res); }
/// <summary> /// Get the angle around an axis for a specific quaternion. /// </summary> /// <param name="rotation">The quaternion.</param> /// <param name="axis">The relative axis.</param> /// <returns>The angle.</returns> public static double AxisAngleFor(this BEPUutilities.Quaternion rotation, Vector3 axis) { Vector3 ra = new Vector3(rotation.X, rotation.Y, rotation.Z); Vector3 p = Utilities.Project(ra, axis); BEPUutilities.Quaternion twist = new BEPUutilities.Quaternion(p.X, p.Y, p.Z, rotation.W); twist.Normalize(); Vector3 new_forward = BEPUutilities.Quaternion.Transform(Vector3.UnitX, twist); return(Utilities.VectorToAngles(new Location(new_forward)).Yaw *Math.PI / 180.0); }
public override void ExclusiveUpdate() { if (Plane.PlanePilot == null) { return; // Don't fly when there's nobody driving this! } // TODO: Special case for motion on land: only push forward if W key is pressed? Or maybe apply that rule in general? // Collect the plane's relative vectors BEPUutilities.Vector3 forward = BEPUutilities.Quaternion.Transform(BEPUutilities.Vector3.UnitY, Entity.Orientation); BEPUutilities.Vector3 side = BEPUutilities.Quaternion.Transform(BEPUutilities.Vector3.UnitX, Entity.Orientation); BEPUutilities.Vector3 up = BEPUutilities.Quaternion.Transform(BEPUutilities.Vector3.UnitZ, Entity.Orientation); // Engines! if (Plane.PlanePilot.SprintOrWalk >= 0.0) { BEPUutilities.Vector3 force = forward * (Plane.PlaneRegularStrength + Plane.PlaneFastStrength) * Delta; entity.ApplyLinearImpulse(ref force); } double dotforw = BEPUutilities.Vector3.Dot(entity.LinearVelocity, forward); entity.ApplyImpulse(side * 5 + entity.Position, up * -Plane.PlanePilot.XMove * entity.Mass * dotforw * 0.5 * Delta); entity.ApplyImpulse(forward * 5 + entity.Position, side * ((Plane.PlanePilot.ItemRight ? 1 : 0) + (Plane.PlanePilot.ItemLeft ? -1 : 0)) * entity.Mass * dotforw * 0.5 * Delta); entity.ApplyImpulse(forward * 5 + entity.Position, up * Plane.PlanePilot.YMove * entity.Mass * 0.5 * Delta * dotforw); // Rotate the entity pre-emptively, and re-apply the movement velocity in this new direction! double vellen = entity.LinearVelocity.Length(); BEPUutilities.Vector3 normvel = entity.LinearVelocity / vellen; BEPUutilities.Vector3 norm_vel_transf = BEPUutilities.Quaternion.Transform(normvel, BEPUutilities.Quaternion.Inverse(entity.Orientation)); // Probably just 1,0,0 on whichever axis... can be simplified! BEPUutilities.Vector3 inc = entity.AngularVelocity * Delta * 0.5; BEPUutilities.Quaternion quat = new BEPUutilities.Quaternion(inc.X, inc.Y, inc.Z, 0); quat = quat * entity.Orientation; BEPUutilities.Quaternion orient = entity.Orientation; BEPUutilities.Quaternion.Add(ref orient, ref quat, out orient); orient.Normalize(); entity.Orientation = orient; entity.LinearVelocity = BEPUutilities.Quaternion.Transform(norm_vel_transf, orient) * vellen; entity.AngularVelocity *= 0.1; // Apply air drag Entity.ModifyLinearDamping(Plane.PlanePilot.SprintOrWalk < 0.0 ? 0.6 : 0.1); // TODO: arbitrary constant Entity.ModifyAngularDamping(0.5); // TODO: arbitrary constant // Ensure we're active if flying! Entity.ActivityInformation.Activate(); }