\documentstyle{article}
\begin{document}

%\title{Notes on 3d Viewing and the Cube Assignment}
%\lecturedate{}
%\raggedbottom
%\begin{document}
%\maketitle

\noindent This note describes the ``simple 3D viewing'' system that 
I described at the end of class on Tuesday. I'm interested in corrections and
improvements; perhaps we can lobby FvDFH to incorporate parts of it in Chapter
7, as a way to introduce the concepts and to give readers a better intuition
for what's going on. This material was derived fromWatt's {\it Fundamentals of
Three-Dimensional Computer Graphics}.


\section{ Viewing ($M_{view}$)}

To a first approximation, there are only two variables that can be set in our
simple viewing system: the position of the viewer's eye and the distance the
viewing plane is away from the eye. The viewer is always looking at the origin
of the ``world space,'' and the viewing plane is always normal to the line of
sight. More about this later.  We say that the eye is at position $P$ and the
origin of world space is the point $O$.

The position of the eye defines the origin of a new coordinate system called
the ``eye space''. It is a left-handed coordinate system whose $z$ axis sits on
the line $PO$. As we look along the eye's $z$ axis, the values are getting
larger as things are farther away. The $x$ axis of the eye-space is parallel to
the $x$-$y$ plane of world space.

The gist of things is that we need to find a matrix that will convert a point
in world space into eye space. This matrix is completely specified by $P$'s
location in world-space. As it turns out, the matrix is easy to derive (and to
write down) if we specify $P$ in spherical coordinates rather than cartesian
coordinates. So $P$ is given by a triplet of numbers, $(\mu, \theta, \phi)$,
with the following interpretation: \begin{description} \item $\mu$ is the
distance from the viewer to the origin. \item $\theta$ is the angle made
between the line of sight, $PO$, and the plane containing the $x$-$z$ axes.
\item $\phi$ is the angle between the line of sight and the plane containing
the $y$-$z$ axes. \end{description} To check your understanding, consider the
point $P$ with $\mu=10$, $\theta=-30,$ and $\phi=45$. The eye is somewhere in
the octant with positive values for all three coordinates, and the viewer would
be looking down and to his left to see the origin.

With some high school trigonometry, we find that 
\begin{eqnarray*}
    P_x &=&   \mu cos \theta sin \phi   \\    
    P_y &=& - \mu sin \theta            \\
    P_z &=&   \mu cos \theta cos \phi   \\
