Programming Assignment #2
1 Introduction
Your second assignment will require you to make a controlled animation and to learn
some more advanced OpenGL programming. You will create a rollercoaster track along
which the camera will move. You will include an environment for your rollercoaster beyond
the starter code skybox, which may include a terrain (heightmap is included which you may
use), a track your rollercaoster will run on, or other scenery. You may use the GLFW toolkit
for interaction with the mouse and keyboard to give the user interactive control over rotation
of the camera or other control over the motion / view.
Note about New Starter Code: The starter code contains both a working project 1
code and the project 2 code. Each project has it’s own subdirectory and, in Visual Studio,
you can set the Single startup project to compile either one. The movement code from
project 1 is still present and you may remove it (or anything else) if you aren’t using that
piece of code.
Intermediate Submission: For you intermediate submission, you should have the roller-
coster itself mostly made and maybe some work on the camera following the track.
For both the intermediate and nal submissions, you must submit working code (the
Project 2 Folder) as well as executable (built for release), example output (including a
video), and a readme le explaining whether or not you met each requirement and detailing
any extra credit you added. The readme le is important! Your grade will su er if you
do not include one! The folder structure is (Necessary because of le path) should be the
Project2 folder, with a video, executable, and readme in it. As long as the folder is called
Project2, the links for the executable will work.
2 Environment
It is required to have a skybox; it is ne to reuse the skybox from your heightmap project
and a skybox and skybox is provided for you in the starter code. You may get new textures
to put on the faces. You may leave the a terrain using the code to create a heightmap
provided. You can also create / download .obj or other kinds of object les to make more
realistic objects within your program (an example is shown in the starter code). Feel free to
add anything else you want to for scenery; be creative, it may earn you some extra credit!
Take a look at Figure 1 for some inspiration on the kinds of things you can do.
2
Figure 1: Screenshots of completed rollercoaster.
3 Rollercoaster Track
3.1 Track appearance
The track for your roller coaster must be detailed. It must have 3D structure, not be made
merely of lines. It must have texture to it and the lights in your scene must also have dif-
fuse, ambient, and specular properties. An example of a directional light, four point-lights,
and a spotlight are given in ‘void set lighting(Shader shader, glm::vec3 * pointLightPosi-
tions)’. If you want to de ne more lights, you will need to change the ‘lightingShader *.frag’
‘NR POINT LIGHTS’ variable (both of them).
In order to edit the texture of the material, can use the textures provided or nd / create
your own. The lightingShader specular assumes that your input has a specular texture image
(look at media/textures/container2 specular.png). The lightingShader basic shader is just
set from the code (look at the ‘heightmap::Draw(Shader shader, unsigned int textureID)’
function for an example).
3
3.2 File Types
You will not be writing one speci c rollercoaster track into your code. Instead, you will
be reading a track le which dictates control points, a set of locations that your track must
pass through in the order they are read. The track le (Figure 2) will instruct your program
to read one or more spline les (extension .sp) which contain displacements from the last
control point to the next one. This allows you to reuse common pieces (a turn, a hill, a
loop...) by including a spline le multiple times in your track le. An example spline le is
shown in Figure 3.
The rst number indicates the length of the le (how many entries there will be). Then
each line is a spline part le to be read. A track le may include many spline les or just
one. It may also reuse pieces, as seen here. Your track MUST connect to itself (it must be
a loop) and the rollercoaster cannot stop.
For each spline part, the rst number indicates the length of the le (how many entries
there will be). Then each line is a 3 dimensional o set to the next control point. So (1, 0,
0) would indicate that the next control point should be one unit in the X direction from
the last control point, but not that it should actually be at the point (1, 0, 0) in the global
coordinate system.
14
spline parts/x.sp
spline parts/x.sp
spline parts/turn-x-y.sp
spline parts/y.sp
spline parts/y.sp
spline parts/y.sp
spline parts/turn-y-negx.sp
spline parts/negx.sp
spline parts/negx.sp
spline parts/turn-negx-
negy.sp
spline parts/negy.sp
spline parts/negy.sp
spline parts/negy.sp
spline parts/turn-negy-x.sp
Figure 2: A Sample Track File. Each line is a di erent spline part which de nes the control
points.
4
Figure 3: A Sample Spline Part File showing the change between control points in the X,
Y, and Z.
Figure 4: Output of Starter Code showing the track control points as boxes, a load .obj
model of a crysis character, and the heatmap.
3.3 Interpolation
The output of your starter code, seen in Figure 4, only places a dot at each control point.
In order to draw a detailed track, you must have a way of guring out intermediate points
between the control points. This is called interpolation.
To interpolate, you will use the Catmull-Rom splines that you learned about in class.
5
Figure 5: Interpolating spline from point B to point C.
Let’s review: To interpolate between two control points, we need to know their locations as
well as the locations of the control points immediately before and after the points we wish
to interpolate.
In Figure 5, if we wish to interpolate between B and C, we need to know A, B, C and D.
We will perform. the interpolation by de ning a parametric function f(u). As u goes from 0
to 1, f(u) will travel along the magenta line from B to C.
In your code, you will implement this matrix multiplication (you can work it out on paper to
get a long function in terms of A, B, C, D, , and u or use glm to do the matrix operations).
You probably want to de ne a function that takes four points and a u value and returns the
3D location at that u value interpolating between the 2nd and 3rd point. It is okay for
to always equal 0.5. When you draw your track, to get smoothly interpolated locations for
vertices, you can keep a queue of 4 control points and iterate u by a small increment from
0 to 1. Each time u reaches 1, pop the oldest control point from your queue and push the
next one to the end, then set u back to 0 and iterate again.
3.4 track.hpp
This is the track header le and is very similar to the heightmap.hpp le. Provided is
a le reader for your spline control points (with an example already provided as ‘rc Spline
g Track’). You will need to create your track objects here (take a look at Figure 1 for some
examples). At a minimum you should be the rails and the planks between the rails (but you
can have a switch to turn them o if you think it look better without them). Make sure
6
to create the normals in your Vertex since the lighting won’t work without them (look at
heightmap.hpp for an example on how to create the normals. You may add whatever helper
functions you want here.
One thing which would make the project easier would be to use a quaternion rotation
matrix to track to rotation between elements (an example of this is provided in the source
code). This would make it easier to cumulate each rotation between each point and object.
You will need to ll in the following functions in track.hpp:
glm::vec3 interpolate(glm::vec3 pointA, glm::vec3 pointB, glm::vec3 pointC, glm::vec3
pointD, oat tau, oat u)
Write the interpolation here and return the interpolated point.
void create track()
An example on how to index the control points is provided for you, you can erase it
for your track.
void setup track()
Similar to before, initialize the bu ers and setup everything for the objects. Look at
heightmap.hpp for an example.
4 Camera Motion
4.1 Physics
Your camera must move along the track with somewhat realistic physics. This means
that it must follow gravitational acceleration. You need to either start your rollercoaster
on a hill or give it some initial velocity so that it can get over hills. The basic physics
equations you need to know are that the sum of KineticEnergy and PotentialEnergy must
never changes.KineticEnergy = 0:5 mass velocity2. PotentialEnergy = mass 9:8
height. Give your coaster some non-negative mass, it does not matter what. At the beginning
of your program, calculate how much energy the coaster has from its starting height and
initial velocity. Every time you need to move the coaster, you can calculate its current
velocity by examining its current height and making sure that the sum of KineticEnergy and
PotentialEnergy is the same as at the start.
4.2 Moving the Camera
The camera position is determined essentially the same way that you drew the roller-
coaster; iterate through the control points keeping a queue of 4 points and, within that loop,
iterate u from 0 to 1 by some small increment to get smooth interpolation. You should
incorporate the deltaTime variable to determine how much to move between each frame.
Each time you move the camera, you know its current position (both in global coordinates
and as a u parameter value along a segment of your track) and its velocity (dependent on
initial energy and current height). If you use a timer function, you set the refresh rate, so
you know how much time will elapse before the next frame. is rendered. The distance you
want to travel is equal to your current velocity times the time to the next rendering. When
you know the distance you want to travel, there is still a problem; you need to know what
value of parameter u is that distance away from your current position. In order to nd
this, we need to examine the distance along the curve. Distance between points(a;b;c) and
(x;y;z) is equal to p(a x)2 + (b y)2 + (c z)2. You can use this formula for distance to
determine the correct u value: beginning at your current u position, increment u by a very
small amount and test the distance (in global coordinates) between your current location
and the one at the new u value. If the distance is less than your desired travel distance,
move the camera to the location at the new u value, decrease your desired distance to travel
by the distance you just moved the camera, then repeat the process (Figure 6). Repeat this
until your very small increase in u would result in greater distance travel than you desire, at
this point you have moved enough and will render the new image.
Figure 6: Moving Your Camera.
Similar to moving your objects around, a quaternion rotation matrix to track the param-
eters in the camera.hpp le. This would make it easier to cumulate each rotation between
each point between each shift in movement and can be converted back to Euler angles us-
ing glm::eulerAngles(Quaternions) for the lookat function or rotate the initial Front and Up
vectors with the quaternion. The function \void ProcessTrackMovement(glm::vec3 newPo-
sition)" has been added to the camera.hpp function which you can ll out to handle moving
to a new camera position.
You can look at the camera.hpp le to see how the ‘wasd’ movement are applied as a
guide to setting up the movement.
5 Extra credit
Possible ideas are extra track features (like support columns), secondary animations
(other moving things in the environment), banking turns, interactive features, detailed
scenery, or anything else you can think of. As usual, be creative, describe everything you do
in the readme le, and make things look nice to get more points.
Another possible extension would be to use instancing for your track. Instancing re-
duces the time necessary to create each object if all the objects have identical vertices.
This will greatly reduce the time necessary for rending the track variable. This is a bit
more advanced so it is not required. Here is a link to the tutorial (this would allow you
to have thousands of objects rendered very quickly): http://www.learnopengl.com/#!
Advanced-OpenGL/Instancing
6 Shaders
There are four shaders included in the starter code.
6.1 lightingShader basic
These are the basic texture shaders with lighting. You should look through shader.frag
shader too help understand how the lighting works. The vertices need to have the world
coordinates XYZ, the normals of each triangle, and the texture coordinates. You need to
de ne the material’s shininess and the uniform. specularity. Look at heightmap.hpp for an
example.
6.2 lightingShader specular
This is the more advanced shader which uses a specular map to de ne where to re ect
the specular parts of the texture. This needs the same vertices attributes as the previous
shader (XYZ, Normal, Texture). You still need to de ne the shininess though.
6.3 re ectionShader
These are some shaders you can use to play around with. They re ect the skybox back
(but nothing else). They only require the XYZ world coordinates.
6.4 skyboxShader
Since the skybox does not need a model matrix (since it never changes position), this is
taken out to increase e ciency. You shouldn’t have to modify this one.