Stepping into the 3rd Dimension

teapot_shadedThis 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.

teapot_wireframe

teapot_shaded

Torus

torus_wireframetorus_shaded

Cylinder

cylinder_wireframecylinder_shaded

Sphere

res_sphere_wireframeres_sphere_shaded

Dog face

dog_face_wireframedog_face_shaded

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 )

  1. / ReplyAnoop.V S
    Great work man. Really interesting ! Keep up this gud work
  2. / Replyusha krishna
    briiliant work...:) ranjith.
  3. / ReplyThe Lenzmaker Project | Ranjith Raghunathan
    […] You can find more details here. […]

Leave a reply

Your email address will not be published.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>