The three vectors that determine a ship's orientation in space
Each ship in the Elite universe has its own set of three orientation vectors, which determine its orientation in space. These are fundamental aspects of the Elite universe, and form the basis for the ship-moving routines in MVEIT (moving the universe), MVS4 (pitching and rolling our ship) and MVS5 (pitching and rolling other ships).
There are three different vectors - nosev, roofv and sidev - with each of them pointing along one of the ship's main axes, like this:
- nosev points forward out of the nose of the ship
- roofv points up out of the ship's sunroof... or it would if it had one
- sidev points out of the ship's right view
(Note that there are five ships that have slightly different orientations to this standard model, namely Thargoids, Thargons, space stations, cargo canisters and asteroids. These orientations are described below.)
It might help to think of these vectors from the point of view of the ship's cockpit. From this perspective, the orientation vectors always look like this, with our ship at the origin:
roofv ^ | | | | nosev | / | / | / |/ +-----------------------> sidev
Every ship out there has its own set of orientation vectors, with nosev pointing out of that ship's nose, roofv pointing out of that ship's roof, and sidev out of that ship's right side. The orientation vectors are used in lots of places, for example:
- When we draw the ship on screen, we take the shape as defined by its blueprint, and rotate it so that it aligns with its orientation vectors, so the ship we draw on screen points the right way
- If an enemy ship is firing its lasers at us, we use that ship's nosev vector to work out whether it is pointing towards us, and therefore whether it can hit us
- When enemy ships pitch or roll, we can apply these movements by rotating their orientation vectors
Our ship doesn't have its own set of orientation vectors - at least, not explicitly. This is because our own ship's orientation vectors always align with the main coordinate axes: sidev aligns with the x-axis, which always points to the right from the point of view of our cockpit, while roofv aligns with the y-axis and points up, and nosev aligns with the z-axis, which always points into the screen.
Storing the vectors in the ship data block
The three vectors are stored in bytes #9-26 of the ship's data block, so when we copy a ship's data into the internal workspace INWK, the vectors live in INWK+9 to INWK+26. Each vector coordinate is stored as a 16-bit sign-magnitude number, like this:
[ INWK(10 9) ] [ INWK(16 15) ] [ INWK(22 21) ] nosev = [ INWK(12 11) ] roofv = [ INWK(18 17) ] sidev = [ INWK(24 23) ] [ INWK(14 13) ] [ INWK(20 19) ] [ INWK(26 25) ]
We can refer to these three vectors in various ways, such as these variations for the nosev vector:
nosev = (nosev_x, nosev_y, nosev_z) = [ nosev_x nosev_y nosev_z ] [ nosev_x ] = [ nosev_y ] [ nosev_z ] [ (nosev_x_hi nosev_x_lo) ] = [ (nosev_y_hi nosev_y_lo) ] [ (nosev_z_hi nosev_z_lo) ]
The three orientation vectors are orthonormal, which means they are orthogonal (i.e. they are perpendicular to each other), and normal (i.e. each of the vectors has length 1).
We can rotate a ship about its centre by rotating these vectors, as in the MVS4 routine (see the deep dive on pitching and rolling for more about this). However, because we use the small angle approximation to rotate in space, and it is not completely accurate, the three vectors tend to get a bit stretched over time, so periodically we have to tidy the vectors with the TIDY routine to ensure they remain as orthonormal as possible (see the deep dive on tidying orthonormal vectors for details).
When a new ship is spawned, its vectors are initialised in the INWK workspace by the ZINF routine as follows:
sidev = (1, 0, 0) roofv = (0, 1, 0) nosev = (0, 0, -1)
So new ships are spawned facing out of the screen, as their nosev vectors point in a negative direction along the z-axis, which is positive into the screen and negative out of the screen.
Internally, we store a vector value of 1 as 96, to support fractional values, and the orientation vectors are stored as 16-bit sign-magnitude numbers. 96 is &60, and &60 with bit 7 set is &E0, so we store the above vectors like this:
sidev = (&6000, 0, 0) roofv = (0, &6000, 0) nosev = (0, 0, &E000)
so nosev_z_hi = &E0 = -96, sidev_x_hi = &60 = 96 and so on.
Rotation matrices and axes
Sometimes we might refer to the orientation vectors as a matrix, with sidev as the first row, roofv as the second row, and nosev as the third row, like this:
[ sidev_x sidev_y sidev_z ] [ roofv_x roofv_y roofv_z ] [ nosev_x nosev_y nosev_z ]
though generally we talk about the individual vectors, because that's easier to understand. See the deep dive on calculating vertex coordinates for an example of the above matrix in use.
For the mathematically inclined, the three orientation vectors can be thought of as axes that define the 3D coordinate space orientated around the other ship - they form the basis for this space. To put it yet another way, the matrix above is a rotation matrix that transforms the axes of our ship into the axes of the other ship.
Finally, the orientation vectors define a left-handed universe, with the thumb as roofv, index finger as nosev, and middle finger as sidev.
The following ships don't have a standard orientation (all other ships follow the logical nose-roof-side pattern).
- Thargoid mothership:
- nosev points out of one side of the mothership
- roofv points out of the other side of the mothership
- sidev points out of the roof of the mothership
- nosev points out of the Thargon's nose
- roofv points out of the side of the Thargon
- sidev points out of the roof of the Thargon
- Space station:
- nosev points forward out of the docking slot
- roofv points out of the side of the space station in a direction that is parallel to the horizontal line of the slot
- sidev points out of the side of the space station in a direction that is perpendicular to the horizontal line of the slot
- Cargo canister:
- nosev points out of the side of the canister, avoiding the apexes of the pentagonal cross-section and at right-angles to roofv
- roofv points out of the side of the canister, through one of the apexes of the pentagonal cross-section
- sidev points out of one end of the canister
The asteroid also follows its own orientation, but I'm not even going to try to describe which features appear to be the the nose, roof and side, as they all just look like bumps to me.
One interesting (and presumably intentional) effect of the Thargoid and Thargon orientations can be seen when they pitch and roll. A pitching Thargoid actually spins like a traditional flying saucer (i.e. like a spinning top) as its roofv vector points out of its side (though a rolling Thargoid tilts back and forth as expected). When fighting Thargoids, you often find yourself orientating your ship to get them vertically aligned in your sights, which is because you can then track their sideways pitching with your own vertical pitching movement. This is different to the other ships, which expose their soft underbellies to your lasers when they try to pitch out of your way.
That's Thargoids for you. Different... and deadly.