Stepping into the 3rd Dimension
This is an old story. During the initial days of my computer graphics experiments, I reinvented the projection technique of 3D graphics. Being too much excited with the Wolfenstein3D game, I was really curious to know how John Carmack did it. The dilemma was that I haven’t covered any computer graphics topics since then, it was really doubtful for me to make it possible under dos. One of the interesting thing is, I used an analogy to evaluate a solution for this problem. Its nothing but the working principles of human eye, a camera, a convex lens or a mirror. All of them maps objects in the 3-Dimensional space into a flat surface. So I went back to take a revisit to the Ray-Optics(Geometrical Optics) taught at school to derive a projection equation based on Lenses or Mirrors.
This a small trick illustrating how to create a 3d version of your 2d graphics functions such as DrawLine(x1, y1, x2, y2) , SetPixel(x, y, color). Let the above two functions, have 3d version DrawLine(x1, y1, z1, x2, y2, z2) and SetPixel(x, y, z, color). Obviously the 3d version has z coordinate. It is a genuine question for a beginner what to do with the z value.
And here it is what you have to do,
// define focal length, I use 600.00f as the default, // reducing this value will give increase the field of view and // give a wide angle effect for the 3d drawings. #define FL 600.00f
And here is what you have to do,
For each coordinate in space P(x, y, z), do the following calculation to project it on a 2d plane, resulting the coordinates (tx, ty)
tx = x * FL/(FL+z) ty = y * FL/(FL+z)
Let’s try putting these into code,
3D Version of the SetPixel function
// here is the 3d version of the SetPixel function void SetPixel3d(float x, float y, float z, long int color) { float fx, fy; fx = x * FL/(FL+z); fy = y * FL/(FL+z); // call the 2d version of SetPixel function SetPixel((int)fx, (int)fy, color) }
3D version of the DrawLine function
// we just created the 3d version of the line drawing function too void DrawLine(float x1, float y1, float z1, float x2, float y2, float z2) { float fx1, fx2, fy1, fy2; fx1 = x1 * FL/(FL+z1); fy1 = y1 * FL/(FL+z1); // z1 must not be equal to -fZ fx2 = x2 * FL/(FL+z2); // above applies to z2 also fy2 = y2 * FL/(FL+z2); // now call the 2d version of the line drawing function line((int)fx1, (int)fy1, (int)fx2, (int)fy2); // done }
Sample drawings
A wireframe teapot and its shaded version.
Torus
Cylinder
Sphere
Dog face
That’s it !
These are the screenshots of a sample demo application I did. All the data I used here was exported from 3dsMax as an Ascii Scene Export (.ase) file.
The tools I used were Borland Turboc 3.0 under MSDOS. The display mode was 640×480, with 4 bits per pixels (16 colors). The shading in these example is performed by making the 16 colors in the palette into 16 shades of white.
Comments ( 3 )