Glass Ball Interface
ECS175: Computer Graphics
Due 7:00pm, Fri. May 19
Please do this project without a partner.
This project will help you familiarize yourself with
three-dimensional modeling and viewing, animation
and user input, and makes you
write an OpenGL program from scratch.
Focus first on the mechanics of viewing and
interaction, and then think about making an interesting model, and other
special features, if you have time.
A program which allows the user to correctly rotate a
simple model, with correct normal vectors, is worth a B, and an
interesting model (built by you, not loaded from a file) will
get you an A.
The project is to model an object in 3D, and move it around using
the ``glass-ball'' (aka ``arc-ball'') user interface.
This applet uses the "glass-ball" interface, so you can see how it works.
The idea is that we imagine the object to be embedded
in a clear glass trackball.
When you hold any mouse
button down in the window containing the object, moving the
mouse spins the glass trackball, and the object along with it.
Notice that the object
rotates around an axis perpendicular to the
direction that the mouse is moving.
Moving the mouse with the buttons released does nothing.
The model can be anything except the icosohedron and the
cube, which are in the book, and a pyramid or cylinder
with fewer than 5 sides, which are too easy.
Since the next and last assignment will be virtual world, possibly
you might get a head start by making a handy object like a
fish or a submarine.
Here is Prof. Staadt's code which reads
in a .obj file and rotates it using an incorrect (but all too common)
user interface. It is a gzipped tar archive.
Here are some step-by-step instructions, if you're wondering
where to begin.
Step 1: Study some examples.
Look at the animation example on pages 20-25 of the OpenGL book.
Using the OpenGL man pages, figure
out what every OpenGL and glut call in the program
does, since you'll probably
have to change most of them.
Also look at the code for modeling an icosohedron on pages 86-89.
Step 2: Build a 3D cube
Let's start with something simple,
and get the 3D viewing and interaction working.
First, build a cube centered at the origin.
You'll need to specify the vertices and faces of the cube.
To get started without using normal vectors,
make every face of the cube a different color, so that you
can see where one face ends and another begins.
Remember to orient all faces counter-clockwise.
Step 3: Look at your cube in 3D
Use glOrtho (pages 127-8)
to specify an orthographic projection of your cube to
the screen, that is, a projection which just drops the z coordinate
of each 3D point.
Remember that only world coordinate points inside the box defined
in the glOrtho command appear in the window!
At this point you'll probably be looking straight at one face of the
cube, so it will just look like a square.
Step 4: Turn on depth buffering.
You'll need to tell both OpenGL and the glut that you
want depth buffering. See pages 185-187
in the OpenGL book.
NOTE: Putting glEnable(GL_DEPTH_TEST) right
after the glutInitDisplayMode call, as it seems to
suggest on page 186, will not work. Calling glEnable
before glutCreateWindow has no effect.
A good way to keep track of what to call when (and make your code more
modular) is to keep all initialization of the glut in main,
before calling init,
and put initialization for OpenGL (including calls to
glEnable) in init.
At this point you should see still just see a single face of the cube.
Step 5: Build the operator interface.
Now let's rotate the cube and see if it's all there.
You'll need to specify the callback routine for mouse motion.
The way you tell the glut you have such a routine is using
Look this up in the on-line glut documentation.
This function will get called many times as you move the mouse
in the window with the button down. Each time, you'll want to
rotate the cube by a little bit.
NOTE: The mouse position at the upper left corner of
the window is (0,0).
Now write the callback routine to implement the glass-ball interface.
You'll have to figure out what axis to rotate around, and how
to use the difference between the new and old x-y positions of the
mouse to determine how much to rotate.
Try and refine the feel of the interface so it really seems like
you're moving the cube with the mouse.
If your program produces
really freaky looking images, you probably did not
succeed in turning depth buffering on; return to Step 4.
Step 6: Specify normals and turn on lighting
To see the cube as one color, with lighting, rather than
with different colored faces, you will need to specify a
normal vector for every vertex, and specify the same color
for every vertex.
Take a look at the information on computing surface normals in the
icosohedron example, although note that in this case you want every
vertex of a face to get the same normal.
Here is a C function that
turns on lighting for an OpenGL program; call it at the end of
Feel free to use this function
and don't worry too much about what it does.
We'll study lighting in more detail later.
Your colors will disappear when you turn on lighting; the vertex colors
are now controlled by the lighting calculations, which use the vertex
To tell the lighting calculations about colors, you use glMaterial.
In the lighting example, the array mat_properties is an RGBA color
specification. Change that to change the color of your object.
You should probably keep your object all one color - the only reason
we were coloring the faces different colors in Step 2 was for debugging
Step 7: Fix the jump
You probably have noticed that your cube "jumps" when you move the
mouse without pushing the button, and then click down on the mouse button
in the window. Why is this? You can fix it by implementing a callback function
for the mouse buttons. Use glutMouseFunc() to tell the glut about
your new callback function.
Step 8: Make a more interesting model
Replace the cube with a cylinder, cone, sphere, pear, space station,
etc. Build at least one such object which does not use
any glut drawing functions like glutSolidSphere,
Step 9: Optional improvments
Here are some ideas for improving the basic assignment.
- Make an interesting object using curved surfaces.
Write a function to make a nice curved object, like a vase, or a
snail, using parametric surfaces defined by Bezier curves, simple quadrics,
Build at least one curved surface using only GL_TRIANGLE
or GL_QUAD, defining the normals yourself. You may use evaluators (Chapter 12 in the OpenGL book) or glutSolidSphere, etc, as well to make a more complicated, interesting or realistic object.
- Read in objects from a file.
This is fun, and recommended,
but will not improve your grade
very much since it is very easy given Prof. Staadt's code from
Add the option for the user to give the program an additional argument,
ie a file to load). If an argument is not given, your program should
draw the OpenGL model you built. There are many modeling formats,
perhaps the easiest to use is "obj". Nate Robins has an OpenGL reader.
Simply search for "glm.h" to find the ".c" and ".h" files, then search for
interesting .obj files.
Be sure that the program that you had in can also display some
model that you built yourself, to ensure you understand how models are
- Texture map your object.
Read the example of OpenGL texture mapping on pages 371-375, and search
the Web to find a nice texture to put on your object.
A good first step would be to place a big polygon behind your
object, which does not move when your object moves, and texture-map
a background onto the big polygon.
Step 10: Documentation.
Write a README
file including a) your name, b) how to compile and run your
program, and c) a few short paragraphs on what you did.
If you use any code you found on the web, (eg. Nate's glm.c), please note that in your documentation, and also the source of any models or textures you used.
Step 11: Turn in your assignment.
Turn in the source file of
your program, the Makefile,
the documentation, the executable, and any additional files.
Please limit yourself to one "found" model and one texture,
we don't want to run out of