How to calculate 3D objects
2004-04-17
Written by PerErik Klarenfjord
Contents:
1. Setup and rotate a 3D object
2. Calculate 3D -> 2D (computer screen) with perspective
3. Example of rotating algorithms in C
4. Receive coordinates in 3D from a picture in 2D with perspective
1. Setup and rotate a 3D object
Coordinates of points in a 3D object can be described by using the X, Y and Z cartesian coordinates. In this document you may see the coordinates of a point as (X, Y, Z), i.e. (20, -30, 40) means X=20, Y=-30, Z=40. (0, 0, 0) is allways the coordinates of reference and can be located in the middle of the object.
Negative values of X is to the left of (0, 0, 0).
Negative values of Y is above (0, 0, 0).
Negative values of Z is deeper into the screen relative (0, 0, 0).
A 3D object contains several points. A cube has a point in every corner which give us 8 points. The points of the cube can have values like:
(20, 20, 20), (-20, 20, 20), (-20, -20, 20), (20, -20, 20), (20, 20, -20), (-20, 20, -20), (-20, -20, -20), (20, -20, -20)

The side of the cube has the length 2*20=40.
We are now going to derive the formulas needed for rotating a 3D object, i.e. calculate new coordinates for every point in the object. It's rather simple to use linear algebra and matrix multiplication to derive the formulas. If you are not familiar with this kind of mathematics you can still use the finnished formulas later in this section.
To rotate around the Y axis an angular A:
| cos(A) 0 sin(A)| |x| |Sx|
My * MX = Ms => | 0 1 0 | |y| = |Sy|
|-sin(A) 0 cos(A)| |z| |Sz|
x, y and z (MX) are the coordinates of a point before rotation. |1 0 0 | |x| |Sx|
Mx * MX = Ms => |0 cos(B) sin(B)| |y| = |Sy|
|0 -sin(B) cos(B)| |z| |Sz|
Sx = x | cos(C) sin(C) 0| |x| |Sx|
Mz * MX = Ms => |-sin(C) cos(C) 0| |y| = |Sy|
| 0 0 1| |z| |Sz|
Sx = x*cos(C) + y*sin(C)| cos(A) 0 sin(A)| |1 0 0 | | cos(C) sin(C) 0| |x| |Sx| => | 0 1 0 | |0 cos(B) sin(B)| |-sin(C) cos(C) 0| |y| = |Sy| |-sin(A) 0 cos(A)| |0 -sin(B) cos(B)| | 0 0 1| |z| |Sz|Sx = x*(cos(A)*cos(C) + sin(A)*sin(B)*sin(C)) + y*(cos(A)*sin(C) - sin(A)*sin(B)*cos(C)) + z*(sin(A)*cos(B))

#include <math.h>
// Calculate coordinates after rotation
void calculate(const int fig[][3], int matrix[][2], double angle_a, double angle_b, double angle_c, int numb, int depth)
{
int s;
double H, Sx, Sy, Sz;
double cos_a = cos(angle_a);
double sin_a = sin(angle_a);
double cos_b = cos(angle_b);
double sin_b = sin(angle_b);
double cos_c = cos(angle_c);
double sin_c = sin(angle_c);
for(s = 0; s < numb; s++)
{
// Algorithm 1
Sx = fig[s][0]*(cos_a*cos_c + sin_a*sin_b*sin_c) + fig[s][1]*(cos_a*sin_c - sin_a*sin_b*cos_c) + fig[s][2]*(sin_a*cos_b);
Sy = fig[s][0]*(-cos_b*sin_c) + fig[s][1]*(cos_b*cos_c) + fig[s][2]*(sin_b);
Sz = fig[s][0]*(-sin_a*cos_c + cos_a*sin_b*sin_c) + fig[s][1]*(-sin_a*sin_c - cos_a*sin_b*cos_c) + fig[s][2]*(cos_a*cos_b);
H = 1 - Sz/depth;
matrix[s][0] = Sx/H;
matrix[s][1] = Sy/H;
}
}
// Rotate the object, angles in radians
void rotate(double angle_a, double angle_b, double angle_c)
{
// A cube with side 40
const int fig[8][3] = {{20,20,20},{-20,20,20},{-20,-20,20},{20,-20,20},{20,20,-20},{-20,20,-20},{-20,-20,-20},{20,-20,-20}};
// The points to draw, changed inside the calculate function
static int matrix[8][2];
// First time boolean
static bool bFirstTime = true;
// Clear object on screen
if(!bFirstTime)
draw(matrix, backcolor);
// Calculate new coordinates, depth = 300, 8 points
calculate(fig, matrix, angle_a, angle_b, angle_c, 8, 300);
// Draw object on screen
draw(matrix, drawcolor);
bFirstTime = false;
}


|cos(C) -sin(C) 0|
inv(Mz) = |sin(C) cos(C) 0|
| 0 0 1|
|1 0 0 |
inv(Mx) = |0 cos(B) -sin(B)|
|0 sin(B) cos(B)|
|cos(A) 0 -sin(A)|
inv(My) = | 0 1 0 |
|sin(A) 0 cos(A)|
The matrix equation to solve is:|cos(C) -sin(C) 0| |1 0 0 | |cos(A) 0 -sin(A)| |Sx| |x| |sin(C) cos(C) 0| |0 cos(B) -sin(B)| | 0 1 0 | |Sy| = |y| | 0 0 1| |0 sin(B) cos(B)| |sin(A) 0 cos(A)| |Sz| |z|x = Sx*(cos(A)*cos(C) + sin(A)*sin(B)*sin(C)) + Sy*(-cos(B)*sin(C)) + Sz*(-sin(A)*cos(C) + cos(A)*sin(B)*sin(C))