\end{eqnarray*}
Note that negative sign for $P$'s $y$ coordinate. The negative sign is
needed because 
$\theta$ is negative in order to ``raise'' a line above the 
$xy$ plane. (An easy sanity check that the
coordinates are reasonable is to look at the square of the distance 
from $P$ to the origin using the cartesian coordinates. It should
equal $\mu^2$.
This doesn't convince you the sign is right, or that we haven't swapped
a cos with a sin, but it's nice to know
that there's nothing to prove the coordinates are wrong.) 

To make a long story short, the matrix that converts a point from world space
into eye space is  
\[
    M_{view} = 
      S(1, 1, -1) \cdot Rx(-\theta) \cdot Ry(-\phi) \cdot T(-P_x, -P_y, -P_z) 
\]
where the matrices for scale, rotation, and translation are found 
in FvDFH, pages 214--5.


\section{ Projecting ($M_{proj}$) }

As mentioned, in our simple model the viewing plane is located normal to the
eye space's $z$ axis (the line from $P$ to $O$), at a distance $d$ away from
$P$. That is, in the eye space, the plane is at $z=d$, parallel to the eye
space's $xy$ plane.

To perform a perspective projection, transform points in eye space
by
\[
    M_{per} =  
       \left[
       \begin{array}{cccc}
       1 & 0 & 0 & 0 \\
       0 & 1 & 0 & 0 \\
       0 & 0 & 1 & 0 \\
       0 & 0 & 1/d & 0
       \end{array}
       \right]
\]
If you ignore clipping and hidden surface elimination, you can now 
homogenize the resulting points. That is, you need to divide the 
$x$ and $y$ coordinates by $z/d$.

To perform an orthographic projection, you don't need to do anything.
If, for the sake of symmetry, you'd like to do a ``projection'' type
transformation, simply transformi your points in eye space
by the identity matrix:
\[
    M_{orth} =  
       \left[
       \begin{array}{cccc}
       1 & 0 & 0 & 0 \\
       0 & 1 & 0 & 0 \\
       0 & 0 & 1 & 0 \\
       0 & 0 & 0 & 1
       \end{array}
       \right]
\]

To summarize, the projection matrix is $M_{proj}$. It is either 
$M_{per}$ or $M_{orth}$, depending on the desired type of projection. 
It projects objects from eye space into ``screen space.'' 


\section{ Imaging ($M_{image}$)}

The final thing you need to do is to get a part of the viewing plane onto
``image space'' on an SRGP canvas (perhaps via a SUIT widget).  How do you
specify such window onto of the view plane?

In our simple model, we define a screen space coordinate system in the view
plane whose origin is the spot where the line $PO$ hits the plane. The vertical
and horizontal axes, usually labeled $u$ and $v$, are parallel to the $x$ and
$y$ axis of our eye space.

Since we are always looking down at the origin, there's a good chance 
that we've set up the objects to be viewed such that they are around 
the origin. So, for the sake of keeping things simple, we'll specify 
a size $w$ of the viewing window centered about the origin. That 
is, the viewing window goes from $(-w,-w)$ in the lower left to $(w,w)$ 
in the upper right. With a regular window nicely centered about the 
origin, the transformation to a viewport in an SRGP canvas is simple:
\[
    M_{image} = 
        T(lx, by, 0) \cdot 
        S\left( {{rx-lx} \over {2w}}, {{ty-by} \over {2w}}, 1\right) \cdot 
        T(w,w)
\]
where the southwest corner of the canvas is $(lx,by)$ and
the northeast corner is $(rx,ty)$. This is just a special case of
the window-to-viewport transformation we've seen a few times in class already.
You are now ready to draw the object by just ignoring the $z$ coordinate.

\section{Putting it all together}

If you are not clipping or performing hidden surface elimination, 
you can combine the three matrices together into a single matrix, 
transform each point from the world space into image space, and then 
homogenize transformed the point. 
The cumulative transformation matrix is as follows
\[
    M_{crm} = M_{image} \cdot M_{proj} \cdot M_{view}
\]
Don't forget to homogenize the transformed  point! 


\section{Rotating the cube}

Most of you have had no problems computing the matrices for
rotating the cube about its main diagonal. Just in case there's any
confusion, here's the scoop.

Assume the cube is centered about the
origin in world space, going from $(-1,-1,-1)$ to $(1,1,1)$. The matrix to spin
the cube by $\alpha$ degree forward is
\begin{eqnarray*}
    M_{spin} =  & T(-1, -1, -1) \cdot Ry(-45) \cdot Rz(arcsin(1/sqrt(3)))
      \cdot  \\
      & ~~~ Rx(\alpha) \cdot \\
      & ~~~ Rz(-arcsin(1/sqrt(3))) \cdot Ry(45) \cdot
       T(1, 1, 1)
\end{eqnarray*}

It is tempting to combine this matrix with the three above. Your life will be
easier if you don't.  Because $M_{spin}$ rotates the cube from its current
position by $\alpha$ degrees, you need to keep the transformed points around
each time you spin the cube a bit.

In other words, the high-level structure for your program is as follows:
\begin{verbatim}
    cube = initial position of cube
    Mctm = Mcanvas * Mproj * Mview;
    loop
        cube = Mspin * cube
        cubeP = Mctm * cube
        cubeP = homogenize cubeP
        display cubeP
    end
\end{verbatim}

If you aren't doing any clipping or hidden surface elimination, and you combine
$M_{canvas},$ $M_{proj},$ and $M_{view}$ into a single cumulative
transformation matrix, $M_{ctm}$, you should still keep the individual matrices
around so the user can change some of the parameters interactively.

For example, in my program, I allow the user to interactively set
the following items:
\begin{itemize}
\item 
viewing parameters $\mu$, $\theta,$ and $\alpha$. These affect
$M_{view}$ only.   
\item 
projection parameters $d$,  and a perspective vs. orthographic flag.
These affect $M_{proj}$ only.
\item 
canvas parameters $w$, and the $lx, by, rx, ty$ which define a
location of the SUIT widget. These affect $M_{canvas}$ only. 
\end{itemize}
Of course, after changing one of the parameters, the cumulative matrix
must be recomputed by matrix multiplying the three matrices that
comprise it.  

\end{document}



