

        OTMPHONG.DOC - A new approximation technique for the Phong

                       shading model based on linear interpolation

                       of angles


        released 3-30-95

        by Voltaire/OTM [Zach Mortensen]


        email -

        mortens1@nersc.gov


        IRC -

        Volt in #otm, #coders



INTRODUCTION


                Realtime phong shading has always been a goal for 3d

        coders, however the massive amount of calculations involved

        has (until recently) hampered progress in this area.  When I

        first heard the term 'realtime phong shading' mentioned about 6

        months ago, I laughed to myself at what I perceived was an

        oxymoron.  In my experience at the time (derived from reading

        several 3d documents), phong shading required a tremendous

        amount of interpolation and one square root per pixel.  Even

        with lookup tables for the square root function, there was no

        way that this algorithm would be fast enough to use in

        realtime.  Early reports from other coders attempting realtime

        phong shading proved this, the fastest code I heard of could

        draw around 1500 triangles per second.


                Phong shading never really was a goal of mine.  I am a

        pretty lazy person, I could think of a thousand ways I would

        rather spend my time than implementing an inherently slow

        algorithm in my code and trying to optimize it.  Until about a

        week ago that is, when I received a little demo called CHEERIO

        by Phred/OTM.  Phred and I have been good friends for quite

        awhile, and we both write vector code.  We have helped each

        other improve the speed of our code dramatically by sharing our

        ideas, 2 heads are definitely better than 1!  Anyway, there

        were rumors flying around that CHEERIO was phong shaded, when

        in reality it was really nice gouraud shading.  I took a close

        look and...well, it looked like phong but Phred wasn't around

        to correct us, so I went on believing he had coded a phong fill

        that was as fast as my gouraud fill.  Part of the reason Phred

        and I have made our code so fast is competition, neither of us

        can stand being outdone by the other.  So whether I wanted to

        or not, I had to come up with a fast phong fill SOON if I were

        to save face.


                The fastest method I knew of was using a Taylor series

        to approximate color values.  This method involves a fairly

        fast inner loop with a lot of precalculation.  It also requires

        a thorough knowledge of calculus.  Believe me, doing Taylor

        series on your homework is a lot easier than trying to

        implement one in the real world for some strange reason.  So

        that is where I started, I was deriving the Taylor

        approximation for phong shading when I stumbled upon what

        seemed to me an obvious shortcut that would make phong filling

        nearly as fast as gouraud filling.  I also believe I am the

        first to come up with this method, since I have seen no

        articles about it, and I have yet to see realtime phong shading

        in a demo or game.


                OK, now on to the fun stuff...




THE PHONG ILLUMINATION MODEL



                This is not a text on phong illumination, but on phong

        SHADING.  They are two very different things.  Whether you use

        phong shading or not, you can use phong illumination with your

        lambert or gouraud shading to make your colors look more

        realistic.  I don't want to get into how this formula is

        derived, so I will just give you the low down dirty goods.



        color = specular + (cos x) * diffuse + (cos x)^n * specular



                Make sure you set up your palette in this way. In a

        nutshell, the ambient component defines the color of an object

        when no light is directly striking it, the diffuse component

        defines the color of the object, and the specular component

        defines the color of the highlight made when light strikes the

        object directly.  x should have a range of 0 to 90 degrees,

        since that is the range of angles possible when light

        intersects a visible plane.  The power n in the specular

        component defines certain attributes about the material, the

        greater the power n, the shinier the material will appear to be

        (i.e. the specular highlight will be smaller and brighter as n

        increases).




THE PHONG SHADING MODEL



                The idea behind phong shading is to find the exact

        color value of each pixel.  In its most common form, the phong

        shading model is as follows:


        1) determine a normal vector at each vertex of a polygon, the

           same normal vector used in gouraud shading.


        2) interpolate normal vectors along the edges of the polygon.


        3) interpolate normal vectors across each scanline, so you have

           one normal vector for each pixel in the polygon.


        3) determine the color at each pixel using the dot product of

           the normal vector at that pixel and the light vector, the

           same method used in gouraud and lambert shading.  Since the

           interpolated normals are not of constant length, this step

           requires a square root to find the length of the normal.



                This shading model produces impressive results.  A new

        color is calculated for each pixel, and the color gradient

        across a plane is non linear.


                However it is also VERY SLOW if implemented as it is

        shown here.  In order to linearly interpolate a vector, one

        must interpolate x, y, and z coordinates.  This task is not

        nearly as time consuming as the dot product, which requires 4

        multiplies, 2 adds, a divide and a square root per PIXEL.  A

        few optimizations can be performed that eliminate one multiply

        and replace the square root with a table lookup, but 3

        multiplies and a divide per pixel are far too slow to be used

        in realtime.



