Project 2 - Trains and Roller Coasters
In this project, you will create a train that will ride around on a track. When
the track leaves the ground, the train becomes more like a roller coaster. If you're
curious, you can look at previous years' projects (2007,
2006, 2005, 2003, 2001, 2000, 1999) to see what to expect. Each year's
requirement is slightly different, but the basic ideas will be the same. Historically,
students have really liked this project.
The main purposes of this project is to give you experience in working with curves
(e.g. the train and roller coaster tracks). It will also force you to think about
coordinate systems (to make sure that things move around the track correctly). In
the past, a big part of this project (especially in terms of time) was to make the
3D user interface, but this year, we will give you framework code so that you don't
need to worry about that so much.
The core of the project is a program that creates a 3D world, and to allow the user
to place a train (or roller coaster) track in the world. This means that the user
needs to be able to see and manipulate a set of control points that define the curve
that is the track, and that you can draw the track and animate the train moving
along the track. We'll provide the framework code that has a world and manages a
set of control points. You need to draw a track through those points, put a train
on that track, and have the train move along the track.
In the past, we expected students to build the system from scratch. Last year, we
created a new sample solution that better shows off some of the features you might
want to include. In the process, we decided that we would give you most of the code
so you can focus on writing the interesting parts (in terms of the assignment).
Yes, it will take you some time to figure out our code, but it will be much less
than it would take you to write it yourself. (Although, if you want to work hard,
you are welcome to do that - see below).
Basically in this project you will need to:
Find your way around the framework code.
Add the basic functionality: draw a track (curve) based on the control points and
draw a train on that track. If you do the latter part correctly, the framework will
make it easy to animate the train going around the track. You will also need to
implement a "train view" (so the user can "ride" your train).
Add more advanced features: nicer drawing of the track, arc-length parameterization,
more kinds of splines, physics, ...
Add special effects and extra features to make it really fun. Really nice looking
train cars, scenery, better interfaces for creating complex tracks, ...
I must emphasize that the basic functionality is most important, and the core advanced
features (arc-length parameterization) are the next most important things. Fancy
appearance (like using textures and pretty lighting) aren't the focus here - add
them only if you have time after doing the more important things.
We have provided a sample solution (also see the discussion
of the source and framework) of the possible features
(at least the most common ones). We recommend that you play with it a bit to understand
how it works. The example also has options that lets you see some of the most common
mistakes and simplifications that students make.
There are two example solutions to this project in /p/course/cs559-lizhang/public/train-examples.
One is a version that Prof Mike Gleicher wrote and another was written by a really
good student (robs-train, requires glut32.dll under the same directory). I recommend
that you try them out to get an idea as to what you'll be doing.
Mike's sample train, circa 1999
Rob Iverson's A+ assignment from 1999
While the assignment was a little bit different in 1999, the basic idea was the
same. For a totally crazy solution to this assignment, check out RocketCoaster.
Note: at the beginning of the project, you might not understand all the things we're
going to ask you to do. Don't worry - you'll be learning it all soon enough!
Historically, this project is done individually. This semester, you are expected
to complete the assignment in groups (two people in each group).
Your program must use OpenGL and run on the XP computers in the department computer
lab (like everything else in this class). While we strongly recommend you use the
framework code, this is not a requirement. The Framework/Example solution uses FlTk,
but you can use any UI toolkit that you wish, providing it's available on the department
machines as we need to be able to build your program.
If you want to use other external libraries/code, please ask us. Something like
a math library or data structures library is probably OK, but please check.
The project is due on Monday, April 4th. Late projects are accepted according to
the class late penalty. We will probably grade these assignments with scheduled
live demos - these will be announced before the due date, so you'll know when they
start (and very late projects will not be accepted).
The most basic part of this assignment is to provide a "world" for the train track.
Your program must do the following things (all of these are provided by the
provided framework):
- Provide a user interface to look around the world, as well as providing a "top down"
view.
- You must have a "ground" (so the track isn't just in space).
- Provide a user interface that allows control points to be added, removed, or repositioned.
Note: even if you do a very advanced interface, you should display the control points
and allow for them to be edited manually.
- Allow for the control points to be saved and loaded from text files in the format
used by the example solution.
- Provide lighting. Allow things to be animated (have a switch that allows the train
to start/stop), as well as allowing for manually moving the train forward and backwards.
If you make your own framework, please make sure you can do all of these things.
You won't get many extra points for writing it yourself, but you will lose points
if you don't have the basic features.
The basic/essential features you must add:
- Have a track that is (at least) C1/G1. Your program should draw the track. You might
want to support multiple kinds of curves (like a C(0) track with line segments for
testing). But you must provide at least a C1/G1 track. (we recommend cardinal cubic
splines). The track should be a loop, always, and should be either interpolate or
approximate the control points. You might want to support C0/G0 tracks as well for
testing.
- Have a train that goes around the track (with a "run" button to start/stop it).
The train should always be on the track. Your train need not be fancy, but it should
be obvious which end is the front. And your train should not distort in wierd ways
as it moves (if it is not rigid, it should be for a good reason).
- Have the train oriented correctly on the track. The train should always face forward
if the track is flat, and mostly face forward on a 3D track. Getting 3D orientation
correct in the hard cases (like loops) is a more advanced feature (see below).
- Allow the user to "ride" the train (look out from the front of the train). There
should be a button or keystroke to switch to this view. (the framework has a "Train"
view button)
- Have some scenery in the world besides the groundplane. (note that the example solution
does not have this)
- Your program is properly documented, is turned in correctly, and has sufficient
instructions on how to use it in the readme file.
- You should have a slider (or some control) that allows for the speed of the train
to be adjusted (how far the train goes on each step, not the number of steps per
second).
The framework code is designed to make it easy to add all of those things. In fact,
there are "TODO:" comments explaining where to plug them in. See the the discussion
of it in the provided framework.
The framework code was used to make the sample solution. We didn't give you all
of the files, but you can see the "hooks" to the parts we didn't give you (they
are turned off with a macro). In some places, we intentionally left extra code for
you to look at as a hint. The framework has some spiffier features (like drop shadows),
and some features you may not need (the control points have "orientation").
Among the two sample solutions (Mike's and Rob's), Mike's sample
solution (mikes-train.exe) does not do all of these. (the train doesn't have a front,
and the only scenery is the point light source - also, there's a wierd bug where
the train stretches out when it goes down a hill).
Meeting the basic requirements will get you a basic grade (definitely a C or better).
But to get a better grade, and to really make the assignment fun, you should add
some advanced features to your train.
Note: the exact point values for each of these is not given. The rough guide here
will give you some relative importance (big features are worth more than small ones).
We will only check the features that you say that you have implemented correctly.
Partial credit will be given for advanced features, but negative credit may be given
for really incorrect features. (so, its better to not say you implemented a feature
than to show us something that is totally wrong).
Also, remember that in your demo, you will have to show off the feature, so think
about what demonstration will convince us that it works. For example, with arc-length
parameterization, you're best off being able to switch it on and off (so we can
compare with the normal parameterization), and think about a track that really shows
off the differences.
- Arc-Length Parameterization (BIG)
Having your train move at a constant velocity (rather than moving at a constant
change of parameter value) makes things better. Implementing this is an important
step towards many other advanced features.
You should allow arc-length parameterization to be switched on and off to emphasize
the difference, you should also provide a speed control.
- Give a tension control for the splines (small)
This is so simple, but it will give you some intuitions for what the tension parameter
does. For cardinal splines, you could have a different tension value for each control
point. You should allow for tension to be adjusted interactively (like with a slider).
- C2 Curves (medium)
Having C2 Curves are better than C1 curves. (the 2nd order discontinuities would
make the motion unrealistic). With C2 curves, your train may not go through the
control points, but only approximate them.
- Draw nicer looking tracks (medium)
The most basic track is just a line. To make something nicer (to make a tube or
a ribbon), you need to consider the geometry of the curve. Drawing rail ties (uniformly
spaced lines perpindicular to the tracks) and parallel tracks is a little bit tricky.
The rail ties require good arc-length parameterization (to get uniform spacing).
- Parallel rails
For parallel rails (like a real train), simply offsetting the control points (in
world space) doesn't work. You need to know the local coordinates as you go around
the track.
- Rail ties
Ties are the cross pieces on railroad tracks. Getting them right (uniformly spaced)
requires good arc-length parameterization. In the example code, you can turn the
arc-length parameterization on and off to see the difference.
- Correct Orientation in 3D (medium)
The simple schemes for orienting the train break down in 3D - in particular, when
there are loops. Make it so that your train consistently moves along the track (so
its under the track at the top of a loop).
One good way to provide for proper orientations is to allow the user to control
which direction is "up" at points along the curve. This allows you to
do things like corkscrew roller coasters.
- Have Real Train Wheels (medium)
Real trains have wheels at the front and back that are both on the track and that
swivel relative to the train itself. If you make real train wheels, you'll need
arc-length parameterization to keep the front and rear wheels the right distances
apart (make sure to draw them so we can see them swiveling when the train goes around
a tight turn).
- Have Multiple Cars on Your Train (medium)
Having multiple cars on your train (that stay connected) is tricky because you need
to keep them the correct distance apart. You also need to make sure that the ends
of the cars are on the tracks (even if the middles aren't) so the cars connect.
If you're really into trains, you could have different kinds of cars. In particular,
you could have an engine and a caboose.
- Implement simple physics (medium - its actually not hard once you have arc-length)
Roller coasters do not go at constant velocities - they speed up and slow down.
Simulating this (in a simple way) is really easy once you have arc-length parameterization.
Remember that Kinetic Energy - Potential Energy should remain constant (or decrease
based on friction). This lets you compute what the velocity should be based on how
high the roller coaster is.
Even Better is to have "Roller Coaster Physics" - the roller coaster is
pulled up the first hill at a constant velocity, and "dropped " where
it goes around the track in "free fall." You could even have it stop at
the platform to pick up people .
- Adaptive subdivision (or sampling) (small to medium)
To draw the curves (or to compute arc length parameterizations), you need to sample
along the curve (for example, to draw lines connecting the points). The curves are
simple enough that simply sampling them uniformly and densely is practical. Adaptive
sampling (when the curve is straight, fewer line segments are needed) is a better
approach, but the benefits may be hard to see. If you implement adaptive sampling,
be sure to have some way to show off that it really works.
These are really advanced features. It is much better to have the advanced features
(that are really central to the assignment) than these frills, but frills can be
fun. And we will give you points for them (but remember, you can't get points for
frills unless the more basic stuff works)
- Have People On Your Roller Coaster (small)
Little people who put their hands up as they accelerate down the hill are a cool
addition. (I don't know why putting your hands up makes roller coasters more fun,
but it does). The hands going up when the train goes down hill is a requirement.
- Lighting (small)
Having proper lighting makes things look more 3D. Its really easy to do in OpenGL.
- Hack Shadows (small)
Having hack shadows "dropped" onto the groundplane are more than just
eye candy - they actually make things more usable by giving a depth cue. The sample
programs do this - although to get full points, you'll need to use a stencil buffer
to make overdraw work correctly.
- Headlight for the Train (small)
Have the train have a headlight that actually lights up the objects in front of
it. This is actually very tricky since it requires local lighting, which isn't directly
supported.
- Have the train make smoke (small/medium)
Steam trains are the coolest trains, even if they are being a roller coaster. Having
some kind of smoke coming from the train's smoke stack would be really neat. Animate
the smoke (for example, have "balls of smoke" that move upward and dissipate).
- Direct Manipulation or Intepolating C2 Curves (BIG)
The easier form of C2 curves are approximating. Making it so that the user has direct
control of the C2 curves (either having it interpolate the control points, or having
the user adjust the track and having the system adjust the control points to make
the track fit. One method for doing this is the paper:
Barry Fowler, Richard Bartels. "Constraint-Based Curve Manipulation,"
IEEE Computer Graphics and Applications, vol. 13, no. 5, pp. 43-49, September/October,
1993. If you're on the UW campus, you can get the article here.
Note: to get full credit for this feature, you need to provide for total control
over the curve - just translating a control point when the user tries to move the
curve doesn't apply.
An even more interesting variant of this is to allow the user to sketch a curve,
and then fit a smooth curve to the sketched one.
- Something so cool we can't predict it
Yes, you might think of something to do that we didn't mention here. If its really
cool, we might give you points for it. We'd like you to focus on trying to do more
with the curves aspect of this assignment (rather than making arbitrary eye-candy),
so we won't give you points for just making eye candy (e.g. putting textures on
things) - there will be a whole project devoted to that. If you want to do something
and you want to make sure it will be worth points, send the instructor email.
We divide this project as 5 stages.
This written assignment is described on this page.
The purpose of this phase is to:
- Make sure you have worked out the mechanics of getting and OpenGL program to compile.
- Can work out the basic mechanisms for making interactive programs.
- Can make programs that do animation in OpenGL.
These are all essential elements for your roller coaster. So we want you to try
doing these things without all of the added complexity of curves and 3D.
You must turn in a program that:
- Has sufficient documentation that the TA can compile the program and use it enough
to confirm that it has all of the required features.
- Has an OpenGL window.
- Has a collection of "points" (drawn as small shapes like squares).
- Has an "animate mode" that when turned on has another shape orbit the
selected point (like a moon orbiting). The spinning should be animated. It needs
to start and stop when the animate mode is turned off.
Once you are able to do these simple tasks by yourselves, you are in a better position
to read and understand our skeleton code for this project, which does much more
complex tasks.
The tutorials will guide your through learning the basic skills you need to complete
this assignment. Be sure to read the OpenGl Survival
Guide for help getting started. The Main.Tutorials
will help you with the mechanics of getting your program to compile and give your
some ideas for user interfaces. The Main.SampleCode
will provide you with useful elements for building things (particularly RunButton).
Here is another simple sample code for building
the RunButton.
In order to make a roller coaster, you need to understand curves and perspective
transformations. So we'll give you a written assignment described
here designed to give you some practice.
The exam will cover the same material, so this assignment will be good practice
for the exam. In fact, a portion of the problems from this written assignment will
appear on the exam (with some of the details changed to discourage you from trying
to just memorize the answers).
If you work hard enough, you may be able to find the answer sheet to these howemwork
questions. However, we discourage you from doing so because you won't have a chance
to do so in the exam. Also, the previous answer sheets may have errors. It's embarrassing
that you give a wrong answer that is the same as in the previous answer sheet. It
happened when I taught last time.
We want to make sure that everyone is making good progress on the project. In particular,
we want to make sure that by March 24th (about 10 days before the project is due),
you've at least gotten the basic 3D interactions working. Here is a
skeleton solution code for this project that has many UI functions implemented
for you as a good starting point this phase.
For this phase, you need to read the skeleton code, well understand what it has
done and what remains to be done, and where you should add code to get these additional
things done. We're just checking for the first pieces to make sure you've started.
Be warned: if you only have these basic requirements done by the checkpoint,
you still have a lot of work to do. To avoid having a hectic week
before the project is due, we recommend that you have more than the checkpoint requirements
done.
Your roller coaster program will need to have the following features.
- You must have a "ground"
- You must have points that can be positioned in the world. The user needs to be able
to adjust the positions of points, add points, and delete points.
- The user must be able to move the camera around to look around the world.
- There must be some other objects (a cube, a cone, simple objects are Okay) in the
world besides the points (scenery to look at when riding the train/roller coaster)
- Connect the points with some curves; line segments are fine
- You need to be able to start and stop the animation in the world. When there is
a roller coaster that will be moving. For now, you must have something (e.g., a
cube) moving along the curve (e.g., the line segments) going in a circle. That moving
object should have a clear front (good practice for making a train that has a front).
If you download the skeleton code, you will notice it has many of these features
already. We actually encourage you to use the skeleton code to make your
interface. Your main job is to read and understand it.
For this part of the project, you will turn in the actual roller coaster simulator,
and the required documentation. As with all projects, we will evaluate your project
both in a demo session (where you get to show it off) and by evaluation of your
code and documentation.
You must implement all the basis functions, and advanced functions if you want a
higher grade, and some of bells and whistles if you enjoy doing so.
This is the actual project when you turn in your train/roller coaster program and
feel the big sense of accomplishment that you've created something really cool.
Along with the program itself, you'll turn in documentation as to how it works.
>Remember: while the majority of you project grade will come from our evaluation
of your final program, the earlier stages do count too! In addition, the written
assignments are important practice for the exams, so blowing them off will also
hurt you there. Finally, the checkpoints are important to make sure you're making
progress over the entire 5 weeks of the project: this project is a lot to do in
1 week, but not so bad if you think of it as a 5 week effort.
By the deadline (Apri 5th) you must turn in:
- Everything needed to compile your program (.cpp files, .H files, .vcproj files,
.sln files, and UI files or other things your program needs). Be sure to test that
your program can be copied out of this directory and compiled on a Storm computer.
- Your README file.
- A screen shot (or two) showing off neat things in your program.
- Some example track files. You should not turn in the track files that we distribute
(we give you a bunch) - only turn in ones that you made.
Your README.txt should explain the following:
- a list of all the features that you have added, including a description, and an
explanation of how you know that it works correctly.
- an explanation of the types of curves you have created
- a discussion of any important, technical details (like how you compute the coordinate
system for the train, or what method you use to compute the arc length)
- any non-standard changes that you make to the code
- anything else we should know to compile and use your program
Use the framework. It will save you lots of time.
In case it isn't obvious, you will probably use Cardinal Cubic splines (like Catmull-Rom
splines). Cubic Bezier's are an option (just be sure to give an interface that keeps
things C1. For the C2 curves, Cubic B-Splines are probably your best bet.
You should make a train that can move along the track. The train needs to point
in the correct direction. It is acceptable if the center of the train is on the
track and pointing in the diretion of the tangent to the track. Technically, the
front and back wheels of the train should be on the track (and they swivel with
respect to the train). If you implement this level of detail, please say so in your
documentation. It will look cool.
In order to correctly orient the train, you must define a coordinate system whose
orientation moves along with the curve. The tangent to the curve only provides one
direction. You must somehow come up with the other two directions to provide an
entire coordinate frame. For a flat track, this isn't too difficult. (you know which
way is up). However, when you have a roller coaster, things become more complicated.
In fact, the sample solution is wrong in that it will break if the train does a
loop.
The 1999 sample solution defines the coordinate frame as follows: (note: you might
want to play with it understand the effects)
- The tangent vector is used to define the forward (positive Z) direction.
- The "right" axis (positive X) is defined by the cross product of the world up vector
(Y axis) and the forward vector.
- The local "up" axis is defined by the cross product of the first two.
Doing arc-length parameterizations analytically is difficult for cubics. A better
approach is to do them numerically. You approximate the curve as a series of line
segments (that we know how to compute the length of). A simple way to do it: create
a table that maps parameter values to arc-lengths. Then, to compute a parameter
value given an arc length, you can look up in the table and interpolate.
Alternatively, you can do a little search to compute the arc length parameterization.
If you have a starting point (u) in parameter space, and a distance you want to
move forward in arc length space, you can move along in parameter space, compute
the next point, find the distance to it, and accumulate.
Be creative and have fun!