Lab 06: Toon ShadingGoalsBy the end of this lab, you will:
|
The main goal for this lab is to practice with GLSL
. We will do so by implementing the Phong reflection model again, but this time, it will be in a shader (specifically, the fragment shader to assign the final pixel color). With a few modifications to this lighting model, we can also add silhouettes, toon-shading and a cool-to-warm shading effect. These are known as non-photorealistic rendering (NPR) techniques.
In terms of new concepts and code to write, this lab will be shorter than previous labs. However, it's our first lab with GLSL
and WebGL
so it can be hard to debug because we cannot "print/log" in a shader. Please read and try to interpret the cause of the error messages in the Console when your shader does not compile. When an error is reported on line X, try to pinpoint which line this is by starting at the first line of the fragmentShaderSource
string and moving to an offset of X lines.
(almost) All of the code you will write in this lab will be in the fragmentShaderSource
variable at the top of renderer.js
. Feel free to look at the other stuff, which will be covered in the next few weeks. I said "almost" because there is one small change we will make on the JavaScript
side with the WebGL
context used by the Renderer
.
Before proceeding, let's look at how the template is set up. The rightmost dropdown in the HTML
file selects the shading algorithm to use. Try changing this to "Phong". You should see the model in blue now. When the selected option in this dropdown changes, it changes a variable in our WebGL
program called u_shader
. Notice that when u_shader == 0
(the first option in the dropdown, i.e. "None"), then the fragment shader defined in fragmentShaderSource
sets the final color (gl_FragColor
) to red and returns. Otherwise, it sets gl_FragColor
to blue. We'll talk about the details of the u_shader
variable next week, but please note the relationship between u_shader
and the color we want to set from the following table:
u_shader |
color to use |
---|---|
$\hspace{30pt}$1 | Phong (Part 1 + Part 3) |
$\hspace{30pt}$2 | Toon (Part 3 + Part 4) |
$\hspace{30pt}$3 | Cool-Warm (Part 3 + Part 5) |
The fragment shader defined in fragmentShaderSource
currently sets a constant color to the fragment (pixel). Please implement the Phong reflection model in the fragment shader. Use a light that is positioned exactly at the eye (camera) location (please ask yourself: what are the coordinates of eye in the camera coordinate system?). Note that the coordinates of the surface point being processed in the fragment shader (relative to the camera coordinate system) is available in the variable point
. The surface normal is available in the variable normal
which has already been normalized. Remember to use a unit vector for the direction to the light gl_FragColor
(use a transparency of 1 to make the result opaque).
This part will look a bit strange at first because we need to fix a few things in Part 2 (left-most image below after rotating the model a bit).
WebGL
context.In the Renderer
draw
method, note that the gl
context is used to set some attributes. Every time we draw, we need to clear the existing buffer of color and depth values. Add the following line after the gl.clearColor
call:
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
This will clear the buffers used to store the color and depth of each pixel. When you rotate the model, you should no longer see a cascading effect. However, it still doesn't look quite right (middle image above). This is because we need to enable depth testing. Please see the following documentation and add the appropriate line to enable depth testing.
https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/enable
Your rendering should then look like the right-most image above. When this works, please take a screenshot of a model of your choice and add the image to your repl
, naming the file phong.png
(or .jpg
).
A silhouette is a black border where the model surface normal starts to point away from the observer. This can be added by checking the dot product between the surface normal normal
) and the vector point
) to the eye (gl_FragColor
to black and return
from the fragment shader. Use
Toon shading can be implemented by "banding" the result of the diffusion term in the Phong reflection model into discrete values. There are various ways to do this. Here we will band the color by resetting the diffusion term according to the following table:
value used | |
---|---|
0 - 0.25 | 0 |
0.25 - 0.5 | 0.25 |
0.5 - 0.75 | 0.5 |
0.75 - 1.0 | 0.75 |
The color returned for toon shading would then be the ambient + diffuse contributions (no need for specular reflection, but you can discretize that as well if you want). You should still use a silhouette for this effect. When this works, please take a screenshot of a model of your choice and add the image to your repl
, naming the file toon.png
(or .jpg
).
Note: there is a one-line way to implement this, but if
statements are okay.
Another artistic shading technique is to use a "cool-to-warm" shading model. The idea here is to, again, use the diffusion term to influence the final color. For this technique, please return (store in gl_FragColor
):
where normal
) and repl
, naming the file coolwarm.png
(or .jpg
).
The initial submission for the lab is due on Wednesday 11/01 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
and be sure to upload all three images described above. 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 this Google Form.
© Philip Claude Caplan, 2023 (Last updated: 2023-10-26)