OPTIMIZING THE PHONG SHADING MODEL



                Lets mathematically break down the phong shading model.

        After all is said and done, you are left with the dot product

        of the pixel normal vector and the light vector divided by the

        product of the magnitudes of these two vectors.  Another way to

        express this value is (cos ), where  is the smallest angle

        between the two vectors.


        u = pixel normal vector

        v = light vector


        u dot v = cos  * |u| * |v|


                 u dot v

        cos  = ---------

                |u| * |v|


                So the dot product of a normal vector and a light vector

        divided by the product of the magnitudes of the two vectors is equal

        to the cosine of the smallest angle between the two vectors.  This

        should be nothing new, it is the same technique used to find color

        values in the lambert and gouraud shading techniques.  Lets attempt

        to graphically represent what is going on with phong, gouraud and

        lambert shading.



                                graph of y = cos  (*)

        |

        |

        |*    *

        |          *

        |             *

        |                *

        |                   *

        |                     *

        |                       *

        |                         *

      y |                          *

        |                           *

        |                            *

        |                             *

        |                              *

        |                               *

        |                                *

        |                                 *

        |                                  *

        |                                   *

        +------------------------------------------

                            


                The phong shading model states that the intensity of light

        at a given point is given by the dot product of the light and normal

        vectors divided by the product of the magnitudes of the two vectors.

        Flat shading is the roughest approximation of this, planes are

        rendered in a single color which is determined by the cosine of the

        angle between the plane's normal vector and the light vector.  If

        we graph the intensity of light striking flat shaded planes, we

        should find that they roughly form a cosine curve, since the color

        values at certain points are determined by the cosine of the angle

        between two vectors



                          graph of Intensity = cos  (*)

        |      flat shading approximations of light intensity shown as (X)

        |

        |*XXXX*XX               d  (angle between normal vectors)

        |          *       -------------

        |        XXXXX*XXXX            |

        |                *             | dI  (change in intensity)

        |                   *          |

        |                  XXX*XXXXXX  |

        |                       *

      I |                         *

        |                          *

        |                           *XXXXXX

        |                            *

        |                             *

        |                              *

        |                               *

        |                                *

        |                                 *XXXXX

        |                                  *

        |                                   *

        +------------------------------------------

                             


                This graph tells us something that we already know by

        practical experience, that flat shading is very inaccurate for large

        values of d, and much more accurate for small values of d.  This

        means that the shading appears smoother when the angle between

        normals (and therefore between planes) is very small.


                Now lets consider gouraud shading.  Gouraud shading is a

        linear interpolation of color between known intensities of light.

        The known intensities in gouraud shading are defined at each

        vertex, once again by use of the dot product.  In this case, the

        normal vector at each polygon vertex is the average of the normal

        vectors (the ones used in flat shading) for all planes which share

        that vertex.  Normals of planes which are greater than 90 and less

        than 270 degrees from the plane containing the vertex in question are

        not considered in the average because the two planes are facing

        away from each other.  If we plot interpolated intensities used in

        gouraud shading against the cosine curve, it is evident that gouraud

        shading is a much more accurate approximation than flat shading.



                        graph of Intensity = cos  (*)

        |        interpolated light intensities shown as (X)

        | ---------------------------------+

        |*X   *                            | in this region, the linear

        |  XXXX ---*--------+              | approximation is always going to

        |      XXX    *     | dI (error)   | be inaccurate without a very

        |         XXXX --*--+              | small value for d

        |             XXX   *              |

        |                XXXXX*  --------------+

        ||____________________|X*              |

      I |        d              X*            |

        |                         X*           | in this region, a gouraud

        |                          X*          | approximation is nearly

        |                           X*         | perfect because cos x is

        |                            X*        | nearly linear

        |                             X*       |

        |                              X*      |

        |                               X*     |

        |                                X*    |

        |                                 X*   |

        |                                  X*  |

        +------------------------------------------

                           


                This graph tells us that gouraud shading is very accurate

        as ->90.  However, if  is small and d is large, gouraud shading

        will look like an obvious linear approximation.  This can be avoided

        by using smaller values of d (i.e. use more polygons to fill in the

        gaps in the interpolation).  With enough polygons, gouraud shading

        can be 100% correct.


                Phong shading is the most correct method of shading because

        it is not an approximation, distinct colors are determined for each

        pixel.  These values follow the cosine curve exactly, because the

        intensity of each pixel was calculated using a dot product, which

        eventually yields the cosine of the angle between the plane at 

        that pixel and the light vector.  If we plot phong shading 

        intensities with the cosine curve, we find that the values 

        follow the function exactly.



                        graph of Intensity = cos  (*)

        |            phong light intensities shown as (X)

        |

        |X    X

        |          X

        |             X

        |                X

        |                   X

        |                     X

        |                       X

        |                         X

      I |                          X

        |                           X

        |                            X

        |                             X

        |                              X

        |                               X

        |                                X

        |                                 X

        |                                  X

        |                                   X

        +------------------------------------------

                             


                Once again, shadings calculated using the phong model follow

        the cosine curve, because the dot product between the normal vector

        at each pixel and the light vector can be simplified to a function

        involving cos .



