[comp.graphics] Projecting from 3D to 2D

hollasch@enuxha.eas.asu.edu (Steve Hollasch) (06/20/91)

    I decided a while back to draw up a simple description of the
process of creating 3D images and finally got around to it tonight.
This is for beginners who want to know about this process.  Also,
the next time someone posts to comp.graphics for this information,
we'll have a file we can send off!

     By the way, if you're familiar with the process of projecting
from 3D to 2D, I'd recommend that you look over the method I use
to convert from 3D world coordinates to 3D eye coordinates.  Most
folks use rotation matrices (bleeech!), but the method I use is
_much_ cleaner.  This method is presented in the paper by Thomas A.
Foley and Gregory Nielson referenced at the end of this article.


----------------------------------------------------------------------------


                      Projecting Points From 3D To 2D

                              Steve Hollasch

                              19 June, 1991





-------  Introduction

    I've decided to whip up this article in response to the many queries
about the process of creating 3D graphics.  There are a number of books
that cover this subject, but this article should be useful for those
folks that want something online.

    This document presents the series of steps needed to project a point
in three-space to a point in two-space.  In other words, how to create
a two-dimensional image from a three dimensional scene.

    There are four parts to this problem:
    
        (1)  Providing the 3D coordinates of the point and the 3D
             viewing parameters. 

        (2)  Converting the point's world coordinates to eye
             coordinates.

        (3)  Projecting the 3D point to 2D normalized coordinates.

        (4)  Mapping the 2D normalized coordinates to the display
             window.

    In step one, we specify how we're going to look at the 3D scene.
Then we convert the 3D coordinates of each point to ``eye coordinates''.
This step is necessary for step three, where we project the point to the
normalized coordinate rectangle, i.e. the [-1,+1] x [-1,+1] rectangle.
Finally, we then map the normalized coordinate rectangle to our display
window (e.g. 512 pixels by 1024 pixels).



-------  Viewing Parameters

    The first thing we need to establish is how we're looking at the 3D
