Quiz 7: Sampling a Tartan Handkerchief

Currently you are hard at work on carefully implementing a rasterization algorithm that efficiently turns on all the pixels in a triangle. In this quiz, you will instead throw caution to the wind, and use the most brain-dead (and inefficient) algorithm for filling in a triangle: just take a bunch of random samples (x,y), keeping only those that fall inside the triangle! You will also use these sample points to texture your triangle with a lovely tartan pattern.

The starter code can be found here.

When you first load up the code, it should look like this (with some labels added):

Texture mapping diagram

The image on the left is the source texture, which you want to map into the triangle on the right. (Note that since the two triangles have different shapes, the texture should be somewhat distorted by this mapping!) Initially, of course, nothing is working properly. You will implement a few simple steps to get things going; these parts are clearly marked in the code. (The good news is that some of these steps will also be needed for A1. So hopefully testing them out in this simpler, interactive environment will help ease your final implementation!)

  1. The hardest part comes first. Given a point P and a triangle with vertices A,B,C (all given in 2D rectangular coordinates), write a routine to compute the three barycentric coordinates of P. You may use whatever method you like---we discussed several in class, including: computing the height of the point over each of the three edges; computing the relative areas of the three sub-triangles; and inverting a 2x2 linear system. We encourage you to use any and every source that will help you better understand barycentric coordinates---you do not have to limit yourself the the course slides! (However, your actual implementation should be your own! Just copying and pasting code is certainly cheating. :-))

  2. Once you've computed the barycentric coordinates, use them to test whether the current sample is inside the triangle. As long as you computed signed barycentric coordinates (i.e., you didn't take the absolute value at any point), this test should be pretty darn simple. Once this step is working, you should already see the samples clipped to the region inside the triangle (assuming the first part was also correctly implemented!).

  3. At this point you should have a nice triangle, but it won't be textured. Use your barycentric coordinates to compute the sample point Q in texture space corresponding to the current sample P in image space. Using the provided functions, this should basically be a one-liner (or maybe a few-liner depending on your personal coding style!).

  4. Finally, to see the fruits of your labor, increase the number of samples until you have a nicely-rendered triangle. Do you notice that it takes a lot of samples to draw the triangle this way? As crazy as this random sampling strategy may seem, we'll see later on (in our lectures on photorealistic rendering) that it is actually a good solution (sometimes the only solution!) when we want to render more complex phenomena.

Handing in

Please print out your code for rectangularToBarycentric() and drawTexturedTriangle(), as well as an image of the final result. An easy way to get a copy of the final image (without all the surrounding code) is to click the "Export" button in the lower-right, exporting as ZIP. If you open the index.html file in this ZIP, you will get a page with just the image on it that can be printed. Please remember to put your Andrew ID on your submission.

Some notes on coding

The code framework linked above is in JavaScript. For this quiz, you basically need to know nothing about JavaScript, other than the few basic functions we've provided for you. However, it is worth knowing how arrays are stored, since you'll use these to work with 2- and 3-component vectors. In particular, the code u = [x,y,z] is used to specify an array (or vector) u with components x, y, and z. These values can be passed around and returned from functions, as is done in many of the provided subroutines. You can also access the individual components with square brackets, e.g., y = u[2]. Otherwise, the syntax you'll need is much like any other language (e.g., a logical "and" is encoded by two ampersands &&, etc.).