TAYLOR APPROXIMATIONS


                Now that we know a function which gives the intensity of

        light at a given pixel, we need to find a fast way to evaluate that

        function.  Most people seem to know that Taylor series can be used

        for phong shading, but I have never met anyone that was able to

        tell me that the cosine function would be the function that is

        approximated.  The fact that vector coders are afraid of math is

        disturbing to me.


                The Taylor approximation for cos(x) is given by the following

        series:


                    x^2   x^4   x^6                      x^(2n)

        cos x = x - --- + --- - --- + ... + (-1)^(n-1) * ------

                     2!    4!    6!                       (2n)!


        Actually I think that is a Maclaurin series, which is nothing more

        than a Taylor series expanded about the point x = 0.  In any case,

        you can use any number of terms in a Taylor series to approximate

        a function.  The more terms you use, the more accurate your

        approximation will be...and the slower your approximation will be.

        The first two terms of the series for cos x are sufficient to give

        an accurate approximation from x = 0 to x = 90, which are the limits

        of  between the light and visible facets.


                This is about as far as I got with the Taylor approximation

        method for phong shading.  Once I got to this point, the proverbial

        light bulb clicked on inside my head, and I forgot all about Taylor

        series because I came up with a faster method.



LINEAR INTERPOLATION OF ANGLES


                To set the scene for you, I was riding the bus to school

        about at about 8:00 in the morning when I thought I would do a bit

        of work on the phong algorithm.  The bus ride is about 30 minutes and

        is usually devoid of any excitement, so I whipped out my trust pad

        of graph paper and started grinding out formulas.  I got really

        excited when I arrived at the Taylor approximation, but I just about

        jumped through the roof when this thought entered my mind.


                I realized that the Taylor approximation for phong shading

        basically interpolates values along the curve I = cos() just as

        gouraud shading linearly interpolates values, except the values for

        phong shading happen to fall directly ON the cosine curve.  The

        problem is that the cosine curve is not linear, therefore phong

        interpolation is much more complicated than gouraud interpolation.


                Then I stepped back and looked at the problem from another

        angle (punny).  If it were possible to interpolate some other value

        related to cos(), and if this other value changed in a linear

        fashion, it would be possible to create a lookup table that related

        cos() to this other value.  After a bit of deep thinking, I realized

        that I was staring right at such a value, !  The angle between the

        light vector and the normal vector at each vertex of a plane

        changes in a linear fashion as you go from one vertex to the next, and

        from one edge of the plane to the next across each scanline.


                As soon as it hit me, this idea made perfect sense.  The phong

        shading model calls for normal vectors to be linearly interpolated

        from vertex to vertex and from edge to edge.  When I thought about

        this a bit further, it seemed totally ridiculous.  The actual

        <x,y,z> coordinates of these normals do not matter one bit, only

        the angle between the vector defined by these coordinates and the

        light vector.  Why interpolate 3 coordinates per pixel when they are

        just an intermediate step in finding the angle between two vectors?


                So angular interpolation eliminates the interpolation of a

        whole vector.  But that's not all, it also eliminates the dot product

        which was previously needed to find the cosine of the angle between

        the normals and the light.  Without the dot product or vector

        interpolation,  there is nothing left of the traditional method of

        phong shading.  All that needs to be done is interpolate angles

        across the plane, and look up the cosine of those angles in a lookup

        table.  Once you know the cosine, the rest is easy.


                Using this method, an existing gouraud fill can be converted

        to a phong fill very very easily.  Instead of interpolating colors

        across the plane, interpolate angles instead.  If you are smart about

        the way you express your angles, they can be represented in a single

        byte.  Remember that the only possible values for the smallest angle

        between a normal vector and a light vector are 0 to 90 degrees.


                After you have interpolated an angle and looked up its

        cosine, all you need to do is plot a pixel of the correct color.

        The color calculations for each pixel are the same as those for

        lambert and gouraud shading.  Multiply the cosine by the number of

        colors in the gradated palette range and add the result to the base

        color of the range.


                Of course, you need to determine the angle between the light

        and the normal vectors at each vertex.  This can be accomplished by

        the inverse cosine function.  By taking the inverse cosine of the

        cosine, you get the angle as a result.  Try to remember your trig

        classes.



