Create 3D Graphics without OpenGL or DirectX

Environment: VC6

This program is doing exactly what you see in the figure above.

First, a little theory:

1. Baric 3D Transformations:

We have Viewer and Cub in a real 3D world.

  • Viewer—It is a three-dimensional point V(x, y, z) that represents yourself.
  • Cub—It is represented by eight edges, every with three-dimensional coordinates P (x, y, z).

1.1 Translation:

Normally, the Viewer is moving around the Cube with a fixed step. The formula is simple:

Vix = Vx + t
Viy = Vy + t
Viz = Vz + t

1.2 Rotation:

It is implemented very simply, by moving the centre of Cub to the beginning of the coordinate system (Viewer), rotating around the desired axis, and then moving it back to its initial position. Here is the rotation formula:

Xi = X * cos(alpha) - Y * sin(alpha)
Yi = X * sin(alpha) + Y * cos(alpha)

It comes from the following picture:

First we have:

Xi = r * cos(alpha + gamma) = r *cos(gamma)*cos(alpha) -
                              r *sin(gamma)*sin(alpha)
Yi = r * sin(alpha + gamma) = r *cos(gamma)*sin(alpha) -
                              r *sin(gamma)*cos(alpha)

But we have: X = r * cos(gamma) and Y = r * sin(gamma)

So here it comes:

Xi = X * cos(alpha) - Y * sin(alpha)
Yi = X * sin(alpha) + Y * cos(alpha)

You could find the whole theory in the chapter titled “Geometrical Transformations” in Computer Graphics Principles and Practice by Foley, Van Dam, Feiner, and Hughes. For the sake of simplicity, I do not represent the transformations in homogenous coordinates and matrixes, although the first verson of the program I developed in this way. Here, I do not cover “Scaling” either.

2. Projection:

Here we have again Viewer, Cub, and Projection Plane in a real 3D world.

  • Projection Plane—the computer screen.
  • Delta—the distance between the Viewer and the Projection Plane.

Below are views along the Y-axis and X-axis.

Every point P (x, y, z) projects into the Projection Plane into two coordinates (Xp, Yp). The formula is simple and it applies to any of the Cub edges:

Xp / delta = X / Z ==> Xp = X * delta  / Z
Yp / delta = Y / Z ==> Yp = Y * delta  / Z

3. Visual Surface Determination:

Here, I implement one very simple algorithm. First, I calculate the cross product (which is the normal vector) of the polygon – Np. Then, I calculate the dot product of the normal (Np) and the line of sight vector (from Viewer to the polygon) – N. If Np x N > 0, this polygon is visible. For details, look at Chapter 5.2, “Cooling and Clipping,” in 3D Computer Graphics by Alan Watt.

4. Drawing Projected Points (Pixel by Pixel):

Please refer to Chapter 3, “Basic Graphics Algorithms for Drawing 2D Primitives,” in Computer Graphics Principles and Practice by Foley, Van Dam, Feiner, and Hughes. I particularly used “Basic Incremental Algorithm” and “Midpoint Algorithm” for drawing lines and “Cohen-Sutherland Line Clipping Algorithm” for clipping the lines.

5. Here Is the Whole Lifecycle:

  1. We have a 3D transformation on the screen.
  2. Then, visual service determination and projection of the Cub is added.
  3. Then, drawing projected points (pixel by pixel) into DIB are created.
  4. Finally, transfer this DIB onto the screen.

Source Code Notices:

  1. dibcub.cpp—The main module of the program. It is a standard Windows program that responds to some messages:
    • WM_CREATE: Crates a cub (which consists of eight polygons) and a “Viewer” in real 3D coordinates.
    • WM_PAINT: 3D – 2D conversion and draw the Cub pixel by pixel into a DIB. Then, transfer this DIB onto the screen.
    • WM_SIZE: Recreates the DIB object with the new screen size
    • WM_KEYDOWN: Here are implemented the basic 3D transformations depending on the user activity (Please check the theory section.)

  2. figure.cpp/cub.cpp (Cfigure /CCub):
    • Cfigure: Encapsulates the functionality of a 3D figure. It contains a list of the edges of the figure (vertex list) and a list of its polygons. The vertex list consists of real-world points.
    • CCub: A real 3D figure that inherits all basic functionality from the CFigure class. Properly Fills the vertex and polygon lists.
    • CCub::Draw(): Draws the figure on the screen by drawing all its visible polygons.
    • CCub::IsPolygonVisible():Determines whether the polygon is visible from the Viewer.

  3. polygon.cpp/rectpolygon.cpp: Encapsulates – Cpolygon/CrectPolygon classes.

    Polygon is a basic part of every figure. Every polygon contains pointers to the figure’s vertex list (edge list) in 3D coordinates. Rectpolygon inherits all the functionality of Cpolygon. In addition, it fills out its surface with a particular colour.

  4. vertex.cpp (CVertex)—Represents a point in a real-world (3D) coordinate system.

  5. primitiv.cpp—Encapsulates some basic graphics algorithms for drawing 2D primitives. At present, they include only lines.

  6. dbstruc.cpp (CDib)—Encapsulates a 16-color DIB. Do not use a color table.
    1 px. = 1 word.

  7. llist.cpp (VLList/ VLListIterator)—Encapsulates a linked list and Iterator to this list.

Some time ago a friend of mine, who is very good in this matter, told me that if you want to be good with computer graphics, you should not start with OpenGL or DirectX or any other graphic “toolkit” but simply from the ground up. Let me admit that I am not a Computer Graphics guru. I did this in my free time—just for fun! Computer graphics has always been a challenge for every software developer. It is a challenge for your maths skills, it is hard to be debugged, and finally it is a big pleasure when you see your results in full motion on the screen—much better than implementing “boring” business rules. What do you think? Well, if you are interested in 2D graphics, you could look at A Simple, Flicker-Free 2D Animation Demo.

Downloads


Download demo project – 24 Kb


Download source – 34 Kb

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read