By the end of this lab, you will:
JavaScript
,glMatrix
function called vec2.lerp
,To access the lab template, please click the assignment link in this discussion board message.
This lab is inspired by this exercise from the Pixar-Khan Academy collaboration called Pixar-in-a-Box (similar to the Chapter 2B example). Here, we will control the height of a ball over time using cubic curves which will either interpolate four points, or treat them as Bézier control points.
You will mostly work in the Curve
class (in curve.js
), but will also (optionally) modify the Animation
class (in animation.js
) in Part 5. The Animation
class maintains two Curve
objects: one for the downwards motion of the ball (curve 0), and one for the upwards motion of the ball (curve 1). Starting from the top at time = 0, the ball hits the ground at time = 0.5 and then comes back to the top at time = 1.
Your task in this lab consists of implementing some Curve
methods to interpolate, evaluate and render the curves.
Each curve in this lab is parametrized in the interval time
in the animation. In each part below, the conversion between time
and
where 0.5
in this lab since this is the time interval spanned by each curve.
You should initially see a total of 7 points: the three black points are the fixed points of the curves and the four pink points are modifiable. Click and drag any of the pink points to modify these points. There are some callbacks that are already implemented for you (in animation.js
), which modify the keyframe points referenced by the two curves.
Each Curve
stores the four points that define the curve (whether we interpolate the points or use them as Bézier control points). Within any method of the Curve
class, you can access these points using this.points[i]
where i
is the index of the desired point (this.points[i]
is a vec2
. Therefore this.points[i][0]
is the x-coordinate (which is the time) and this.points[i][1]
is the y-coordinate (which is the height) of the
vec2.lerp
.The vec2.lerp
function is useful for performing "Linear intERPolation" between two input points. Specifically, the vec2.lerp
function (see here) will calculate:
using:
let c = vec2.lerp(vec2.create(), a, b, t);
Try it out (in the Console of this webpage) using a = vec2.fromValues(0.2, 0.5)
, b = vec2.fromValues(0.75, 0.25)
with t = 0.8
. The result should be [0.64, 0.3]
. The vec2.lerp
function will be useful for Parts 3 and 4.
Curve
interpolate
function.Complete the interpolate
method in the Curve
class (in curve.js
) to interpolate the four points stored in this.points
. The method you implement here should be very similar to what we did in class. At the end of this method, this.coefficients
should be filled with the four coefficients (
The conversion from time
to t
is already done for you, and the height
is extracted from this.points[i][1]
.
Curve
evalInterpolant
function.Now complete the evalInterpolant
function (also in curve.js
) using this.coefficients
(computed in Part 1) to evaluate the height curve at a specific parameter value t
. Note that the input t
is in the range
Also notice that time
is already computed, which is the x-coordinate of the output vec2
.
How to know when this works? Moving the pink points should produce curves that pass through the four interpolated points of each curve. Also, the red tracer (and the ball height) should follow your interpolating curve when you click the Animate button.
Curve
drawBezier
function.Change the dropdown to Cubic Bézier and notice the curve rendering looks quite rough. This is because only the base case (depth == 0
) is implemented, which simply connects the controls points. If you increase the render depth, the curve will disappear because the recursive case is not implemented yet.
For the recursive case, we can evaluate the curve at HTML
input to control the recursion depth of the Bézier curve rendering).
Your task in this part is to complete the code in the Curve
drawBezier
function to render a Bézier curve recursively using the specified recursion depth.
Remember that de Casteljau's algorithm creates two new Bézier curves, the first one with controls points curve0
and curve1
), you should call their drawBezier
functions, decrementing the depth (i.e. curve0.drawBezier(depth - 1)
and curve1.drawBezier(depth - 1)
).
How to know when this works? The curve should look progressively smoother as you increase the depth in the Bézier render depth input.
Curve
evaluateBezier
function.Notice that the ball height does not follow the correct Bézier curve - see the red tracer which follows a straight line. This is because we are currently using linear interpolation (vec2.lerp
) between the curve endpoints to compute the height of the ball at a particular parameter t
within the Curve
evalBezier
function. This is not what we want.
Please complete the Curve
evaluateBezier
function. This function takes in a particular parameter value vec2
corresponding to the evaluated point on the curve. Use de Casteljau's algorithm and note that vec2.lerp
can be used to do a lot of the calculations here.
How to know when this works? When the dropdown is in Cubic Bézier mode, the red tracer (and ball height) should follow the Bezier curves (as in the animation above).
Search for the call to context.drawImage
in animation.js
. Notice that the width (w
) and height (h
) are both set to 50
, which define the size of the pixarball.png
image as it is pasted at the w
and h
by modifying this block of code in animation.js
in order to create a "squash-and-stretch" effect:
if (document.getElementById("input-squash-stretch").checked) {
// ...
}
If you want to investigate further with how things are drawn, look up the CanvasRenderingContext2D
documentation since everything in this lab is drawn with the "2d"
rendering context of the HTMLCanvas
. A lot of the other pieces in animation.js
(particularly, the transformations) will be covered later in the semester.
The initial submission for the lab is due on Thursday 2/27 at 11:59pm EST. Please see the Setup page for instructions on how to commit and push your work to your GitHub repository and then submit your repository to Gradescope (in the Lab 1 assignment). I will then provide feedback within 1 week so you can edit your submission.
Please note that Codespaces are generally deleted after a certain amount of time (I believe it's 30 days), so it's important to commit and push your work often.