Lab: Dotplots
In this chapter, you've been learning how to model objects as a collection of points and lines. Let's apply this knowledge by writing two renderers, one to plot a circle and one to plot a more interesting curve.
Circle
Your first challenge is to plot a circle. WebGL doesn't have a circle primitive, so the best you can do is plot a regular polygon with many sides. Follow these steps to create a circle regular polygon renderer.
npm run dev
to start up a web server.circle
. Put a new li
and a
in the index page and make a copy of your hello-cornflower
directory named circle
.generateCircle
. You are going to factor out the vertex buffer and VAO creation to this separate function so that you can regenerate the circle without reinitializing the whole renderer.initialize
that deals with positions
, attributes
, and vao
to generateCircle
. Leave the shader code in initialize
because it won't change.initialize
, call generateCircle
. You should see the two dots as before.generateCircle
accept parameters named n
and radius
.positions
array so that it contains n
evenly spaced vertices on the perimeter of a circle of the given radius. You'll need to loop through the angles around the circle. A vertex's location can be computed by turning its angle and radius into Cartesian coordinates:
generateCircle
with various parameters. Ensure that you can see circles of various sizes and roughnesses.body
tag in index.html
to give the user an interface for changing the sample rate and radius:
<div class="controls">
<label for="n-input">n</label>
<input id="n-input" type="text">
<label for="radius-input">radius</label>
<input id="radius-input" type="text">
</div>
<div class="controls"> <label for="n-input">n</label> <input id="n-input" type="text"> <label for="radius-input">radius</label> <input id="radius-input" type="text"> </div>
public/style.css
to position the controls atop the canvas:
.controls {
position: absolute;
top: 5px;
right: 5px;
display: grid;
grid-template-columns: auto auto;
grid-gap: 2px 5px;
justify-items: end;
z-index: 1;
}
.controls { position: absolute; top: 5px; right: 5px; display: grid; grid-template-columns: auto auto; grid-gap: 2px 5px; justify-items: end; z-index: 1; }
src/main.ts
:
let n = 6;
let radius = 0.9;
let n = 6; let radius = 0.9;
n
by adding this code at the end of initialize
:
const nInput = document.getElementById('n-input') as HTMLInputElement;
nInput.addEventListener('input', () => {
n = parseInt(nInput.value);
synchronize();
});
const nInput = document.getElementById('n-input') as HTMLInputElement; nInput.addEventListener('input', () => { n = parseInt(nInput.value); synchronize(); });
attributes
a global variable instead of a local one. We need it to be global so we can destroy the old attributes when a new circle is generated. Keep its assignment statement where it is, but move its declaration to the global scope.synchronize
function, which will be called whenever a number in the text inputs changes:
function synchronize() {
// Release previous VAO and VBOs.
vao.destroy();
attributes.destroy();
// TODO: regenerate circle and redraw.
}
function synchronize() { // Release previous VAO and VBOs. vao.destroy(); attributes.destroy(); // TODO: regenerate circle and redraw. }
Lissajous Curve
Your second challenge is to render Lissajous curves. Just like circles, they can be modeled through a set of parametric equations. Their coordinates are computed as functions of variable \(t\):
The domain of \(t\) is \([0, 2\pi]\). The position of the first vertex is \(\begin{bmatrix}x(0)&y(0)&z(0)\end{bmatrix}\). Complete the following steps to build a Lissajous renderer.
circle
directory to a new directory named lissadots
.generateCircle
to generateLissajous
.n
, a
, b
, ratio
, and shift
.getElementById
.synchronize
whenever these inputs are modified.synchronize
. Only parameter n
is an integer. The others are reals.generateLissajous
and its calls to generate Lissajous curves instead of a circle. The code will have a very similar structure to your circle generator. It just generates a different shape and relies on different free variables.Submission
To receive credit for your lab work, follow these steps:
circle
and lissadots
folders before the host closes the session.#lab
channel in Discord. Tag your partner in the message with @
. No voiceover is necessary.Only labs submitted on time will be granted credit. Late labs or forgot-to-submits are not accepted because Monday at noon is when your instructor has time to grade.