Directions

Direction objects represent a rotation starting from an initial point in KSP‘s coordinate system where the initial state was looking down the \(+z\) axis, with the camera “up” being the \(+y\) axis. This exists primarily to enable automated steering.

In your thinking, you can largely think of Directions as being Rotations and Rotations as being Directions. The two concepts can be used interchangeably. Used on its own to steer by, a rotation from the default XYZ axes of the universe into a new rotation does in fact provide an absolute direction, thus the name Direction for these objects even though in reality they are just Rotations. It’s important to know that Directions are just rotations because you can use them to modify other directions or vectors.

Note

When dealing with Directions (which are Rotations) in kOS, it is important to remember that KSP uses a left-handed coordinate system. This affects the convention of which rotation direction is positive when calculating angles.

Creation

Method Description
R(pitch,yaw,roll) Euler rotation
Q(x,y,z,rot) Quaternion
HEADING(dir,pitch,roll) Compass heading
LOOKDIRUP(lookAt,lookUp) Looking along vector lookAt, rolled so that lookUp is upward.
ANGLEAXIS(degrees,axisVector) A rotation that would rotate the universe around an axis
ROTATEFROMTO(fromVec,toVec) A rotation that would go from vectors fromVec to toVec
FACING From SHIP or TARGET
UP From SHIP
PROGRADE, etc. From SHIP, TARGET or BODY
R(pitch,yaw,roll)

A Direction can be created out of a Euler Rotation, indicated with the R() function, as shown below where the pitch, yaw and roll values are in degrees:

SET myDir TO R( a, b, c ).
Q(x,y,z,rot)

A Direction can also be created out of a Quaternion tuple, indicated with the Q() function, passing it the x, y, z, w values of the Quaternion. The concept of a Quaternion uses complex numbers and is beyond the scope of the kOS documentation, which is meant to be simple to understand. It is best to not use the Q() function unless Quaternions are something you already understand.

SET myDir TO Q( x, y, z, w ).
HEADING(dir,pitch,roll)

A Direction can be created out of a HEADING() function. The first parameter is the compass heading, and the second parameter is the pitch above the horizon:

SET myDir TO HEADING(degreesFromNorth, pitchAboveHorizon).

The third parameter, roll, is optional. Roll indicates rotation about the longitudinal axis.

LOOKDIRUP(lookAt,lookUp)

A Direction can be created with the LOOKDIRUP function by using two vectors. This is like converting a vector to a direction directly, except that it also provides roll information, which a single vector lacks. lookAt is a vector describing the Direction’s FORE orientation (its local Z axis), and lookUp is a vector describing the direction’s TOP orientation (its local Y axis). Note that lookAt and lookUp need not actually be perpendicualr to each other - they just need to be non-parallel in some way. When they are not perpendicular, then a vector resulting from projecting lookUp into the plane that is normal to lookAt will be used as the effective lookUp instead:

// Aim up the SOI's north axis (V(0,1,0)), rolling the roof to point to the sun.
LOCK STEERING TO LOOKDIRUP( V(0,1,0), SUN:POSITION ).
//
// A direction that aims normal to orbit, with the roof pointed down toward the planet:
LOCK normVec to VCRS(SHIP:BODY:POSITION,SHIP:VELOCITY:ORBIT).  // Cross-product these for a normal vector
LOCK STEERING TO LOOKDIRUP( normVec, SHIP:BODY:POSITION).
ANGLEAXIS(degrees,axisVector)

A Direction can be created with the ANGLEAXIS function. It represents a rotation of degrees around an axis of axisVector. To know which way a positive or negative number of degrees rotates, remember this is a left-handed coordinate system:

// Pick a new rotation that is pitched 30 degrees from the current one, taking into account
// the ship's current orientation to decide which direction is the 'pitch' rotation:
//
SET pitchUp30 to ANGLEAXIS(-30,SHIP:STARFACING).
SET newDir to pitchUp30*SHIP:FACING.
LOCK STEERING TO newDir.

