Aviator on the BBC Micro

# Rotating and translating points in 3D space

## Converting between different frames of reference in 3D

The deep dives on 3D objects and rotation matrices go into a lot of detail about transforming points and vectors between different frames of reference by rotation and translation, but it's probably easier to see what's happening when talking about a concrete example. Here we take a deeper look at how rotation matrices are used when calculating 3D coordinates for points within objects, as this covers all the main parts of the process.

## Rotating points with SetPointCoords -----------------------------------

The SetPointCoords routine takes a set of 3D coordinates that define a point in space, and rotates them around the origin to a new set of coordinates. It does this by taking the point's coordinates, multiplying them by one of the four rotation matrices, and storing the result to give us the point's new coordinates. See the deep dive on rotation matrices for details of the matrices and how they are calculated.

Specifically, let's take an example:

• Say the point is at coordinates (xPoint, yPoint, zPoint), where each coordinate is a 16-bit value, e.g. xPoint = (xPointHi xPointLo)
• Say we want to rotate the object by matrix 1, where:
```  m0 = (matrix1Hi matrix1Lo)
m1 = (matrix1Hi+1 matrix1Lo+1)
...
m8 = (matrix1Hi+8 matrix1Lo+8)
```

Given the above, calling the SetPointCoords routine would update the point's coordinates as follows:

```  [ xPoint ]     [ m0 m1 m2 ]   [ xPoint ]
[ yPoint ]  =  [ m3 m4 m5 ] x [ yPoint ]
[ zPoint ]     [ m6 m7 m8 ]   [ zPoint ]
```

On its own, this simply rotates a point around the origin. Now let's take a look at one example of this in action.

## Rotating and translating multi-point objects in 3D space --------------------------------------------------------

The SetObjPointCoords routine calculates the coordinates for a point within an object (an "object point"). Object points are stored as coordinates that are relative to the object's anchor point, so the definition for the tree object contains the points for a tree, stored as if it were at the origin, in the outside world's frame of reference. To draw the object as seen out of the canopy of the plane, we need to transform these anchor-relative coordinates into coordinates that are relative to the pilot and in the plane's frame of reference.

We do this by taking the object point's coordinates relative to the object's anchor (i.e. the vector from the anchor to the point), and rotating this vector to the plane's frame of reference by multiplying by matrix 1 (this multiplication is the rotation step). We also take the object's anchor point, and move this to the plane's frame of reference, again by rotating my matrix 1. Finally we add the two together (this addition is the translation step). This gives us the final coordinates of the object point, relative to the pilot, which is the same as saying it's relative to the screen.

Specifically, let's take an example:

• Say the object's anchor point is at (xObject, yObject, zObject), relative to the outside world (this value would typically come from the (xObjectHi xObjectLo), (yObjectHi yObjectLo), (zObjectHi zObjectLo) tables)
• Say the object point has coordinates of (xObjectPoint, yObjectPoint, zObjectPoint) relative to the object's anchor (in other words, this is the vector from the anchor to the point)
• Say we want to rotate the object by matrix 1, so:
```m0 = (matrix1Hi matrix1Lo)
m1 = (matrix1Hi+1 matrix1Lo+1)
...
m8 = (matrix1Hi+8 matrix1Lo+8)
```

Given the above, the SetObjPointCoords routine calculates the object point's 3D coordinates as follows:

```  [ xPoint ]   [ xObjectP ]   [ xObjectPointP ]
[ yPoint ] = [ yObjectP ] + [ yObjectPointP ]
[ zPoint ]   [ zObjectP ]   [ zObjectPointP ]
```

where:

```  [ xObjectP ]     [ m0 m1 m2 ]   [ xObject ]
[ yObjectP ]  =  [ m3 m4 m5 ] x [ yObject ]
[ zObjectP ]     [ m6 m7 m8 ]   [ zObject ]
```

and:

```  [ xObjectPointP ]     [ m0 m1 m2 ]   [ xObjectPoint ]
[ yObjectPointP ]  =  [ m3 m4 m5 ] x [ yObjectPoint ] x 2^scaleFactor / 16
[ zObjectPointP ]     [ m6 m7 m8 ]   [ zObjectPoint ]
```

The scale factor is a power of 2 whose exponent is extracted from bits 4 to 7 of zObjectPoint, and in the final result we drop the least significant byte of the calculation, so the result is effectively divided by another 256. Only bits 0 to 3 of xObjectPoint, yObjectPoint and zObjectPoint are used in the matrix multiplication; bits 4 to 7 of xObjectPoint and yObjectPoint are ignored (and happen to be 0).

The scale factor determines the size of the object, and this is how the alien objects grow in size while feeding - the scale factor is incremented to double the alien's size. Other objects have static scale factors, but it enables the same object point system to be used for all sorts of different object sizes, from trees, runways and fields, all the way to hills, lakes, bridges and towns.