My friend *Sir Bob* asked me yesterday if I knew anything about drawing something like a three-dimensional box on a flat screen, like in Java, and have it so that if you were to drag the mouse, you could rotate the box.

Simply put: yes. I very briefly outlined the concept of rasterisation, how it works in a context like OpenGL, and how you could do it manually. This post is a bit of an elaboration on the "how you could do it manually" part, with basic geometry.

These are simple ways of rendering 3D objects in a 2-dimension space (like a computer screen.) Libraries like OpenGL don't do this, OpenGL uses transformation matrices; but those matrices are derived from simple geometry like this.

Converting from object-space to screen-space. For example, you may have a line
from *{0, 1, 1}* to *{1, 2, 0}*, and you want to convert it to
a line on the 2-dimensional screen.

Ignore the *z* part.

`{ x, y, z } → { x, y }`

For example: *{0, 1, 1}* becomes *{0, 1}*, and *{1, 2, 0}* becomes *{1, 2}*

Shrink things that are further from the view-point.

`{ x, y, z } → { x / (z + 1), y / (z + 1) }`

For example: *{0, 1, 1}* becomes *{0, ½}*, and *{1, 2, 0}* becomes *{1, 2}*

Moving the object in its 3-dimensional space, by rotating it about the point *{0, 0}*.

Rotate the vector *{ x, z }*

1. `current angle = ` |
`⎧ 90° ` |
`.. if x = 0, z > 0` |

`⎨ 270° ` | `.. if x = 0, z < 0` | |

`⎩ atan(z / x) ` | `.. otherwise` | |

2. `distance = ` | `sqrt(x` | |

3. `new angle = ` | `current angle + rotation` | |

4. `new point = ` | `{ x = distance × cos(new angle), z = distance × sin(new angle) }` |

Note: the *y* value doesn't change. I'm sure you can work out why not.

Rotate the vector *{ y, z }*

(as above, using *y* in place of *x*)

Rotate the vector *{ x, y }*

1. Easy solution: let the 2D render surface take care of that (eg. Java Graphics2D's `.rotate()`

— *note:* in the documentation for rotate you can see a two dimensional transformation matrix.)

2. Real solution: as above, using *y* in place of *z*

To rotate an object about a *Y* axis that isn't at *{x=0, z=0}*,
you do the same maths as above, but translate the *x* and *z*
terms so they are relative to the axis.

For example, to rotate the line above by 90° about the axis *{x=-1, z=1}*:

- the point
*{0, 1, 1}*is translated to*{1, 1, 0}*by subtracting the axis; then rotated to*{0, 1, 1}*; then translated to*{-1, 1, 2}*by adding the axis again - the point
*{1, 2, 0}*is translated to*{2, 2, -1}*, rotated to*{1, 2, 2}*, and translated back to*{3, 2, 1}*

Then to draw the line in a perspective view, the screen points are: *{-0.33, 0.33}* and *{1.5, 1}*

**Disclaimer:** I worked most of this post out in my head, so if it's wrong, tough.

Also, there are additional factors you can introduce, such as a field of view, clipping box, etc. that give you a bit more control over what you draw.

My general rule when doing anything graphical is this: don't be afraid to hold your hands out and imagine what is happening to the objects. Visualising everything is key to understanding it, much more so than the maths.

... Matty /<

- Previous: Grim Fandango ()
- Next: Collision Detection ()
- Index

- Published
- Modified
- License
- CC BY-SA 4.0
- Tags
- development, graphics