Fast Specular Highlights with Local Light Sources and Viewer
============================================================
Sebastien Loisel (zed@scylla.math.mcgill.ca)
This described a method for shading triangles in a phong-like way so that
we can get specular highlights within triangular faces. In Gouraud shading,
if the vertices are all dark, then the entire triangle will be dark, missing
any specular highlight that maybe ought to have been in the center of the
triangle.
Overview
========
In screen space, the (x,y,z) difference between the specular reflection vector
and the eye vector is linearly interpolated. The norm of this (x,y,z) value
itself is enough to let us compute some sort of specular highlight, we only
need to look up the value x*x+y*y+z*z in a table to get the actual intensity
of the lighting, per pixel. Since x, y and z vary linearly across a scanline,
x*x+y*y+z*z varies quadratically and forward differencing can be applied to
reduce the number of operations required to 2 adds per pixel plus some set
up operations.
Computing the (x,y,z) values in screen space
============================================
Let R be the unit vector which points in the direction in which the light
is reflected and E be the vector from the vertex under consideration to the
eye, normalized.
The specular highlight should be a function of the "difference" between R and
E. Traditionally, this difference was measured by the dot product. I suggest
that |R-E| may also be an adequate measure.
So R-E is evaluated at each vertex, which yields a "specularity vector" S
for each vertex. Note that, if R and E are each of unit norm, the triangle
inequality says that |R-E|<=2. Of course, knowing that || is always non-
negative, this gives tight bounds as to what values |S|, and therefore
|S|^2 can take. Since |S|^2 is easier to compute than |S| is, |S|^2 will be
used as an index into a specular color table.
If we want to have some sort of distance attenuation for the specular
highlight, we can make this specular color table bi-dimensional, one axis
for |S|^2 and another axis for distance to light.
Interpolating |S|^2 in screen space
===================================
We arbitrarily decide to linearly interpolate S across the screen between
the vertices for the triangle. This means that, for a given scanline, S
varies linearly and that
S(t)=(at+b,ct+d,et+f), a,b,c,d,e,f some scalars and t is the column number
(x coordinate) of the current pixel
and noting that P(t)=|S(t)|^2=S(t)*S(t), we can expand this and find that
P(t)=|S(t)|^2=(a^2+c^2+e^2)t^2 + (2ab+2cd+2ef)t + (b^2+d^2+f^2).
Now we wish to evaluate this incrementally and since this is a simple
quadratic, we can apply forward differencing:
P(t)=At^2+Bt+C with A=a^2+c^2+e^2, B=2ab+2cd+2ef, C=b^2+d^2+f^2
DP(t)=P(t+1)-P(t)=A(t^2+2t+1)+B(t+1)+C - (At^2+Bt+C)
=(2A-B)t+(A+B)
and
DDP(t)=DP(t+1)-DP(t)=2A-B
So that, given P(t0) and DP(t0), to evaluate P(t0+1) we add DP(t0) to it
and to evaluate DP(t0+1) we add 2A-B to it.
This value can now be used as a look up in the specular highlight table.
A few notes on the specular highlight lookup table
==================================================
If (and only if) |S|^2 > 2 then R and E point away from one another. Perhaps
the right thing to do in this case is to add no specular highlight at all.
For |S|^2<2, one could use a formula similar to the Phong illumination model
to compute the specular highlight table. For instance, one can use:
k*(1 - (|S|^2)/2)^p (*)
where k would be a "specular coefficient" and p would be a "specular power".
The higher the p, the sharper the specular highlight. The larger the k, the
more intense the specular highlight.
Noting the identity
|R-E|^2=(R-E)*(R-E)=R*R-2*R*E+E*E=|R|^2+|E|^2-2*R*E
|R-E|^2=2-2*R*E
R*E=1-(|R+E|^2)/2=1-(|S|^2)/2
this says that (*) is exactly the Phong specular illumination component,
k*(R*E)^p.
Distance Attenuation
====================
In addition, the Phong lighting model often makes use of a light attenuation
component, dividing by a factor of Ad^2+Bd+C where d is the distance between
light and point lit.
This value d can be evaluated at vertices and linearly interpolated across
the surface. Then, a 2d specular highlight is used instead of the 1d table
described above. The entries in the table would be given by something of the
form, eg,
k*(1 - (|S|^2)/2)^p
-------------------
A*d^2+B*d+C
This is exactly the Phong specular term with distance attenuation.
Note that linearly interpolating from the vertices does not generally yield
an exact value for d. (Eg, if we're measuring distance from (0,0) to line
segment (1,0)-(1,1), then the distance at the vertices is 1 and sqrt(2)
respectively, yielding a linearly interpolated value of (1+sqrt(2))/2 for the
midpoint while the actual distance is sqrt(1.25), not the same.)
Multiple Light Sources
======================
Several light sources can be thus rendered, either by having multiple S and d
values to interpolate per surface, or using a multipass algorithm and an
accumulation buffer.
Diffuse and Ambient components
==============================
Diffuse and ambient components should be obtained by another method and
accumulated with the specular value.