Note

The fact that KSP is using a left-handed coordinate system is important to keep in mind when visualizing the meaning of an ANGLEAXIS function call. It affects which direction is positive when calculating angles.

ROTATEFROMTO(fromVec,toVec)

A Direction can be created with the ROTATEFROMTO function. It is one of the infinite number of rotations that could rotate vector fromVec to become vector toVec (or at least pointing in the same direction as toVec, since fromVec and toVec need not be the same magnitude). Note the use of the phrase “infinite number of”. Because there’s no guarantee about the roll information, there are an infinite number of rotations that could qualify as getting you from one vector to another, because there’s an infinite number of roll angles that could result and all still fit the requirement:

SET myDir to ROTATEFROMTO( v1, v2 ).
Suffix terms from other structures

A Direction can be made from many suffix terms of other structures, as shown below:

SET myDir TO SHIP:FACING.
SET myDir TO TARGET:FACING.
SET myDir TO SHIP:UP.

Whenever a Direction is printed, it always comes out showing its Euler Rotation, regardless of how it was created:

// Initializes a direction to prograde
// plus a relative pitch of 90
SET X TO SHIP:PROGRADE + R(90,0,0).

// Steer the vessel in the direction
// suggested by direction X.
LOCK STEERING TO X.

// Create a rotation facing northeast,
// 10 degrees above horizon
SET Y TO HEADING(45, 10).

// Steer the vessel in the direction
// suggested by direction X.
LOCK STEERING TO Y.

// Set by a rotation in degrees
SET Direction TO R(0,90,0).

Structure

structure Direction

The suffixes of a Direction cannot be altered, so to get a new Direction you must construct a new one.

Suffix Type Description
PITCH scalar (deg) Rotation around \(x\) axis
YAW scalar (deg) Rotation around \(y\) axis
ROLL scalar (deg) Rotation around \(z\) axis
FOREVECTOR Vector This Direction’s forward vector (z axis after rotation).
VECTOR Vector Alias synonym for FOREVECTOR
TOPVECTOR Vector This Direction’s top vector (y axis after rotation).
UPVECTOR Vector Alias synonym for TOPVECTOR
STARVECTOR Vector This Direction’s starboard vector (z axis after rotation).
RIGHTVECTOR Vector Alias synonym for STARVECTOR
INVERSE Direction The inverse of this direction.
- (unary minus) Direction Using the negation operator - on a Direction does the same thing as using the :INVERSE suffix on it.

The Direction object exists primarily to enable automated steering. You can initialize a Direction using a Vector or a Rotation. Direction objects represent a rotation starting from an initial point in KSP‘s coordinate system where the initial state was looking down the \(+z\) axis, with the camera “up” being the \(+y\) axis. So for example, a Direction pointing along the \(x\) axis might be represented as R(0,90,0), meaning the initial \(z\)-axis direction was rotated 90 degrees around the \(y\) axis.

If you are going to manipulate directions a lot, it’s important to note that the order in which the rotations occur is:

  1. First rotate around \(z\) axis.
  2. Then rotate around \(x\) axis.
  3. Then rotate around \(y\) axis.

What this means is that if you try to ROLL and YAW in the same tuple, like so: R(0,45,45), you’ll end up rolling first and then yawing, which might not be what you expected. There is little that can be done to change this as it’s the native way things are represented in the underlying Unity engine.

Also, if you are going to manipulate directions a lot, it’s important to note how KSP‘s native coordinate system works.

Direction:PITCH
Type:Scalar (deg)
Access:Get only

Rotation around the \(x\) axis.

Direction:YAW
Type:Scalar (deg)
Access:Get only

Rotation around the \(y\) axis.

Direction:ROLL
Type:Scalar (deg)
Access:Get only

Rotation around the \(z\) axis.

Direction:FOREVECTOR
Type:Vector
Access:Get only

