Viewing
The goal of this week's lab and project is to build a class for creating and managing the viewing parameters and view transformation matrix.
Tasks
The main result of your work this week should be a View class that holds the current viewing parameters and can build a view transformation matrix [VTM] based on the parameters.
-
Create a file view.py and begin a class View (you can use any name you
like, but I'll provide some short test programs that assume the class
is named View).
Within the __init__ method, create the following fields and give them the specified default values. You may want to have a reset method, called from __init__ that assigns the default values, as you may want to enable the user to reset the view at any time. Note that the view parameters provide a complete view of the data, looking normal to the X-Y plane, assuming the data is all located inside the unit cube with one corner on the origin.
- vrp: a NumPy matrix with the default value [0.5, 0.5, 1].
- vpn: a NumPy matrix with the default value [0, 0, -1].
- vup: a NumPy matrix with the default value [0, 1, 0].
- u: a NumPy matrix with the default value [-1, 0, 0].
- extent: a list or NumPy matrix with the default value [1, 1, 1]
- screen: a list or NumPy matrix with the default value [400, 400]
- offset: a list or NumPy matrix with the default value [20, 20]
-
Write a build method that that uses the current viewing
parameters to return a view matrix.
-
Generate a 4x4 identity matrix, which will be the basis for the view
matrix. For example:
vtm = numpy.identity( 4, float )
-
Generate a translation matrix to move the VRP to the origin and then
premultiply the vtm by the translation matrix. For example:
t1 = numpy.matrix( [[1, 0, 0, -self.vrp[0, 0]], [0, 1, 0, -self.vrp[0, 1]], [0, 0, 1, -self.vrp[0, 2]], [0, 0, 0, 1] ] ) vtm = t1 * vtm -
Calculate the view reference axes tu, tvup, tvpn.
- tu is the cross product (np.cross) of the vup and vpn vectors.
- tvup is the cross product of the vpn and tu vectors.
- tvpn is a copy of the vpn vector.
-
Normalize the view axes tu, tvup, and tvpn to unit length. You
probably want to write a simple normalize function to handle this.
Make sure you do not include the homogeneous coordinate in the
normalization process. A normalized vector has unit length, and can
be computed as below. (There are more compact ways to do this using
numpy.)
Length = math.sqrt( Vx*Vx + Vy*Vy + Vz*Vz )
Vnorm[0] = Vx / length
Vnorm[1] = Vy / length
Vnorm[2] = Vz / length
- Copy the orthonormal axes tu, tvup, and tvpn back to self.u, self.vup and self.vpn.
-
Use the normalized view reference axes to generate the rotation matrix
to align the view reference axes and then premultiply M by the
rotation. For example:
# align the axes r1 = numpy.matrix( [[ tu[0, 0], tu[0, 1], tu[0, 2], 0.0 ], [ tvup[0, 0], tvup[0, 1], tvup[0, 2], 0.0 ], [ tvpn[0, 0], tvpn[0, 1], tvpn[0, 2], 0.0 ], [ 0.0, 0.0, 0.0, 1.0 ] ] ) vtm = r1 * vtm -
Translate the lower left corner of the view space to the origin. Since
the axes are aligned, this is just a translation by half the extent of
the view volume in the X and Y view axes.
Note that the rest of the project description will use shorthand, rather than writing out the matrices explicitly. Conceptually, the translation is represented as:
vtm = T( 0.5*extent[0], 0.5*extent[1], 0 ) * vtm
-
Use the extent and screen size values to scale to the screen.
vtm = S( -screen[0] / extent[0], -screen[1] / extent[1], 1.0 / extent[2] ) * vtm
-
Finally, translate the lower left corner to the origin and add the
view offset, which gives a little buffer around the top and left edges
of the window.
vtm = T( screen[0] + offset[0], screen[1] + offset[1], 0 ) * vtm
If your code is working properly, then using the default parameters you should get the matrix below.
[[ 400. 0. 0. 20.] [ 0. -400. 0. 420.] [ 0. 0. -1. 1] [ 0. 0. 0. 1.]]
-
Generate a 4x4 identity matrix, which will be the basis for the view
matrix. For example:
When you are done with these tasks, go ahead and start the rest of the project.
Spring 2017