Lab 04: Bird PhotographyGoalsBy the end of this lab, you will:
|
I went for a hike recently and saw a great blue heron flying close to a lake. I thought it would make for a fun lab :) But I couldn't find a free model of a heron online, so we're going to use a raven which I found here and read it into our lab scripts using this webgl-obj-loader
.
When you run the initial template, you should see a blue canvas, which is the color of the lake.
We're going to develop our own virtual camera in this lab, point it at the bird and take a picture. We'll also model the situation when the bird is rotating and we'll also add a reflection of the bird in the water.
Most of the implementation for this lab will be in the Camera
takePicture
function as well as the Triangle
constructor
. Of course, you may want to write additional functions to help in your implementation since some functionalities will be repeated, like calculating the color of the bird from our lighting model.
There are two objects in the scene: the bird
and the lake
. Each of these has a center
and a color
attribute. The details of the underlying classes for these two objects are implemented in utils.min.js
, which you do not need to inspect in this lab. Just note that both of these objects have an intersect
method which takes in a Ray
object and returns information about the closest intersection point in JSON format:
{
t: {Number} // ray parameter of intersection
p: {vec3} // surface point (which is equal to ray.origin + t * ray.direction)
n: {vec3} // surface normal (in world space) at intersection
km: {vec3} // material diffuse reflection coefficient
}
A lot of the setup will look similar to what we had in previous labs. In this lab, however, the dimensions of the image plane (width
and height
) are already calculated for you.
Please create rays and intersect them with the bird object, using the equations in the notes for pointing a camera at a specific target point. The target point is bird.center
and the camera is placed at this.eye
(of the Camera
object). Use an "up" direction of (0, 1, 0). You can either develop the change-of-basis vectors yourself, or use the glMatrix
targetTo
function (but be careful that it includes a translation).
As a first debugging step, please just check for an intersection with the bird
object using ixnB = bird.intersect(ray)
. If there is an intersection, set the color to ixnB.km
, which should look like the following image:
We will now add a light, which will be modeled as the distant sun, so we only have a direction - use a direction to the light of
If the camera ray does not intersect the bird, check for an intersection with the lake. ixnL = lake.intersect(ray)
. Then cast a reflection ray off of the lake and check if the reflected ray intersects the bird. If so, set the color of the pixel
This last part should be implemented entirely in the Triangle
constructor
. The bird model is represented with a soup of triangles called a mesh which is read from the raven.obj
file (OBJ files are a common format for representing 3d models). Each triangle is constructed from three vec3
's as we did in Lab 2, which are saved as a
, b
and c
in each Triangle
object. The constructor now takes a fourth parameter n
which is the outward normal vector to use for the triangle (saved in this.normal
). When an intersection occurs, this.normal
is returned as the normal to the surface at the intersection point.
The axis of the bird from tail to beak is aligned with the z-axis. Your job in this part is to rotate the bird about the z-axis with the bird center as the center of rotation. Please calculate the model matrix which performs the rotation and then modify the incoming a
, b
and c
points directly in the Triangle
constructor. Hint: think about translating, rotating and then translating back. Note that the bird center is printed in the console, which you will need to center the rotation. Here is what a rotation of
Yes, this means we are calculating the same transformation matrix for every triangle, but it's okay because it's just a preprocessing step to our rendering algorithm.
Remember to transform the incoming normal vector too! Please see the notes for a description of how to transform normal vectors.
This question can be answered at any point while working on the lab. Similar to Lab 2, please upload a picture of your response to your repl
.
In the notes we have the
Let's omit the
Please express this as a transformation of the pixel indices i
and j
in the following form:
where
There is an additional flag that you can pass to the Lake
constructor in index.html
. Find where the Lake
object is created and change the last parameter passed to the constructor to true
. This will take a bit longer to render (about 2x for me) because the km
value returned by the lake intersection will be looked up in the water.jpeg
image which takes a little extra time. More on techniques to do this in about month! You can also add shadows if you want, but this is also optional since we just practiced with that in Lab 3.
The initial submission for the lab is due on Wednesday 10/11 at 11:59pm EDT. I will then provide feedback within 1 week so you can edit your submission.
When you and your partner are ready, please submit the assignment on replit
. I will then make comments (directly on your repl
) and enter your current grade status at the top of the index.html
file.
Please also remember to submit your reflection for this week in the Google Form below (or click here to access the form).
© Philip Claude Caplan, 2023 (Last updated: 2023-10-04)