﻿ Planes in 3D Graphics Planes in 3D Graphics  Site Map Feedback      gCoord Points Vectors PV Planes  ## Planes in 3D Graphics

gPlane is the first step to posing uniformly scaled 3D Objects, or placing things in 3D space.

The key thing with the journey to making a 3D world is deciding which conventions to follow when there are several ways of doing things that appear similar. The set of conventions used here result in great optimisations later on in the system.

### A Right-Handed World

Put a piece of paper on a table and think of its bottom left corner as the Global Origin - the point (0,0,0). The bottom edge is the X-axis pointing to the right, and the Left edge is the Y-Axis pointing forwards just like a map; the Z-Axis is 'up'.

When given a choice, opt for the most natural option: the Right Hand Rule is used because everyone (especially left-handed people) agrees that we live in a right-handed person's world, so it is easy to remember "It's a Right-Handed World". OpenGL uses a Right Hand world with the Y-Axis being up (it's thinking of the world through a vertical screen, not as a map on a desk). DirectX uses a Left Hand world with the Y-Axis being up. Feeding your worlds global coordinate system to another system is not difficult, so (as no standard exists) use the most natural: the right hand and a map (or XY graph that is taught at school). Another way to see the world as a coordinate system is to think of a tiled floor: each tile is a coordinate in the XY plane. Pick an origin and define the location of your chair relative to the origin.

### Planes are for drawing on

To fully imagine a new plane that is more useful, a plane that we can draw on is needed, but rather than hold up a sheet of paper for ages, look for a rectangular flat window with a spot of dirt on. The bottom left-hand corner is the window's origin, its X-Axis is along its bottom, its Y-Axis is up its left-hand edge and its Z-Axis will be towards you. The spot of dirt on the window is at a particular point on the window's plane which you can measure in two dimensions (X,Y) where X is how far from the left edge the spot is (distance from its origin in the X direction), and Y is how far from the bottom edge the spot is (distance from its origin in the Y direction).

### From the Plane's drawing to the World and back

gPlane holds the window's details and allows you to do things like convert the spot's coordinates from being relative to the Window Plane, to relative to the piece of paper on your desk. Transforming coordinates from Local to Global and back allows us to draw on a two dimensional plane and place the two dimensional objects in the three dimensional world. It also allows us to render the three dimensional world onto a two dimensional screen. If the spot of dirt on the window lines up with something outside (assuming you're currently inside), you can imagine that the thing outside has global coordinates that can be mapped onto the window's two dimensional coordinate system. gPlane can do that for you very quickly and efficiently.

To know everything about the window, gPlane needs to hold a the Window's Origin as a point relative to the Global Origin (the corner of your piece of paper). gPlane also needs to store the coordinate system of the window as three orthogonal unit vectors relative to the Global unit vectors (the edges of your piece of paper). It it not enough to just store the Plane's Origin and Normal (the Z-Axis): that doesn't tell you which round the plane is (the X-Axis could be any direction away from the origin on the plane): the spot of dirt can not be located without specifying an axis on the plane.

There are conventions for creating the other axes from a Normal axis that are used in Computer Aided Machining: a system may specify that the X or Y axis should be horizontal. That leaves two potential directions for the third axis to lie. That decision is made using another boolean: 'Clockwise Twist' which means: looking down the horizontal axis to the origin, the third axis is clockwise from the normal (or not). Those principles are handled within g3Vector::GetAxes which uses HorizontalAxisType to create new axes from a normal vector.

So it is necessary to store at least one other axis as well as the Normal...

### The Magic Begins...

If all three axes are stored, they can be held in such a way that they form a transformation matrix which can directly transform points! This speeds up many processes including 'camera placement' as used by gPose which is derived from gPlane. To make this work, the axes need to be stored as 'unit vectors' which means that the vector length is exactly 1. g3Vector::Normalise() will set the length to 1.

If 'Origin' is the Local Origin (in World Coordinates) and xAxis, yAxis and zAxis are the normalised local axes, they can be stored as a transformation matrix as follows:

```M={xAxis.x, yAxis.x, zAxis.x, Origin.x,
xAxis.y, yAxis.y, zAxis.y, Origin.y,
xAxis.z, yAxis.z, zAxis.z, Origin.z};
```
Since gPlane owns this transformation matrix, it is natural to think of that matrix as the plane's way to convert from Local to Global coordinates.
The method: g3Point TransformToPlane(const g3Point& p) const; simply multiplies the point, p by the above matrix and the result is the point in global coordinates.

To translate from global to local coordinates, the global point must be multiplied by the inverse of the matrix. Calculating the inverse of a matrix is verbose but, fortunately, our matrix is a little special in that the 3x3 part holding the normalised vectors is entirely orthogonal and the inverse of an orthogonal matrix is its transpose, so all that is needed for that part is to mirror the positions of the numbers in the matrix around the leading diagonal! The inverse of the point section is a projection that reduces to a dot product leaving:

```I={xAxis.x, xAxis.y, xAxis.z, -xAxis.Dot(Origin),
yAxis.x, yAxis.y, yAxis.z, -yAxis.Dot(Origin),
zAxis.x, zAxis.y, zAxis.z, -zAxis.Dot(Origin)};
```
It may be useful to know that the z projection I is the distance from the global origin to the closest part of the plane...

Rather than re-calculate these values, gPlane stores both the matrix and its inverse for fast transformations. When you come to serialize a gPlane (save and load) you only need to save the xAxis,zAxis and Origin. zAxis is generally the most important one to be accurate, so store that and when you load the gPlane, yAxis=zAxis.Cross(xAxis);

Graphics libraries like OpenGL work using 4x4 matrices but that holds no advantages here and makes finding the inverse far more time consuming and verbose. gglCamera.h shows how to implement an OpenGL interface from a gPlane.

### Flat Land

Imagine a tree with rectangular leaves. Most of the leaves will need their own plane onto which a rectangle is drawn. An optimisation is to notice that all horizontal leaves could use the global XY plane as a drawing surface and the z coordinate says how high off the floor that leaf is. gPlane can recognise that you asked for a horizontal plane and simply use Flat-land (no transormation required). Unless you call NoFlatLand(), optimisations are used if the plane is horizontal and its X-Axis is in the same direction as the global X-Axis (FlatLand==true) and Local coordinates are the same as Global coordinates.  