Author: Not specified Language: text
Description: Not specified Timestamp: 2013-06-03 01:47:21 +0000
View raw paste Reply
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. [AddComponentMenu("Cosmic Storm/Autopilot")]
  5. public class Autopilot : MonoBehaviour {
  6.         private Ship ship;
  7.        
  8.         public void Start() {
  9.                 ship = GetComponent<Ship>();
  10.         }
  11.        
  12.         public void RotateToward(Vector3 finalForward, float maxTorque, float turnRate) {
  13.                 ship.antiSpin = false;
  14.                 Vector3 targetRotationAxis = Vector3.Cross(finalForward, transform.forward).normalized;
  15.         // the target rotation axis is an axis that is perpendicular to both the current forward, and the forward the ship will eventually have.
  16.                 if (targetRotationAxis == Vector3.zero && rigidbody.angularVelocity.sqrMagnitude <= 0.001f)
  17.                         targetRotationAxis = Vector3.up;
  18.             // if the current forward and the eventual forward are already aligned, use Vector3.up as the rotation axis. This prevents universe implosion.
  19.                 float forwardAngleDifference = 180 - Vector3.Angle(finalForward, transform.forward);
  20.         // the forward angle difference is the angle between the current forward and the eventual forward.
  21.                 float angularVelocityDampening;
  22.         // the "angular velocity dampening" coefficient is a number that is zero when forward angle difference is zero, and goes up to one when forward angle difference is 180.
  23.         // its purpose is to keep the ship's angular velocity low when the forward angle difference becomes small, so it doesn't overshoot and start oscillating.
  24.         if (forwardAngleDifference >= 180 / Mathf.Sqrt(Mathf.PI * Mathf.PI - 1)) {
  25.                         angularVelocityDampening = Mathf.PI * Mathf.PI * forwardAngleDifference * forwardAngleDifference /
  26.                                 ((Mathf.PI * Mathf.PI -1) * forwardAngleDifference * forwardAngleDifference + 32400);
  27.             // this is the default expression for AVD.
  28.                 }
  29.                 else {
  30.                         ship.antiSpin = true;
  31.                         angularVelocityDampening = Mathf.PI * Mathf.PI * forwardAngleDifference / (360 * Mathf.Sqrt(Mathf.PI * Mathf.PI - 1));
  32.             // when the forward angle difference is low enough, AVD switches to a linear function, and turns antiSpin on so as to avoid overshooting the target vector.
  33.                 }
  34.                 Vector3 targetAngularVelocity = turnRate * Mathf.Deg2Rad * angularVelocityDampening * targetRotationAxis; // Mathf.Pow(0.5f, 30 / forwardAngleDifference)
  35.         // target angular velocity is the angular velocity the ship needs to be at in order to follow the intended rotation profile exactly.
  36.         // because the ship may start out with a variety of initial rotations and starting positions, it may not be able to reach target angular velocity in a single frame.
  37.         Vector3 targetAcceleration = (targetAngularVelocity - rigidbody.angularVelocity) / Time.fixedDeltaTime;
  38.         // target acceleration is the acceleration the ship would need to exert on itself in order to reach the target angular velocity at the start of the next frame.
  39.                 Quaternion inertiaTensorRotation = transform.rotation * rigidbody.inertiaTensorRotation;
  40.         // the inertia tensor is the vector containing the moments of inertia about the local x, y, and z axes.
  41.         // rigidbody.inertiaTensorRotation is the rotation of rigidbody.inertiaTensor from the local coordinate system.
  42.         // inertiaTensorRotation is the quaternion that describe's rigidbody.inertiaTensor's rotation relative to the universal coordinate system.
  43.                 Vector3 targetTorque = inertiaTensorRotation * Vector3.Scale(rigidbody.inertiaTensor, (Quaternion.Inverse(inertiaTensorRotation) * targetAcceleration));
  44.         // Quaternion.Inverse(inertiaTensorRotation) rotates targetAcceleration into the same coordinate system as rigidbody.inertiaTensor,
  45.         // such that targetAcceleration is now expressed in terms of accelerations about the local x, y, and z axes.
  46.         // Scaling it by rigidbody.inertiaTensor produces a vector <Ixx * Axx = Txx, Iyy * Ayy = Tyy, Izz * Azz = Tzz>.
  47.         // Then multiplying that by inertiaTensorRotation rotates it back into the universal coordinate system.
  48.         // Thus, target torque is the torque required for the angular velocity to reach its target by the next frame.
  49.                 if ((forwardAngleDifference < 1) && (rigidbody.angularVelocity.sqrMagnitude < 0.01f)) {
  50.                         rigidbody.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(-finalForward, transform.up), 0.01f);
  51.                         rigidbody.angularVelocity = Vector3.zero;
  52.                 }
  53.                 else if (targetTorque.magnitude <= maxTorque) {
  54.                         // return targetTorque;
  55.                         rigidbody.angularVelocity = targetAngularVelocity;
  56.                 }
  57.                 else {
  58.                         // return maxTorque * targetTorque.normalized;
  59.                         float scalarMomentOfInertia = targetTorque.magnitude / targetAcceleration.magnitude;
  60.                         float maxAcceleration = maxTorque / scalarMomentOfInertia;
  61.                         rigidbody.angularVelocity += maxAcceleration * targetAcceleration.normalized * Time.fixedDeltaTime;
  62.                 }
  63.         }
  64. }
  65.  
View raw paste Reply