This page does not represent the most current semester of this course; it is present merely as an archive.

1 Purpose

This assignment is unlike MP1 in two keys ways.

  1. It was unanimously identified as the easiest MP of the semester by last semester’s students.

  2. The primary goal is for you to explore. Other MPs have specific algorithms to implement and tasks to accomplish; this MP is mostly about trying things out. Tasks are vague and grade at full credit if they make a reasonable approximation of their description.

Largely the goal is familiarity with writing Javascript, WebGL2 and how they work together. Later MPs will test you ability to do specific things with WebGL2.

2 Overview

University of Illinois Logo
University of Illinois Logo

You will submit a webpage that has

  • One canvas
  • An animation of the majestic and inspiring University of Illinois logo
  • Additional animations selectable using radio buttons
  • All animations are 2D (3D will be added in later assignments)

As with the WebGL warmup, you’ll submit an HTML file and any number of js, css, glsl, and json files. No image files are permitted for this assignment. Also submit a file named implemented.txt listing any optional parts you believe you completed.

You are welcome to use a JavaScript math library, such as the one used in in-class examples or others you might know.

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.

This assignment, like all other assignments, is governed by the common components of MPs.

3 Required (50 points)

HTML layout

Your HTML file must contain

  • Compliance content, including DOCTYPE, lang, charset, and title.
  • At least one script element in the head, and none outside the head
  • One canvas element.
  • On radio button for the required part, plus more for optional parts, all with the same name attribute.
  • A label for each radio button briefly describing what it will display. These should be a label from this page (such as Required or GPU-based vertex movement) followed by a colon and a short description of what will be displayed (such as Required: The "I" logo spinning clockwise while moving along a counterclockwise path).
  • The first radio button defaults to being selected.

We have an example HTML file that meets these requirements you might find a useful reference or starting point: radios.html.

About requestAnimationFrame

Each call to requestAnimationFrame queues a function to be called in the future and returns a handle to that function. To have an animation, we need to ensure there is always one (and only one) pending function requested by requestAnimationFrame. If we have fewer than one, we don’t get an animation. If we have more than one, the browser tries to do several things at once and will slow down and eventually freeze.

When we have different animations we could use, we have to approaches to ensure the only-one rule:

  • When switching, cancelAnimationFrame what used to be pending and requestAnimationFrame the new callback

    function draw1(milliseconds) {
        // ...
        window.pending = requestAnimationFrame(draw1)
    }
    function draw2(milliseconds) {
        // ...
        window.pending = requestAnimationFrame(draw2)
    }
    function radioChanged() {
        let chosen = document.querySelector('input[name="example"]:checked').value
        cancelAnimationFrame(window.pending)
        window.pending = requestAnimationFrame(window['draw'+chosen])
    }

    or

  • Have just one function that requestAnimationFrames itself and dispatches to the right function for the current animation

    function draw1(milliseconds) {
        // ... does not call requestAnimationFrame
    }
    function draw2(milliseconds) {
        // ... does not call requestAnimationFrame
    }
    function timestep(milliseconds) {
        let chosen = document.querySelector('input[name="example"]:checked').value
        if (chosen == 1) draw1(milliseconds)
        else if (chosen == 1) draw2(milliseconds)
        requestAnimationFrame(timestep)
    }

Either approach can work, but you can’t mix-and-match: pick one or the other.

Javascript style

Your javascript must break work into reasonable chunks, either as functions with meaningful names (preferred) or using whitespace and comments to separate parts of computation.

Comments should follow the Google JS commenting style. At a minimum, have a comment preceding each function, preferably in JSDoc style; additional comments are also encouraged.

2D model of logo

Make a reasonable polygonal approximation of the University of Illinois logo. No need to model the curves where the vertical bar meets the serifs.

According to the Office of Strategic Marketing and Branding, the logo has RGB 255/95/5, which converted to 0–1 colors used by WebGL is (r,g,b) = (1, 0.373, 0.02). Sometimes the logo has a blue outline; if you wish to do that it should be RGB 19/41/75 meaning (r,g,b) = (0.075, 0.16, 0.292).

You should create this model by hand, such as by drawing the logo on graph paper. The by-hand requirement isn’t something we’ll even try to enforce or grade, but doing it that way will help build your brain’s ability to convert between shapes and coordinates, a valuable skill in graphics.

A process for creating 2D models by hand
  1. Draw the shape on graph paper
  2. Put a bold dot at each corner of the shape
  3. Number the points in any order, starting with 0
  4. Pick an origin and scale for the graph paper
  5. Create an array of vertices in numbered order, using coordinates from the graph paper
  6. Fill in a triangle on the graph paper and add the number of its three vertices to the triangles index array
  7. Repeat step 6 with another triangle, and then another, until the entire shape is filled in

