**3D perspective projection.**

If you're anything like me and you wanted to learn how 3D objects are projected on to a 2D plane (i.e. a screen), you may have come across articles like this and spent some time scratching your head, pondering a way to make sense of it. In fact, in an futile effort to implement the trigonometric functions there, I came up with something like this.

d.x = cosf(o.y*PI/180) * ( sinf(o.z*PI/180) * (a.y - c.y) + cosf(o.z*PI/180) * (a.x - c.x) ) - sinf(o.y*PI/180) * (a.z - c.z); d.y = sinf(o.x*PI/180) * ( cosf(o.y*PI/180) * (a.z - c.z) + sinf(o.y*PI/180) * (sinf(o.z*PI/180) * (a.y - c.y) + cosf(o.z*PI/180) * (a.x - c.x)) ) + cosf(o.x*PI/180) * ( cosf(o.z*PI/180) * (a.y - c.y) - sinf(o.z*PI/180) * (a.x - c.x) ); d.z = cosf(o.x*PI/180) * ( cosf(o.y*PI/180) * (a.z - c.z) + sinf(o.y*PI/180) * (sinf(o.z*PI/180) * (a.y - c.y) + cosf(o.z*PI/180) * (a.x - c.x)) ) - sinf(o.x*PI/180) * ( cosf(o.z*PI/180) * (a.y - c.y) - sinf(o.z*PI/180) * (a.x - c.x) );

As you can see, it's pretty convoluted and difficult to make sense of. Well, here's the good news, we can scrap the above code and come up with something far more simple and intuitive which does a better, cleaner and faster job.

The formula we will use does not involve trigonometry (phew!), just good ol' fashioned arithmetic. However, before we can understand the formula itself, we need to define a few concepts.

**Terminology and components of our formula**

**Perspective:**Objects viewed in perspective appear smaller when they're further away and larger when they are closer. This is typically the way we see 3D objects in real life and it's the best form of projection for a realistic scene.

**2D plane:**Our 2D plane will be our screen which we are projecting our 3D points on to. This screen can simply be thought of as a 2D array of pixels with width and height. We will need to define the width and height of our 2D plane for this formula. As a conceptual aid, you can think of this plane as a single 'slice' of 3D space.

**The viewers eye position:**This is literally where you are viewing the screen from. Your eye's position is a 3D point in space, so it will be defined using X,Y and Z coordinates.

**The point to project:**Of course, this is a 3D point with X, Y and Z coordinates. This will conceptually be behind the 2D plane.

**Our resulting 2D coordinates:**This will be the X and Y coordinate for our 2D plane (our screen).

**Visualizing the scene**

Before we get to the formula itself, let's look at how the components listed above look in real space. Note that is this example, the 2D plane has a resolution of 640x480 and the top left of the screen is (0,0).

E = The viewers eye

P = The 3D point we are projecting

S = The result of the projection on to our screen

Axes (X,Y,Z) are displayed in lower case next to the above symbolic letters. (e.g. 'Pz' is the Z axis of the 3D point)

In these images, the coordinates of the components are as follows.

NOTE: In the eye coordinates, the Z values refers to a distance, not an absolute coordinate. (the distance between the eye and the screen is 800, at least that's a rough estimate for me)

E = (320, 240, 800)

P = (600, 200, 1000)

S is then calculated as (444, 223) NOTE: It's a 2D coordinate

(these images are only an approximation to the above components)

**Birds eye view**

This view shows the X and Z (horizontal and depth) axes.

**Front view**

This view shows the X and Y (horizontal and vertical) axes.

**The formula**

The formulas to project P (3D point) onto S (our 2D screen) are quite simple, but for a more full explanation of how they work, you can go here.

To calculate the X coordinate of the projection, we have the following equation.

// ---------------------------------------- // Formula to solve Sx // ---------------------------------------- // Ez = distance from eye to the center of the screen // Ex = X coordinate of the eye // Px = X coordinate of the 3D point // Pz = Z coordinate of the 3D point // // Ez*(Px-Ex) // Sx = ----------------------- + Ex // Ez+Pz

To calculate the Y coordinate of the projection, we have the following equation.

// ---------------------------------------- // Formula to solve Sy // ---------------------------------------- // Ez = distance from eye to the center of the screen // Ey = Y coordinate of the eye // Py = Y coordinate of the 3D point // Pz = Z coordinate of the 3D point // // Ez*(Py-Ey) // Sy = ------------------- + Ey // Ez+Pz

Using those two equations, we can easily project a 3D point on to a 2D plane.

To finish off, here's a small example of how you might implement the equations in C++, for example.

#include <iostream> struct Vector2i { int x, y; }; struct Vector3i { int x, y, z; }; int main() { // lets assume 640x480 res. // Our "eye" is where we are viewing from, which // is about 800 pixels towards me and in the center of // the screen. Vector3i eye = {320, 240, 800}; // This is the point that we're projecting onto // our 2D plane. Vector3i P = {600, 200, 1000}; // This will be the 2D coords of our perspective projection. Vector2i S; // ---------------------------------------- // Formula to solve Sx // ---------------------------------------- // Ez = distance from eye to the center of the screen // Ex = X coordinate of the eye // Px = X coordinate of the 3D point // Pz = Z coordinate of the 3D point // // Ez*(Px-Ex) // Sx = ----------------------- + Ex // Ez+Pz S.x = (eye.z * (P.x-eye.x)) / (eye.z + P.z) + eye.x; // ---------------------------------------- // Formula to solve Sy // ---------------------------------------- // Ez = distance from eye to the center of the screen // Ey = Y coordinate of the eye // Py = Y coordinate of the 3D point // Pz = Z coordinate of the 3D point // // Ez*(Py-Ey) // Sy = ------------------- + Ey // Ez+Pz S.y = (eye.z * (P.y-eye.y)) / (eye.z + P.z) + eye.y; std::cout << "Result of projection.\nx: " << S.x << std::endl << "y: " << S.y; return 0; }

Thanks for reading.