This page does not represent the most current semester of this course; it is present merely as an archive.
You will submit a webpage that has
As with the WebGL warmup, you’ll submit
an HTML file and any number of js, glsl, json, and image files. Also
submit a file named implemented.txt
listing any optional
parts you believe you completed.
As with most assignments, this is divided into required and optional parts. For full credit, you need all the required parts of each assignment and an accumulated average of 50 optional points per assignment. Excess optional points at the end of the semester award extra credit at 3% of their raw point value.
This assignment build off of the terrain assignment; if you didn’t get the required parts of that assignment working you’ll need to return to it and finish it first.
This assignment, like all other assignments, is governed by the common components of MPs.
Add a keyboard listener that handles user input and moves the camera
location around the scene. To handle held-down keys you’ll need both a
keydown
and keyup
listener.
The recommended way to listen to keys for this assignment is
window.keysBeingPressed = {}
window.addEventListener('keydown', event => keysBeingPressed[event.key] = true)
window.addEventListener('keyup', event => keysBeingPressed[event.key] = false)
and then in your animation function (whatever calls itself with
requestAnimationFrame
) use keysBeingPressed
to
decide how to move the camera.
For the required part, your camera needs to respond to the at least four keys:
if (keysBeingPressed['w'])
move the camera forwardif (keysBeingPressed['s'])
move the camera
backwardif (keysBeingPressed['a'])
move the camera to its left
(move, not turn)if (keysBeingPressed['d'])
move the camera to its right
(move, not turn)These keys are common in video games and are commonly called
WASD
.
Holding down a key should result in smooth motion in the given direction until the key is released.
Instead of a constant color or height-based color ramp, use a texture map for the color of the terrain. The image you use must be one of
A useful source of images with a given license is Duck Duck Go’s license-filtered image search. The photo should be in good taste (nothing offensive) and not primarily black (otherwise we won’t be able to see the lighting on the terrain).
Use texture coordinates based on the (x,y) positions of the terrain, scaled such that the image covers the entire terrain once and at approximately the right aspect ratio (i.e. if you have a square terrain and rectangular image, only map a square part of the image to the terrain).
See our page on textures for the technical details of how to get a texture map set up.
We provide an example public-domain image you may use if you wish.
Add four more keyboard controls:
ArrowUp
and ArrowDown
pitches the camera
up and downArrowLeft
and ArrowRight
turns the camera
to the left and rightThe WASD keys should work as defined by the current camera view:
W
means forward in the current view, not in some global
world view.
Add a key that acts like a toggle instead of a held-down control.
Pressing G
should toggle between flight mode (default) and
on-the-ground mode. When in on-the-ground mode, the altitude of the
camera should be fixed at 2 terrain grid cell lengths above the current
terrain.
Suppose your terrain goes from -1 to 1 in x and y and has 50 points on along each axis. Then the terrain grid cell length is \frac{1--1}{50} = \frac{2}{50} = 0.04, meaning the camera should be kept 0.08 above the ground in on-the-ground mode.
In on-the-ground mode camera movement speed should be slow enough to have several frames moving across one grid cell, and heights should adjust smoothly when moving between cells of different height.
If the camera is driven off the edge of the terrain, you should do something sensible: keep the same height, revert to some globally-defined ground height, switch into flight mode, or prevent the motion by snapping the camera back to the nearest over-ground position.
Load an OBJ file and place it on top of the center of your terrain.
See the OBJ parsing page for tips on how to load an OBJ file. Several sample files are available:
Handle f
and v
. Load
example.obj
(always that exact filename), which may be
different when we test your code than it was while you were developing
your code.
If example.obj
does not exist
(i.e. fetch("example.obj")
fails) your code should run
normally with just the terrain, no OBJ loaded.
This should work with both the teapot and triangle model at a minimum
(i.e. after running cp teapot.obj example.obj
or
cp triangle.obj example.obj
).
Handle v
in both the 3-value position-only and 6-value
position-and-color forms.
You’ll likely need separate shaders for the two because they have different sets of vertex shader inputs.
The example file cow.obj
has vertex colors.
window.location.hash.substr(1)
if that’s defined, or example.obj
otherwise. That will
allow us to visit URL/to/your/file.html#thing.obj
to have
it load thing.obj
instead of example.obj
.
Handle vn
and vt
as well as f
and v
.
If the OBJ file uses vt
and you implement
vt
, you should use the same name as a OBJ with the ending
jpg
instead of obj
as the texture map (e.g. for
thing.obj
use thing.jpg
as the texture
map).
You’ll likely need separate shaders for the v
-only case,
the v
+vn
case, the
v
+vt
case, and the
v
+vn
+vt
case because each has a
different set of vertex shader inputs.
You don’t need to combine these with vertex colors, even if you implement them both.
The example file monkey.obj
has texture coordinates and
surface normals.
Add a key that acts like a toggle instead of a held-down control.
Pressing F
should toggle between no-fog mode (default) and
fog-mode. In fog mode, the fragment shader should cause fragments that
are farther from the camera to be drawn closer to the background color,
which should be some pale foggy color if you implement fog.
There are multiple options for fog. From simple to accurate, you may do any of
gl_FragCoord.z
; at 0 use full object color, at 1
use full fog color.Your fog should be dense enough to be obviously present and thin enough to see at least part of the terrain from the initial camera position.