scene.  One obvious thing we need to know is the location we're looking
from, called the viewpoint or from-point.  This location specifies where
our ``eye'' is located in 3D.

    The next thing we need to establish is the line of sight (where
we're looking).  We can accomplish this by either specifying a line-of-
sight vector, or by specifying a point of interest in the scene.  The
point-of-interest method has several advantages.  One advantage is that
the person setting up the scene usually has something in mind to look
at, rather than a particular direction of sight.  It also has the
advantage that you can ``tie'' this point to a moving object, so we can
easily track the object as it moves through space.  This point of
interest is called the to-point.

    Now we need to establish an orientation of our view.  Most pictures
are oriented so that the ground is at the bottom of the image and the
sky is at the top of the image.  However, not all scenes have ground or
sky, so we need to specify which direction is up.  To do this, we
specify a vector called the up-vector.  If the up vector were included
in the scene, it would always be rendered pointing straight up in the
final image.  Note that the up-vector need not be perpendicular to the
line of sight (we'll ``straighten'' it later), but it must not be
parallel to the line of sight (think about it).

    We also need to specify the amount of perspective, or ``zoom'', that
the image will have.  This is given by the viewing angle.  Think of it
this way.  The rectangle we'll be projecting onto is perpendicular to
the line-of-sight, in front of the from-point.  You can think of this
rectangle as the ``window'' we'll be looking through.  If you connect
each corner of the viewing rectangle to the from-point, you'll get a
rectangular cone -- this is known as the viewing frustum.  The angle
of the tip of the viewing frustum is the viewing angle.  A slender cone
has a small viewing angle, and a fat cone has a large viewing angle.
Note that there are two viewing angles, one horizontal and one vertical.
For simplicity, I'll assume that these are the same.  However, if your
display device does not have a 1:1 aspect ratio, you'll need to
determine what the vertical viewing angle is in terms of the horizontal
viewing angle and the aspect ratio.

    This viewing angle must reside in the range of 0 to pi, exclusive.
Small viewing angles yield a telephoto effect, and large viewing angles
yield a wide-angle effect.  Note that if you change to a large viewing
angle, you'll need to move the from-point closer to keep the object
large in the image.

    So, these are the 3D viewing parameters we need:

        (1)  From-Point [3D Point]:    Where we're looking from.

        (2)  To-Point [3D Point]:      Where we're looking to.

        (3)  Up-Vector [3D Vector]:    Tells us where ``up'' is.

        (4)  Viewing Angle [Degrees]:  Telephoto vs. wide-angle.



-------  Converting World Coordinates to Eye Coordinates

    The first step in projecting the 3D point to the normalized
coordinate rectangle is to convert the 3D ``world'' coordinates to 3D
``eye'' coordinates.  This makes the projection much more simple.

    In the eye-coordinate system, the from-point is located at the
origin, the line-of-sight is the Z axis, the up vector is the Y axis,
and the X axis is perpendicular to the Y and Z axes.

    It turns out that there's a relatively easy way to do this.  Most
other techniques you'll see in textbooks involves the three different
rotations comprised of three 3x3 matrix multiplies -- very messy.  This
method involves a single 3x3 matrix multiplication and no trigonometric
functions.

    Let C be the unit vector along the line-of-sight, B be the vector
perpendicular to C that points ``up'', and A be orthogonal to the
vectors B and C.  What we'd like to see is a 3x3 transformation matrix
such that

                    [Ax Ay Az] T = [ 1 0 0 ],

                    [Bx By Bz] T = [ 0 1 0 ], and

                    [Cx Cy Cz] T = [ 0 0 1 ].

In other words, the unit vector perpendicular to the line-of-sight and
up-vector should map to the X axis,  the unit perpendicular-up vector
should map to the eye-coordinate Y axis, and the unit vector along the
line-of-sight should map to the eye-coordinate Z axis.  These three
equations can be combined in the form

                   +-        -+        +-     -+
                   | Ax Ay Az |        | 1 0 0 |
                   | Bx By Bz |  T  =  | 0 1 0 |
                   | Cx Cy Cz |        | 0 0 1 |
                   +-        -+        +-     -+

So how do we solve for the transformation matrix T?  Well, notice that
because of the way we've constructed the vectors A, B and C, the matrix
composed of the A, B and C row vectors is an orthogonal matrix.
Orthogonal matrices have the wonderful property that their inverse is
equal to their transpose.  So, simplifying, we get

     +-        -+  +-        -+        +-        -+  +-     -+
     | Ax Bx Cx |  | Ax Ay Az |        | Ax Bx Cx |  | 1 0 0 |
     | Ay By Cy |  | Bx By Bz |  T  =  | Ay By Cy |  | 0 1 0 |
     | Az Bz Cz |  | Cx Cy Cz |        | Az Bz Cz |  | 0 0 1 |
     +-        -+  +-        -+        +-        -+  +-     -+

which simplifies to

                                  +-        -+
                                  | Ax Bx Cx |
                            T  =  | Ay By Cy |
                                  | Az Bz Cz |
                                  +-        -+

    Note that before applying this transformation, we need to translate
the world-coordinate origin to the eye-coordinate origin by subtracting
the from-point.

    All that's left for this transformation is to figure out the A, B 
and C vectors.  These are given by

                         To - From
                  C = ---------------
                      || To - From ||


                         Up  X  C
                  A = --------------
                      || Up  X  C ||


                  B =  C  X  A

    These vectors are all unit vectors (B is a unit vector because A and
C are normalized).  So, the final equation is

                                                     +-        -+
                                                     | Ax Bx Cx |
    [Ex Ey Ez]  =  [(Px - Fx) (Py - Fy) (Pz - Fz) ]  | Ay By Cy |
                                                     | Az Bz Cz |
                                                     +-        -+ ,

where E is the eye-coordinate point, P is the world-coordinate point,
F is the from-point, and the A, B and C vectors are computed above.



-------  Projecting from 3D Eye Coordinates to 2D Normalized Coordinates

    Now that we have eye-coordinates (Ex, Ey, Ez) of the data point, we
can project the point to the normalized viewing rectangle.

    To calculate the perspective projection of point P', we need to
project the point to the viewplane and then to normalize the values so
that points on the Z axis are projected to X (or Y) = 0, and so that the
values of X (or Y) range from -1.0 to +1.0.
                       
         /|\  X      _/|         ____. E
          |        _/  |     ___/
          |      _/    | ___/    
          |    _/    __./
          |  _/  ___/  | T
          | /___/      |                                        \
          +------------+------------------------------------------
            \_ V/2     |  /|\                                   /  Z
              \_       |   |
                \_     | tan(V/2)
                  \_   |   |           (V is the viewing angle)
                    \_ |   |
                      \| _\|/_
          
          |/__________\|
          |\    1     /|
                                                               Ex   Tx
The X axis value from this figure is calculated by noting that -- = --.
                                                               Ez   Tz

We can let Tz = 1 if the viewing angle is still preserved.  Thus,

     Ex
Tx = --.  To normalize Tx, note that the maximum possible value of Tx on
     Ez
                            Tx
the viewing plane occurs at -- = tan(V/2).  The equations for the Y axis
                            Tz

are similar.  Thus, the equations for the normalized perspective
projection T are given by

                   Ex                               Ey
          Tx = -----------       and       Ty = -----------
               Ez tan(V/2)                      Ez tan(V/2)

where E is the eye-coordinate point of P, T is the normalize rectangle
coordinate point, and V is the viewing angle.  Again note that we're
assuming the viewport is square (and the aspect ratio is 1:1).  If this
is not the case, then Ty or Tx would be scaled to account for this.


-------  Mapping From The Normalized Viewport to The Display Window

    Now that we have the coordinates in the range of [-1,+1] x [-1,+1],
we need to map them to the display window.

    Let the center of the display window be Cx and Cy, and let the
length of the display window edges be Lx and Ly (both of these units are
in pixels, and the device origin [0,0] is in the lower left corner).
Then the device coordinates (Dx, Dy) of the point are given by the
following equations:

                      Lx                            Ly
            Dx = Cx + -- Tx      and      Dy = Cy + -- Ty .
                       2                             2

    The device coordinates Dx and Dy will be in pixels.



-------  Putting It All Together

    Here's a brief recap of what you need to do to project the point P
to the display window:

    (1)  Calculate the vectors A, B and C to form the transformation
         matrix.

    (2)  Use the matrix to convert the point P to the eye-coordinate
         point E.

    (3)  Project the eye-coordinate point E to the [-1,+1] x [-1,+1]
         normalized coordinate rectangle.

    (4)  Map this rectangle to the display window in screen coordinates
         (usually pixels).



-------  References

    Thomas A. Foley, Gregory M. Nielson, ``Practical Techniques for
        Producing 3D Grahpical Images,'' VMEbus Systems, Nov-Dec 1987,
        pp. 65-73.

    Donald Hearn, M. Pauline Baker, _Computer_Graphics_, Prentice-Hall,
        Inc., 1986.

    Francis S. Hill, Jr., _Computer_Graphics_, Macmillan Publishing Co.,
        New York NY, 1990.

    David F. Rogers, _Procedural_Elements_For_Computer_Graphics_,
        McGraw-Hill, Inc., 1985.

______________________________________________________________________________
Steve Hollasch                /      Arizona State University (Tempe, Arizona)
hollasch@enuxha.eas.asu.edu  /  uunet!mimsy!oddjob!noao!asuvax!enuxha!hollasch