LIMITATIONS


                Angular interpolation is correct in 99% of all possible

        cases.  The only cases when it will not be correct is when the

        angles at any two or more vertices are equal.  Interpolated vector

        phong shading will display a specular highlight inside the plane in

        such a case, but interpolated angle phong shading will render the

        plane in a solid color because the difference between the angles at

        the vertices is 0, there will be no change in the angle across the

        plane.



CRITICISM AND RESPONSE SESSION


                The preliminary release of demos incorporating this technique

        were met with a bit of criticism, most of which was caused by

        ignorance.  Here are a few common criticisms of this technique and

        my responses.



        "You are interpolating something linearly, and linear interpolation

        is gouraud shading"


        Do your homework.  The phong model calls for linear interpolation of

        normal vectors, and it is obviously not gouraud shading.



        "It looks a lot like gouraud shading"


        Yes it does.  Refer to the section where I plotted intensities based

        on various shading techniques, and take a look at the graphs of

        Intensity vs. .  You will find that for a small d, gouraud shading

        looks very much like phong shading.  However, phong shading can

        achieve this result with a much larger d, which means less facets.



        "I see no specular highlight"


        The first version I released used a linear palette, not a palette

        based on the phong illumination model.  Without the phong

        illumination model, it is very hard to make specular highlights look

        correct.  The palette has now been corrected to conform to the phong

        illumination model.



        "You still can't get a highlight in the center of a single polygon"


        Well, I think that the speed of this method is a reasonable tradeoff.

        Specular highlights appear between polygons with this method, and

        the difference is not too noticeable.



        "The specular highlights are no different than gouraud specular

         highlights"


        Take a closer look.  With gouraud shading, specular highlights are

        gradated in a linear manner.  With phong shading, the gradation of

        colors is nonlinear because it follows the cosine curve.



CLOSING COMMENTS


                Angular interpolated phong shading is new as far as I know.

        If you decide to use this technique in any of your code, please give

        me appropriate credit.  I am not asking for a cut of your royalties,

        just to have my name mentioned somewhere.  I have always made it a

        point to give credit where credit is due, and I would appreciate if

        you would do the same.  Someone along the line actually has to put in

        some hard work to develop the algorithms that we all use.



GREETS


        Siri                    - you are the love of my life

        OTM                     - I...have...nothing...to...say

        Phred/OTM               - good vector conversation

        Rich Beerman            - our game will rule

        Darkshade               - for always being helpful

        THEFAKER/S!P            - infinite humility :)

        Sami Nopanen            - cacheman...

        Tran and Daredevil      - PMODE/W, gotta love it

        VLA                     - for not releasing any more 3d docs :)


        all my #coders buddies

        bri_acid

        MainFrame

        StarScream

        ae-

        fysx

        phoebus

        doom

        Moomin

        Simm

        LiveFire

        MArtist

        Zed-

        Omni

        ior

        Kodiak_

        Saeger

        anixter

        Hasty


        and everyone else I forgot...

