11.3 - Simulated Curved Surfaces¶
WebGL only renders points, lines and triangles, but it would be really nice if we could simulate smooth curved surfaces. A simple technique known as Phong shading interpolates the normal vectors of a triangle to give the appearance of a curved surface. This lesson describes Phong shading.
Surface Normal Vectors¶
A triangle defines a surface that lies in a plane. There are two
vectors that are perpendicular to the triangle’s plane. By convention, one of these
vectors defines the “front side” of the triangle, and the other vector defines
the “back side” of the triangle. These are referred to as the “front face” and
“back face” of the triangle. If the vector, n
, defines the
“front face”, then -n
defines the “back face”.
Given a specific triangle, it has exactly one “front face” normal vector. Using the same normal vector for the diffuse color calculations of all triangle fragments will produce the same diffuse color for the entire surface. This is called “flat shading”. The rendering of the bunny to the right is an example of “flat shading”.
To simulate a curved surface, instead of storing a normal vector for each triangle, each vertex of a triangle stores a vector that is perpendicular to the original curved surface of the real world object being modeled. The diagram to the right illustrates the three vectors of a triangle. These vectors are interpolated across the surface of the triangle and used in the lighting calculations. Therefore, each fragment of a triangle is potentially assigned a different color, which simulates a curved surface.
The term “normal vector” might be confusing because a vector’s direction may not be perpendicular to its associated triangle’s plane. However, it is perpendicular to the original object’s surface at the location of the vertex. Therefore, a “normal vector” is defined as a vector that produces the desired lighting calculations for a location on a surface, regardless of whether it is perpendicular to its associated triangle.
Interpolation was explained in chapter 8 and can easily be
performed using a simple parametric equations Given two normal vectors,
n1
and n2*
, intermediate vectors, n
, can be calculated
by varying a parametric parameter, t
, between 0.0 and 1.0:
n = (1-t)*n1 + t*n2 // 0.0 <= t <= 1.0
Since vectors have 3 components, <dx,dy,dz>
, this equation actually represents
three equations:
- ndx = (1-t)*n1dx + t*n2dx
- ndy = (1-t)*n1dy + t*n2dy
- ndz = (1-t)*n1dz + t*n2dz
You don’t have to implement these equations; the WebGL graphics pipeline
automatically interpolates
vectors that are stored in varying
variables. But it
is important that you understand how the interpolation works because
the intermediate vectors will typically not have the same length as the
original two vectors. If an interpolated vector need to be unit length
then it must be normalized for each fragment calculation.
Calculating Smooth Normal Vectors¶
Smooth shading across adjacent triangles of a model is accomplished by setting the normal vector of a vertex to an average of the triangle normal vectors that use that vertex. For example, in the diagram to the right a vertex is used by five triangles, so the vertex’s normal vector is set to an average of the five triangle normal vectors. The average normal vector is calculated by adding the vectors and dividing by the number of vectors. This averaged vector may not be exactly perpendicular to the original object’s surface at the vertex’s location, but it is typically close enough. (Note: Even if the original five vectors were normalized, the averaged vector probably does not have unit length and needs to be normalized.)
Calculating smooth normal vectors becomes more complex if a model contains triangles that share a vertex and lie in the same plane. Consider a simple cube like the one shown in wireframe mode to the right. It is composed of 6 sides that are defined by 12 triangles (two triangles per side). In the diagram you can see that the vertex at the red dot is part of 4 triangles, but just 3 cube faces. If you take the average of the normal vectors of the 4 triangles that share the vertex, the normal vector will be skewed towards the right side that has 2 triangles that use the vertex. Therefore, when you gather the face normal vectors to calculate an average, you must test the face normal vectors to make sure they are unique. If you find multiple normal vectors that are identical, then you assume that they all define the same surface plane and you only include one of them in your average calculation.
To create an accurate rendering of some models, flat shading must be used on some triangles while smooth shading must be used on other triangles. Consider a simple cube with round edges. If smooth normal vectors are used for every vertex in the model, the flat sides of the cube will have a curved appearance. If triangle normal vectors are used for every vertex, the rounded corners will not appear rounded, but rather faceted. The diagram to the right illustrates this problem. Notice that for vertex 1, a triangle normal vector should be used for rendering the triangle to its right to create a flat cube face, while a smooth normal vector should be used for rendering the triangle on its left to create a rounded surface for the cube’s edge.
.OBJ
Data Files¶
The JavaScript class CreateModelsFromOBJ
in the file
obj_to_arrays.js
calculates a “smooth normal vector”
for each vertex of a model when “smooth shading” is enabled and a “triangle
normal vector” when “smooth shading” is disabled. In an .obj
data file,
a line containing s on
or
s 1
enables smooth shading, while a line containing s off
or
s 0
disables smooth shading. For example, in the obj
data below,
the four triangles represented
by lines 2-3 will be associated with “smooth normal vectors” while the three
triangles represented by lines 5-7 will be associated with “triangle normal vectors”.
(Please note that CreateModelsFromOBJ
functions calculate normal vectors
only if there are no normal vectors in the data file. If the data file contains
normal vectors then those are used and enabling or disabling smooth shading
has no effect.)
1 2 3 4 5 6 7 8 | s on
f 9//1 8//1 23//1 24//1
f 2//2 1//2 16//2 17//2
s off
f 6//1 3//1 2//1
f 5//1 3//1 6//1
f 5//1 4//1 3//1
...
|
An Example WebGL Program¶
The following WebGL program allows you to render a 3 different versions of a cube that has rounded edges. One version uses all triangle normal vectors and produces a “faceted” rendering. One version uses all smooth normal vectors which produces a slight curved appearance for the flat sides. The last version uses a combination of triangle and smooth normal vectors.
Investigate Normal Vectors
light position(3.0, 0.0, 5.0) | light color (1.00, 1.00, 1.00) | |
X: -5.0 +5.0 | Red: | 0.0 1.0 |
Y: -5.0 +5.0 | Green: | 0.0 1.0 |
Z: -5.0 +5.0 | Blue: | 0.0 1.0 |
ambient intensities (0.30, 0.30, 0.30) |
|
Red: | 0.0 1.0 |
Green: | 0.0 1.0 |
Blue: | 0.0 1.0 |
Change all intensities at once. |
All faces use triangle normal vectors (flat shading) All faces use smooth normal vectors (smooth shading) Cube sides use triangle normal vectors while the "edge triangles" use smooth normal vectors Display the normal vectors.
|
Open this webgl demo program in a new tab or window
Please note the following about the above WebGL program:
- The smooth shaded triangles facing the camera look great, but you can see their triangle mesh nature when the triangles are in silhouette with the camera.
- When smooth normal vectors are used for all model faces there is no visual “seam” between the sides of the cube and the rounded edges. However, the sides of the cubes have a slight curved appearance to them.
- When the cube’s sides are rendered using “triangle normals” there is a visible “seam” between the cube sides and the rounded edge. This is because the cube side is using a different normal vector than the rounded edge. To remove the visible “seam” the triangles that have a common edge between the cube side and the rounded edge need the vertices on the common edge to use flat shading normal vectors but the other vertices should use a smooth normal vector.
Glossary¶
- Phong shading
- Create a unique normal vector for each fragment that composes a triangle by interpolating the normal vectors defined at the triangle’s vertices.
- triangle normal vector
- A vector that is perpendicular to the triangle’s plane.
- smooth normal vector
- A vector that is perpendicular to the surface of an original, real-world object at a specific location.
Self Assessment¶
- two
- Correct. These corresponds to the two sides of a triangle (or the two sides of a plane).
- one
- Incorrect.
- three
- Incorrect.
- infinite
- Incorrect.
Q-370: Given a triangle, a vector that is 90 degrees to every point in the plane defined by the triangle is called a normal vector. How many normal vectors does a triangle have?
- the diffuse lighting calculation uses the same normal vector for every fragment.
- Correct.
- diffuse lighting is not calculated for “flat shading”.
- Incorrect. Diffuse lighting calculations are required for “flat shading.”
- the color of the diffuse light is constant.
- Incorrect.
- every pixel of a triangle is assigned the color of the triangle.
- Incorrect.
Q-371: “Flat shading” calculates the same diffuse color for every pixel that composes a triangle because …
- taking the average of the face normal vectors of every triangle that uses the vertex.
- Correct.
- using the normal vector of the largest triangle that uses the vertex.
- Incorrect.
- summing all of the normal vectors around it.
- Incorrect. It sums the normal vectors and divides by how many were added together.
- multiplying adjacent normal vectors.
- Incorrect.
Q-372: The “normal vector” assigned to a vertex to implement “smooth shading” is typically calculated by …
- A line before “face” descriptions that contains “s on”.
- Correct.
- A “face” description contains the word “smooth” as its last token.
- Incorrect.
- Smooth shaded triangles can’t be represented in an
.obj
file. - Incorrect.
- By default, all faces from an
.obj
file are “smooth shaded”. - Incorrect. The default is to use “flat shading” on triangle faces.
Q-373: How are triangles in an .obj
file “marked” for smooth shading?