Vector of length 1 that is in the same direction as the “look-at” of this Direction. Note that it is the same meaning as “what the Z axis of the universe would be rotated to if this rotation was applied to the basis axes of the universe”. When you LOCK STEERING to a direction, that direction’s FOREVECTOR is the vector the nose of the ship will orient to. SHIP:FACING:FOREVECTOR is the way the ship’s nose is aimed right now.

Direction:TOPVECTOR
Type:Vector
Access:Get only

Vector of length 1 that is in the same direction as the “look-up” of this Direction. Note that it is the same meaning as “what the Y axis of the universe would be rotated to if this rotation was applied to the basis axes of the universe”. When you LOCK STEERING to a direction, that direction’s TOPVECTOR is the vector the roof of the ship will orient to. SHIP:FACING:TOPVECTOR is the way the ship’s roof is aimed right now.

Direction:STARVECTOR
Type:Vector
Access:Get only

Vector of length 1 that is in the same direction as the “starboard side” of this Direction. Note that it is the same meaning as “what the X axis of the universe would be rotated to if this rotation was applied to the basis axes of the universe”. When you LOCK STEERING to a direction, that direction’s STARVECTOR is the vector the right wing of the ship will orient to. SHIP:FACING:STARVECTOR is the way the ship’s right wing is aimed right now.

Direction:INVERSE
Type:Direction
Access:Get only
Struct:Gives a Direction with the opposite rotation around its axes.

Operations and Methods

You can use math operations on Direction objects as well. The next example uses a rotation of “UP” which is a system variable describing a vector directly away from the celestial body you are under the influence of:

Supported Direction Operators:

Direction Multiplied by Direction:
 

Dir1 * Dir2 - This operator returns the result of rotating Dir2 by the rotation of Dir1. Note that the order of operations matters here. Dir1*Dir2 is not the same as Dir2*Dir1. Example:

// A direction pointing along compass heading 330, by rotating NORTH by 30 degrees around UP axis:
SET newDir TO ANGLEAXIS(30,SHIP:UP) * NORTH.
Direction Multiplied by Vector:
 

Dir * Vec - This operator returns the result of rotating the vector by Dir:

// What would the velocity of your ship be if it was angled 20 degrees to your left?
SET Vel to ANGLEAXIS(-20,SHIP:TOPVECTOR) * SHIP:VELOCITY:ORBIT.
// At this point Vel:MAG and SHIP:VELOCITY:MAG should be the same, but they don't point the same way
Direction Added to Direction:
 

Dir1 + Dir2 - This operator is less reliable because its exact behavior depends on the order of operations of the UnityEngine’s X Y and Z axis rotations, and it can result in gimbal lock.

It’s supposed to perform a Euler rotation of one direction by another, but it’s preferred to use Dir*Dir instead, as that doesn’t experience gimbal lock, and does not require that you know the exact transformation order of Unity.

For vector operations, you may use the :VECTOR suffix in combination with the regular vector methods:

SET dir TO SHIP:UP.
SET newdir TO VCRS(SHIP:PROGRADE:VECTOR, dir:VECTOR)

The Difference Between Vectors and Directions

There are some consequences when converting from a Direction to a Vector and vice versa which should not be overlooked.

A Vector and a Direction can be represented with the exact same amount of information: a tuple of 3 floating point numbers. So you might wonder why it is that a Vector can hold information about the magnitude of the line segment, while a Direction cannot, given that both have the same amount of information. The answer is that a Direction does contain one thing a Vector does not. A Direction knows which way is “up”, while a Vector does not. If you tell kOS to LOCK STEERING to a Vector, it will be able to point the nose of the vessel in the correct direction, but won’t know which way you want the roof of the craft rotated to. This works fine for axial symmetrical rockets but can be a problem for airplanes.

Therefore if you do this:

SET MyVec to V(100,200,300).
SET MyDir to MyVec:DIRECTION.

Then MyDir will be a Direction, but it will be a Direction where you have no control over which way is “up” for it.