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.