Page 1 of 1

## 3D perspective projection

### #1 Aphex19

• Born again Pastafarian.

Reputation: 616
• Posts: 1,873
• Joined: 02-August 09

Posted 12 July 2011 - 11:36 AM

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;
}

Is This A Good Question/Topic? 3

## Replies To: 3D perspective projection

### #2 stayscrisp

• フカユ

Reputation: 1037
• Posts: 4,305
• Joined: 14-February 08

Posted 21 July 2011 - 05:01 AM

Nice work!

### #3 Aphex19

• Born again Pastafarian.

Reputation: 616
• Posts: 1,873
• Joined: 02-August 09

Posted 21 July 2011 - 06:57 AM

stayscrisp, on 21 July 2011 - 06:01 AM, said:

Nice work!

Thanks. There's not many tutorials out there which just give the absolute basics of 3D projection, it was my hope that this would help people looking for tutorials like those. I'm not a particularly talented author but I hope it might help push somebody in the right direction.

### #4 ivan.f

• New D.I.C Head

Reputation: 0
• Posts: 1
• Joined: 18-December 11

Posted 18 December 2011 - 04:23 PM

Hi,

I've found your tutorial very helpful. But there is one thing that is bothering me:

What about the units in which the points (E, P) coordinates are according to the screen points coordinates which are in pixels?

Best regards,
Ivan

### #5 Aphex19

• Born again Pastafarian.

Reputation: 616
• Posts: 1,873
• Joined: 02-August 09

Posted 13 February 2012 - 01:00 AM

ivan.f, on 18 December 2011 - 04:23 PM, said:

Hi,

I've found your tutorial very helpful. But there is one thing that is bothering me:

What about the units in which the points (E, P) coordinates are according to the screen points coordinates which are in pixels?

Best regards,
Ivan

They're specified in units of screen pixels, yes. It's not necessarily a very useful unit to use when dealing with three dimensions though, admittedly.

Just think of this as if the space is really there. That is, imagine your monitor as a see through box, where the objects beyond it are a real distance away. This distance, in this case, is measured in units of pixels.

This post has been edited by Aphex19: 13 February 2012 - 01:07 AM