CPSC 589 - Modeling for Computer Graphics
TA PAGE
Teaching Assistants:
| Luke Olsen |
olsenl at cpsc ... |
Tutorial 01 (MW @ 11am) |
News & Notes
Grades
Links
Submission procedure for assignments:
-
Written portion: Hand in to 589 drop box on the 2nd floor of Math-Sciences.
-
Coding portion: E-mail your code (no executables or objects) to me.
ZIP/TAR the files together before submitting.
- Your code must compile on the Linux machines in the Graphics Lab.
- To create an archive of your code, do the following:
$> make clean
$> tar -cvf mycode.tar *
$> gzip mycode.tar
- Bear in mind that you must do the assignments individually.
-
Instances of copied or inexplicably similar assignments will result
in a grade of zero on the assignment portion of the course.
News & Notes
| 04-23-07 |
The marks for the final assignment have been posted. The average
was a little lower than the first two assignments, but overall everyone should be in
good shape for the course. If you have a question about your mark, let me know.
This will more than likely be the last post for the semester, so I just want to say
thanks to everyone for making it an enjoyable semester for me! I hope you guys learned
a lot in the course, and maybe even pursue a further career in graphics. Best of luck
finishing your projects!
- Luke
|
| 04-20-07 |
Important - Project Extension
The deadline for submission of your final project package has been extended by two days,
to Wednesday, April 25. Hand in the package to Dr. Samavati's office (stick it
under the door if no one is there).
|
| 04-12-07 |
Final Review
Some sample final questions have been posted on the class website. I'll cover solutions
to those questions some time before the examl on Monday, but the time has yet to be decided.
I can possibly go over solutions tomorrow, but the regular lab time is unavailable.
Furthermore, I think it would be more beneficial to you guys to have time to study and
attempt the questions yourselves before the review, which I would hazard to guess won't be
the case by tomorrow morning.
So... I propose we set up a time on the weekend, say Sunday at 11am. That will give you time
to go over the material yourself, and find your trouble spots. If the consensus is to do the
review tomorrow, then that is also fine, but it would have to be in the afternoon after 4pm.
I will pencil Sunday in for now. If you prefer tomorrow, send me an email by the end
of today (Thursday); if enough people ask for a review on Friday, then I will send out
an update tomorrow.
|
| 04-05-07 |
As you've probably noticed by now, coding 3D graphics applications in a C++/Qt environment
can be a frustrating experience. Most of the problems are due to Qt, which interfaces with
C++ in a very unnatural way.
If you continue in graphics development, you may find yourself looking for better alternatives.
Of course, there are two main graphics APIs: OpenGL and DirectX. I have experience in both, and
would say that OpenGL is far better for any application where the most important consideration
is not raw performance.
The flip side is, of course, that DirectX is a highly optimized API
built expressly for gaming. If your square rendering task fits exactly into a DirectX
hole, then you'll be amazed at how much a single function call can accomplish; if it
doesn't, then you'll be dismayed at just how difficult it can be to do what you want.
A not-inconsequential benefit of OpenGL is that there are bindings to its API available
for a large number of languages. For coding up a quick demo or prototype,
Python + OpenGL
is a very powerful combination, that can be used in conjunction with any window manager available
to Python.
Another great combination is C# +
OpenGL (Tao). The level of library support in
C# is fantastic, and you can also use things from DirectX such as vectors, matrices, and
quaternions while staying within the comfortable and familiar confines of OpenGL rendering.
If you're interested in getting started in this environment, you can start with the
simple application linked below, which is similar to the barebones Qt application we've been
using all semester.
[C# OpenGL app]
|
| 04-04-07 |
Important!
The deadline for Assignment 3 has been extended to Monday, April 9th due to Good Friday.
As before, the code should be emailed to me by 11:59pm and the written portion put in the drop
box by 4pm.
|
| 04-04-07 |
Covered in lab today:
How to define field functions for implicit primitives. Most often, field functions are
based on the minimum distance to the primitive; for example, the field function of a point primitive
p at a point q is proportional to the distance between p and q, |p - q|.
In lab, we derived the distance function for a line primitive, based on vector projection. For
the line segment defined by p1 and p2, a point q will
either project onto the line between p1 and p2, or outside of the
line segment. If it projects between the endpoints, then the minimum distance is equal to the
length of the orthogonal component of the projection. If it projects outside of the line segment,
then the minimum distance is the distance from q to the closest endpoint.
I also talked about how to render implicit surfaces. For direct rendering, ray tracing is
pretty much your only option. For real-time rendering via OpenGL or a similar rasterizing API,
you have to first make a discrete representation of the surface. This is done via the
Marching Cubes
algorithm (in 2D, the algorithm is called Marching Squares; both are covered in the linked
page). The basic idea is to partition the object space into voxels (equivalently pixels in 2D),
and then evaluate the implicit field function at the vertices of the voxels. Edges/polygons
are constructed within voxels that have a mixture of vertices inside and outside of the surface.
The original paper is by Lorensen and Cline,
and a later paper by Shoeb provided 8 extra disambiguating cases.
|
| 04-02-07 |
Important!
Regarding Question 3 of Assignment 3, you might find it useful to rephrase the question as,
"Show that bicubic B-spline subdivision of a regular quadrilateral mesh is equivalent
to Catmull-Clark subdivision of the mesh." Please send me an email if you are unclear
on this question.
|
| 04-02-07 |
Covered in lab today:
Boolean operations on implicit surfaces, as it relates to the third assignment.
Also, I talked a bit about wavelets/multiresolution, and the relationship between
decomposition (wavelet transform) and classic least-squares. The important point is that
while decomposition can be formulated as a least-squares problem, the fact that subdivision
is a local operation means that having a local decomposition process is often desirable;
a least-squares approach will yield a global, not a local, decomposition mask.
|
| 03-28-07 |
Covered in lab today:
The quad-edge data structure, as described in the Kettner paper linked below. The quad-edge
structure is more complicated than the half-edge structure, but has the advantage of
being easy to dualize and being able to represent non-orientable surfaces.
This site has a good discussion of the quad-edge structure from both theoretical and practical
viewpoints:
[Quad-Edge
library]
|
| 03-27-07 |
Here is a good resource on mesh data structures
(half-edge, quad-edge, winged edge):
[Designing a Data Structure for Polyhedral Surfaces]
|
| 03-26-07 |
A common problem encountered when implementing a modeling program is this: given a 3D scene
that is being rendered from an arbitrary viewpoint by an arbitrary projection, how can we map user input
such as a mouse click into the 3D scene?
This is a problem with several solutions, some obvious and some more clever. One option is
to project your geometry into 2D window coordinates and compare the results to the mouse position.
For instance, if you have a 2D grid of control points defining a tensor product surface, you could
manually project each control point (eg.
gluProject())
and then do a search to find the point that projects nearest to your mouse position.
This approach makes sense for simple applications, but becomes too inefficient for more complex tasks.
Here is some code that implements this approach, courtesy of John Brosz:
[point-pick.c]
A similar approach is to do the opposite: instead of projecting your 3D geometry to 2D, you can
unproject your 2D mouse coordinate into 3D (eg.
gluUnproject()). This approach has to make up an extra dimension somehow, and does so by
looking at the depth buffer. The problems are basically the same as the previous approach.
OpenGL has some built-in tools to address this problem more robustly: the
selection buffer. The idea
is this: during a rendering pass, you can give each entity of interest a unique name
(
glLoadName()). Your entity of
interest could be coarse -- such as an entire mesh -- or fine, such as each face of a single mesh.
When rendering, OpenGL will keep track of which entities rasterized to your area of interest, i.e.
which objects contributed to the final pixel value of a pixel in your region of interest. Then you
can get a list of all such entities (returned by
glRenderMode()) and process it as you see fit.
Here are some code chunks that implement this:
[glselect.cpp]
The code won't compile as is, but should be easy to modify to suit your purposes.
The selection buffer idea can be mimicked in DirectX or even OpenGL by render-to-texture.
If you render each entity in a unique color (without lighting, of course), then when a mouse
click is received you simply do a constant-time lookup in your texture to get the name/ID of
the entity. The texture only needs to be updated when the scene or camera change, so this method
is very efficient in many cases.
|
| 03-26-07 |
Important! A quick note on the coding portion of Assignment 3: to subdivide
an RGB image, you should apply the subdivision mask to each color channel independently.
|
| 03-26-07 |
Covered in lab today:
Tips on implementing subdivision, including:
- Definition of a half-edge data structure.
- How to populate a half-edge data structure when loading an OBJ file.
- How to traverse faces and vertex neighborhoods.
- How to modify the traditional half-edge structure to accomodate subdivision.
- How to apply subdivision masks and where to store the new vertices created
during subdivision.
- How to create the new face structure after subdivision.
|
| 03-21-07 |
Covered in lab today:
Butterfly subdivision, which is a triangle-based scheme with a face-splitting structure
similar to Loop subdivision. The difference is that Butterfly subdivision is interpolating, while
most other schemes (Loop, Catmull-Clark, etc.) are approximating.

Left: Catmull-Clark Right: Butterfly
Image taken from
http://www.gamasutra.com/features/20000411/sharp_01.htm
The original Butterfly scheme creates artifacts at extraordinary vertices, so a modified scheme
was later introduced. The image below illustrates these artifacts, and the improvements in the
modified scheme.

Left: Original mesh
Middle: Butterfly
Right: Modified Butterfly
Image taken from
http://graphics.stanford.edu/~dzorin/multires/butterfly/index.html
Here are some links:
|
| 03-19-07 |
Covered in lab today:
Techniques for analyzing subdivision. The convergence and smoothness
properties of a subdivision scheme can be determined by looking at the behaviour
of a small neighborhood of points and the corresponding local subdivision matrix S.
If the eigenvalues of S have a certain structure -- namely that
l0 = 1 and li ≠ 0 < 1
-- then the subdivision scheme will converge.
For example, the eigenvalues of cubic B-spline subdivision are (1, 1/2, 1/4, 1/8, 1/8).
We also talked a bit about the third assignment, in particular Question 1. I covered
the same question for Catmull-Clark subdivision.
Finally, the second assignment was returned.
|
| 03-14-07 |
There is an example on the Qt site about creating an image viewer program:
http://doc.trolltech.com/4.2/widgets-imageviewer.html
It takes a different approach than the ImgWidget class posted below, as it uses a
QLabel to display the image. But it also has
some behaviour desirable for the third assignment, such as creating scroll bars for images
that are too big. I recommend you take a look at their code and incorporate it into your
assignment.
|
| 03-14-07 |
Covered in lab today:
Implementation tips for Assignment 3,
from a Qt-centric perspective.
Qt provides two main image classes: QImage and
QPixmap.
- QImage provides the image-loading interface, and is optimized
for I/O and pixel access/manipulation. Supported formats vary depending on the Qt configuration,
but the machines in the graphics lab claim to support the popular formats: JPEG, GIF, BMP, PPM, etc.
- QPixmap is optimized for drawing.
Neither of these classes inherits from QWidget, meaning that neither can
simply be instantiated and added to a GUI. You need to do some more work for that, but not much.
Here is some code that implements a class that inherits from QWidget
and can then be instantiated and added to a GUI layout.
[imgwidget.h |
imgwidget.cpp]
If you have a severe aversion to Qt, I would suggest looking into the CImg library.
That can be used in conjunction with ImageMagick to load more file types.
http://cimg.sourceforge.net
http://www.imagemagick.org
If you go that route, or any other, I will be less able to help you. And the regular submission
rules apply, so any external libraries for loading images must be submitted and configured to
build properly.
|
| 03-12-07 |
If you are working with meshes for your project, the
OBJ format
is a popular mesh file format.
At this site, there are
some great tutorial programs that work with OBJ meshes, along with the source code.
Take a look at the source if you need to write an OBJ parser for your project.
|
| 03-12-07 |
Covered in lab today:
I talked about how to apply subdivision to images. The main issue is how to handle the boundaries.
There are three main approaches: a) use special boundary masks that interpolate the boundaries;
b) wrap around the image for missing samples; c) use symettric extension (mirror the samples about
the boundaries).
|
| 03-09-07 |
I made a mistake when covering solutions for the midterm. On Question 3, part b), the correct
answer is that a cubic Bezier is smoother than the B-spline, because polynomials are infinitely
smooth. Obviously the question tricked me, so hopefully it didn't trick you as well.
|
| 03-08-07 |
In yesterday's lab we talked about how to interpret and implement subdivision filters for
curves. The important thing to remember is that a subdivision filter -- such as S = {1/4, 3/4, 3/4, 1/4}
for Chaikin curves -- represents a regular column of the subdivision matrix, which equivalently
represents the contribution of a single coarse point to all fine points.
For implementation
we are generally more interested in finding all coarse points that contribute to a
single fine point, which comes from the rows of the subdivision matrix; for binary subdivision
schemes, there are two types of row masks: even masks, from the even elements of S, and
odd masks from the odd elements of S.
|
| 03-05-07 |
Reminder: Assignment 2 is due this Friday, March 9. In order to give you guys
as much time to work on the assignment as possible, please note the following specific
deadlines:
Written portion: due before 4pm. I will empty the drop-box at 4pm.
Coding portion: due at 11:59pm via email.
You can also submit a PDF/Doc of the written portion via email, if you wish. Note, however,
that the 4pm deadline still applies for this type of submission.
Note also that the coding portion will be marked a little harder this time around.
That means: ensure your code is implemented in an efficient manner. For example:
don't compute the curve or surface in the display function; use display lists if your
rendering is too slow; and so on.
|
| 03-05-07 |
Today we covered solutions to the midterm.
|
| 02-28-07 |
In today's lab, I covered solutions for the sample midterm that was posted on
the course website. I also covered a true/false question from last year's midterm.
|
| 02-26-07 |
In today's lab, I did a quick midterm review, summarizing what has been covered so far.
The first assignment was also returned.
|
| 02-21-07 |
Marks for Assignment 1 have (finally!) been posted. If you have any questions,
or would like a break-down of your mark, send me an email. The average is very high, so great job
everyone!
|
| 02-14-07 |
Here is some code from today's lab for ruled surfaces. Note that the curve code isn't included,
since that is part of Assignment 2; instead, the executable is included in the archive.
[ruled.tar.gz]
|
| 02-13-07 |
Here is a good vector and matrix library.
Feel free to use it in your assignments, and save the hassle of implementing one yourself. Basic usage
is:
| gmVector3 v, w(0.0, 0.0, 0.0); |
// Default and initialization constructors |
| v.assign(1.0, 2.0, 2.0); |
// Assign values to each component |
| v[2] = 3.0; |
// Use [] to access elements individually |
| w = 2.0*v; |
// Scalar-vector multiplication |
| float mag = w.length(); |
// Member function for getting vector length |
| float dp = dot(v, w) |
// Dot product; also cross(v, w), distance(v, w) (for points) |
| w = normalize(v); |
// Normalize to length = 1 |
The class also overrides the following operators: =, +, -, *, /, +=, -=, *=, /=,
==, and !=.
Usage is similar for the matrix classes.
To use the vector classes in your code, you just need to include the appropriate header file (eg.
#include "gmVec2.h"). For the matrix classes, you will have to
include the header file, and add the corresponding source file to the makefile.
You can add do this with the barebones app
by adding references to the .cpp and .o
files under the CXXFILES and OBJECTS definitions in the makefile.
[libgm.tar.gz]
|
| 02-12-07 |
In today's lab, we covered the efficient B-spline algorithm from the course notes
and traced through an example.
I also explained the connection to -- and expectations of -- the Assignment 2 requirement to
"include an option to demonstrate the algorithm in a geometric fashion."
|
| 02-07-07 |
Just a reminder that Assignment 1 is due tomorrow at 11:59pm. Please review the
assignment procedures and check that your code compiles in the Graphics Lab.
Make sure you email your code archive (no executables, .o files, etc.) by the deadline.
I will pick up the written portion from the drop boxes on Friday morning at 10:00am.
|
| 02-07-07 |
In today's lab, we briefly re-covered the equivalence of degree-d Bezier curves
and order-d+1 B-splines (with a certain knot sequence).
We also covered some simple mouse-look interfaces, one that changes the object and one
that moves the camera in polar coordinates. Trackball rotation via quaternions are the best
mouse-based interaction method, but finding a good quaternion library for C++ is a chore.
(Implementing trackball in C# or higher-level languages, though, is a breeze.)
Finally, we discussed NURBS, which can be interpreted as B-spline curves lifted to a higher
dimension and then projected back down, and proved that NURBS are invariant under projection.
|
| 02-07-07 |
The Makefile in the lab 2 code was corrupt (thanks to Hasan for pointing this out). A new
version is available, or the original Makefile from the barebones app can be used as well.
There was also a problem with the texture-loading function in the barebones app that
caused it to not work properly outside of the Graphics Lab. LoadTexture()
has been updated to a more robust version, including automatic selection of the power-of-2 dimensions,
that should work on all department machines.
[Barebones update]
[Lab 2 code update]
|
| 01-31-07 |
In next Monday's lab, I will be giving a preview of later course topics. If you haven't decided
on a project topic, this will be a good opportunity to see some possible topics.
|
| 01-31-07 |
Sorry for the lack of recent updates. To recap the last few labs, on the 22nd
I talked briefly about the assignment (hint: assume a 2D setting for Q1) and covered
a Bezier curve question involving finding a control point based on known control points
and a curve sample.
On the 24th, I did a quick refresher on vector spaces vs. affine spaces, and bases for
them. We can treat polynomials as elements in a vector space, and for computer graphics there
are some choices of basis that are better than others (i.e. Bernstein polynomials, B-splines).
On the 29th, we talked about affine invariance and proved that parametric curves are
affine invariant if their basis functions have unit summation. We then showed that Bezier
curves are a special case of B-splines by showing the equivalence of the basis functions in the
3rd-degree case. I also covered some properties of B-spline basis functions and hinted at
how to prove them (in case it comes up ;). Finally, I gave a hint about how to set up OpenGL's
viewport and projection when making a curve editor.
In today's lab, I covered a 3-part example involving B-splines: a) use the recursive definition
to find the 3rd-order (k = 3) basis functions; b) prove that the basis functions are indeed splines;
and c) assuming a curve with 4 points (m = 3), find the tangent at umax.
|
| 01-17-07 |
Here is the code from the programming excercise covered in today's lab. The archive includes
the texture map and all modifications of the barebones app that were discussed in lab today,
which involved creating a spinning Earth and implementing some rudimentary camera control.
[Lab 2 code]
|
| 01-17-07 |
In today's lab we will be doing a programming exercise involving texture mapping, GUI
programming, and animation using the barebones application
and the texture given below.
[Earth texture]
|
| 01-15-07 |
Here is a barebones OpenGL/Qt application that can be used as a basis for your
assignments and/or project. It should compile on the machines in the graphics lab
without modification; just extract the files and run make.
[barebones.tar.gz]
The files of interest are renderer.* and
window.*. The Renderer class handles your graphical objects
and rendering duties, while Window is responsible for creating the the window and GUI
elements and communicating with Renderer.
The functions you will most often need to modify, outside of declaration and initialization
of variables in the headers and constructors, are:
- Renderer::initializeGL() This is where you should set up your OpenGL
rendering state, position lights, load textures, initialize objects, and so on.
- Renderer::resizeGL() This is called once when the window is created,
and again whenever the window is resized. Here is where you set up your viewport (eg. orthographic or
perspective projection).
- Renderer::paintGL() This is where you make your rendering calls
or call display lists. You don't call this function yourself; to add a redraw to the event queue,
you can call Renderer::updateGL().
- Renderer::[mouse|key]*Event Here is where you get input events, such
as keypresses or mouse clicks, and perform the appropriate actions. If you make any changes
that modify rendering parameters, you should end with an updateGL()
call.
Some functions and basic rendering calls are stubbed out. When you compile it, you should see a
multi-colored triangle on a black background.
|
| 01-09-07 |
Labs begin on Jan. 15. Check this page frequently for updates throughout
the semester.
|
Grades
Only the last 4 digits of your ID number are shown.
| ID # | A1 / 120 | A2 / 100 | A3 / 140 | Final / 15% |
| 0081 |
96 |
77 |
98 |
11.35 |
| 0621 |
112 |
103 |
76 |
12.53 |
| 1502 |
110 |
- |
20 |
5.30 |
| 3771 |
125 |
75 |
112 |
12.96 |
| 3772 |
140 |
76 |
124 |
14.06 |
| 4022 |
128 |
81 |
122 |
13.74 |
| 4438 |
128 |
119 |
140 |
16.28 |
| 4504 |
132 |
106 |
126 |
15.30 |
| 5746 |
112 |
83 |
60 |
10.96 |
| 6101 |
120 |
91 |
126 |
14.05 |
| 7450 |
102 |
81 |
48 |
10.01 |
| 7731 |
116 |
99 |
124 |
14.21 |
| 8500 |
123 |
84 |
97 |
12.79 |
| 9513 |
128 |
69 |
91 |
12.03 |
| 9564 |
135 |
139 |
130 |
17.22 |
| 9603 |
120 |
77 |
126 |
13.35 |
| Average |
100.36% |
90.67% |
72.32% |
|
Links
|