WebGL displays things between -1 and +1 in x and y. If you modeled the logo with different bounds, you can adjust it in the vertex shader as e.g. by finding a scaling factor s and offsets dx and dy and using them as

gl_Position = vec4(vert.x*s + dx, vert.y*s + dy, 0, 1);
Logo dance

The logo should move about the canvas because its vertex positions are being modified by a matrix that varies with time. This means

  • having animation by the drawing function requestAnimationFrame(itself)
  • having a uniform mat4 in your vertex shader
  • assigning the matrix a new value each frame

Your animation should look smooth (no sudden jumps from one image to another) and should do at least two of

  • moving the logo
  • rotating the logo
  • changing the logo’s size

Do not squish or stretch the logo: any size changes should be uniformly applied to all dimensions.

Another animation
Picking another radio button should show a different moving WebGL image (not the logo) in the canvas. For the required part, this can be anything else, such as an example from class or the point cluster from the warmup

4 Optional

You should have one radio button for the required part, and one radio button for each optional part you implement (labeled so that we can tell which part it was). Each animation (other than the required one) should show off a different optional part.

CPU-based vertex movement (15 points)

Add an animation that uses the I logo but changes the vertex positions in the buffer every frame. They should change individually in a way not achievable using a matrix (i.e. not just rotate, scale, translate, or perspective).

This involves two parts: some Javascript code that creates or updates the list of positions in a Float32Array in CPU memory and connecting sending it to the GPU.

How to send new data to the GPU every frame
  1. When you gl.createBuffer() the buffer that will have changing data, store the result in a global variable or another place you can get at it again.
  2. For that buffer, call gl.bufferData(..., gl.DYNAMIC_DRAW) instead of the usual gl.STATIC_DRAW
  3. Every frame, after gl.bindVertexArray and before gl.drawElements repeat the gl.bindBuffer and gl.bufferData calls with the updated Float32Array.
GPU-based vertex movement (10 points)

Add an animation that uses the I logo but changes the vertex positions in the buffer every frame. They should change individually in a way not achievable using a matrix (i.e. not just rotate, scale, translate, or perspective).

This involves a vertex shader that uses gl_VertexID and a time-varying uniform as well as the model-specific position attributes to position each vertex. Only the vertex shader needs to change from the required portion.

Collisions (15 points)
Add an animation of two logos (or other shapes) colliding, with collision detection and response. The response may be either physics-based or stylized as long as the motion of the logos visibly changes upon collision.
Psychedelic (15 points)

Example psychedelic animation Example psychedelic animation Draw a quad that covers the whole canvas and use a fragment shader to create some kind of colorful pulsing pattern.

Two example animations are shown here; yours needn’t look like either of them but should similarly change with time, fill the screen with color, and vary nonlinearly across the screen instead of being interpolated from vertex colors.

Walking (15 points)
Draw a stick figure walking
Mouse response (10 or 20 points)

Have the motion respond to the mouse in a sensible way: a logo moves towards or away from the mouse, follows a path similar to the mouse’s path, etc.

If the response is immediate (for example, if jerky mouse motions results in jerky animations) then this is worth 10 points. If the response uses the mouse but also has some sense of momentum or gradual change, it is worth 20 points.

5 Grading Rubric

Required (50 points)
HTML style (10 points)
  • doctype
  • lang
  • charset
  • title
  • script in head
  • canvas
  • radio buttons that work
  • labels named as required
  • defaults to selecting the required animation
Javascript style (5 points)
  • readable chunks
  • with comments
Logo model (10 point)
  • made of polygons
  • looks like a capital I
Required animation (23)
  • animated
  • by changing a mat4 each frame
  • resulting in smooth motion
  • including the combination of two motion types
Radio button works (2)
  • can leave and return to required animation
Optional
CPU-based vertex movement
  • Vertices are moving individually in a way that cannot be created by multiplying them all by the same matrix
  • Code inspection shows this is happening by changing the vertex locations in the buffer sent to the GPU
GPU-based vertex movement
  • Vertices are moving individually in a way that cannot be created by multiplying them all by the same matrix
  • Code inspection shows this is happening by modifying vertex locations in the vertex shader
Collisions
  • Two or more moving logos or other objects
  • Paths cause them to come into contact with one another
  • Something (anything) visibly happens when they touch
Psychedelic
  • Boring geometry and vertex shader fills the screen with a large square
  • Interesting fragment shader adds pulsing colors to fragments
Walking
something resembling a stick figure with moving legs
Mouse
Lower point total
moving the mouse changes how the animation progresses
Rest of points
always moving in a smooth way with no sudden jerks or jumps when the mouse moves