Generating Vertex Normals
Author: Max Wagner, mwagner@digipen.edu
Generating Vertex Normals Author: Max Wagner, mwagner@digipen.edu
12/9/2004 Page 1 of 6
Pre-Reqs
Familiarity with terms and concepts from Linear Algebra, including the ideas behind
vectors and vector spaces.
Notation
Vectors AND points in bold, i.e. u
uu
u or n
nn
n. I leave it to the reader to discern from the
context whether the object is a point or a vector. Scalars will be weighted normally, that
is un-bolded. Often I will refer to a vector u
uu
u, and then shortly afterward refer to its
components as u
x
, u
y
, u
z
, etc.
Vertex Normals vs. Surface Normals
We all know what a surface normal is (if not, it’s the normal to the plane that contains the
surface). So how can a vertex (i.e., a point), have a normal? Strictly speaking, it can’t.
What vertex normals provide is a means of simulating smoother surfaces during lighting
calculations when using procedures such as Phong or Gouraud shading (sometimes just
called Smooth shading). Imagine a polygonal mesh of a human: technically, this mesh is
just a bunch of flat polygons. But really, this mesh is simulating the smooth surface of a
human body. If all pixels within a polygon were lit identically, the “flatness” of each
polygon would be starkly obvious; but by using vertex normals, we can light each vertex
on a triangle differently, thus causing a smoother appearance. The trick is to generate
these vertex normals so that they actually enhance this smooth appearance.
The Intuition behind Vertex Normals
Let’s take a close look at the lighting process involved in traditional polygonal mesh,
scan-line rasterization techniques (such as those employed on graphics cards and in
software renderers for real-time applications). Lighting will be applied per-vertex, where
the dot product of the surface normal and the light’s direction will be used to modulate
the intensity of the light’s color (this aspect of the light model is called the Diffuse
lighting term). This modulated light color will then be added to a pre-computed, constant
vertex color. Other terms are also possible (specular, ambient) as well. Thus, if we are
using triangles, all three vertices of a triangle will have an identical dot product between
the light direction and surface normal vectors
1
. Using the same normal for all three
vertices assumes that the actual surface we are simulating is flat, but we know this is not
the case. It’s as though we are using a single sampling point to compute the normal for
all three vertices. But imagine we could actually sample the “true” surface at the vertices
1
Alternatively, if point light sources are being used, there will be a small amount of variation in the dot
product, as the light’s direction will be computed per vertex as the difference between the vertex’s position
and the light’s position. Nonetheless, given small triangles, the diffuse term will remain nearly identical for
all three vertices.
Generating Vertex Normals Author: Max Wagner, mwagner@digipen.edu
12/9/2004 Page 2 of 6
themselves; then we would surely get more variation amongst the vertex normals, in turn
creating a (smooth) variation in the diffuse lighting terms. But how can we sample the
“true” surface?
Unfortunately, we can’t. However, we can come close, using the observation that a
vertex lies at the intersection of multiple triangles. Hence, instead of using the surface
normal of the one triangle of which the vertex is a part, we can detect the adjacent
triangles (i.e., the other triangles that share the same vertex), and perform a kind of
“averaging” of all adjacent surface normals. This provides the intuition behind the notion
of a vertex normal, as there is no strict definition (there are multiple techniques for
computing vertex normals, and no one is “correct”).
The Algorithm
Now that we have an idea of what the vertex normal, let’s devise an algorithm to
compute them. After devising a standard algorithm, I will discuss a few variations that
can be incorporated for a nicer appearance.
The idea is that we want to average the normals of all polygons that are adjacent to a
given vertex. Recall that in standard rasterization techniques, we have access to a list of
triangles; this list will necessarily contain duplicate vertices, as a given vertex is included
for each triangle of which it is a part. This duplication is often alleviated using indexed
triangle lists, but to keep the argument simple, let us assume we are using an un-indexed
list, where the i
th
triangle in our vertex list is defined using the three vertices’ positions
v[i*3].p , v[i*3+1].p , and v[i*3+2].p. Then our task is to find, for each vertex, all the
triangles that share that vertex. Each time we find a triangle that shares the current
vertex, we compute the triangle’s surface normal, and add it into a running tally. When
we are done, we normalize the vertex normal, and store it with the vertex.
In pseudocode:
struct Vertex { Position p, Normal n }
VertexList v
for each vertex i in VertexList v
n ← Zero Vector
for each triangle j that shares i
th
vertex
n ← n + Normalize(Normal(v, j))
end for
v[i].n ← Normalize(n)
end for
The routine Normal(v, j) is assumed to return the outwardly facing normal to the
triangle using the index scheme described above.