Jason McKesson  committed 1199189

Tut10 text finished.

  • Participants
  • Parent commits df2bd32
  • Branches default

Comments (0)

Files changed (7)

File Documents/Illumination/Tutorial 08.xml

+            <title>Further Research</title>
+            <para>Lambertian diffuse reflectance is a rather good model for diffuse reflectance for
+                many surfaces. Particularly rough surfaces however do not behave in a Lambertian
+                manor. If you are interested in modelling such surfaces, investigate the Oren-Nayar
+                reflectance model.</para>
+        </section>
+        <section>
             <title>GLSL Functions of Note</title>
                 <glossterm>lighting model</glossterm>
-                    <para>A mathematical model that defines light/surface interactions. This can
-                        attempt to model reality, but it does not have to.</para>
+                    <para>A mathematical model that defines how light is absorbed and reflected from
+                        a surface. This can attempt to model reality, but it does not have
+                        to.</para>

File Documents/Illumination/Tutorial 09.xml

         <para>The <phrase role="propername">Fragment Point Lighting</phrase> tutorial shows off how
             fragment lighting works.</para>
+        <!--TODO: Show a picture of the tutorial.-->
+        <para>Much better.</para>
         <para>This tutorial is controlled as before, with a few exceptions. Pressing the
                 <keycap>t</keycap> key will toggle a scale factor onto to be applied to the
             cylinder, and pressing the <keycap>h</keycap> key will toggle between per-fragment
             lighting and per-vertex lighting.</para>
-        <!--TODO: Show a picture of the tutorial.-->
-        <para>Much better.</para>
         <para>The rendering code has changed somewhat, considering the use of model space for
             lighting instead of camera space. The start of the rendering looks as follows:</para>

File Documents/Illumination/Tutorial 10.xml

     xmlns:xlink="" version="5.0">
     <?dbhtml filename="Tutorial 09.html" ?>
-    <para>Thus far, our lighting models </para>
+    <para>The diffuse lighting model works reasonably well for a smooth, matte surface. Few objects
+        in reality conform to this archetype. Therefore, in order to more accurately model real
+        objects, we need to improve upon this. Let us focus on making objects appear shiny.</para>
+    <para>Shiny materials tend to reflect light more strongly in the opposite direction from the
+        angle of incidence (the angle between the surface normal and the incoming light direction).
+        This kind of reflection is called a <glossterm>specular reflection.</glossterm> A perfect
+        specular reflector would be a mirror.</para>
+    <para>One way to show that an object is shiny is to model <glossterm>specular
+            highlights.</glossterm> A specular highlight is a bright highlight on an object caused
+        by direct illumination from a light source. The position of the highlight changes with the
+        view direction as well as the light direction.</para>
+    <para>Modelling true specular reflection would require reflecting all light from objects in the
+        scene, whether direct or indirect. However for many objects, like shiny plastics and the
+        like, indirect specular reflections are very weak. Thus, by modeling direct specular
+        reflections, we can make an object appear shiny without having to do too much work.</para>
+    <para>We will look at several models for specular highlights and reflection. The Lambertian
+        diffuse reflectance model was reasonably good for modelling diffuse lighting, but there are
+        several models for specular reflection that should be considered. They vary in quality and
+        performance.</para>
+    <para>Note that these models do not throw away diffuse lighting. They all act as supplements,
+        adding their contribution into the overall result for the lighting equation.</para>
+    <section>
+        <title>Microfacets</title>
+        <para>All of these specular reflection models work based on an assumption about the
+            characteristics of the surface. If a surface was perfectly smooth, then the specular
+            highlight from a point light would be infinitely small (since point lights themselves
+            are infinitely small).</para>
+        <!--TODO: Show a perfectly smooth surface with reflection from a light source. Have several camera positions.
+Position A should be in view of the reflection at the point P, while position B should not.-->
+        <para>Notice that the intensity of the reflected light depends not only on the angle of
+            incidence, but only the direction to the viewer. This is called the <glossterm>angle of
+                view</glossterm> or <glossterm>viewing angle</glossterm>. Viewing position A detects
+            the light specularly reflected from the surface, but the viewing position B does
+            not.</para>
+        <para>Surfaces however are rarely perfectly smooth. Surfaces that seem smooth from far away
+            can be rough on closer examination. This is true at the microscopic level as well, even
+            for surfaces that look quite smooth. This roughness can be modelled by assuming that a
+            surface is composed of a number of <glossterm>microfacets.</glossterm></para>
+        <para>A microfacet is a flat plane that is oriented in a single direction. Each microfacet
+            reflects light perfectly in that direction. A surface with microfacets would look like
+            this:</para>
+        <!--TODO: show two 2D surface with microfacets, one relatively rough and one smooth.-->
+        <para>It is part of the microfacet model's assumption that many microfacets on a surface
+            will contribute to the light returned under a single pixel of the final image. So each
+            pixel in the rendered image is the result of an aggregate of the microfacets.</para>
+        <para>The average normal of the microfacets is the surface normal at that point. The
+            relative smoothness of a surface can be modeled as a statistical distribution of the
+            orientation of microfacets on the surface. A smooth surface has a distribution close to
+            the average, while a rough surface has a broader distribution.</para>
+        <para>Thus, a model of specular reflections includes a term that defines the overall
+            smoothness of the source. This is a surface characteristic, representing the
+            distribution of microfacets using whatever statistical distribution the particular
+            specular model is using. One of the main differences between specular models is the kind
+            of statistical distribution that they use.</para>
+        <para>Specular highlights are formed because, even though the surface normal may not be
+            oriented to directly reflect light from the light source to the viewer, some microfacets
+            may still be oriented to reflect a portion of that light. A microfacet distribution
+            model determines the proportion of microfacets that happen to be oriented to reflect
+            light towards the viewer.</para>
+        <para>Smooth surfaces, those who's microfacets do not deviate much from the surface normal,
+            will have a small, bright highlight. Rough surfaces, who's microfacets are oriented in
+            wildly divergent directions, will have a much dimmer, but larger specular highlight.
+            These highlights will have positions and shapes based on the angle of incidence and the
+            angle of view.</para>
+        <para>Note that specular reflectance models do not become diffuse reflectance models when
+            taken to the extreme case of maximum roughness. Specular reflection represents a
+            different mode of light/surface interaction from diffuse reflection.</para>
+    </section>
+    <section>
+        <title>Phong Model</title>
+        <para>The simplest model of specular illumination is the <glossterm>Phong model</glossterm>.
+            The distribution of microfacets is not determined by a real statistical distribution.
+            Instead it is determined by... making things up.</para>
+        <sidebar>
+            <title>On Phong and Nomenclature</title>
+            <para>The term <glossterm>Phong shading</glossterm> was once commonly used to refer to
+                what we now know as per-fragment (or per-pixel) lighting. That is, evaluating the
+                lighting equation at every fragment over a surface. This term should not be confused
+                with the Phong specular lighting model. Because of this, the term <quote>Phong
+                    shading</quote> has fallen out of common usage.</para>
+        </sidebar>
+        <para>The Phong model is not really based on anything real. It doesn't deal in microfacet
+            distributions at all. What the Phong model is is something that looks decent enough and
+            is cheap to compute. It approximates a statistical distribution of microfacets, but it
+            is not really based on anything real.</para>
+        <para>The Phong model states that the light reflected in the direction of the viewer varies
+            based on the angle between difference between the view direction and the direction of
+            perfect reflection. Mathematically, the Phong model looks like this:</para>
+        <!--TODO: Show the phong equation. Phong term = cos(V, R) ^ s-->
+        <para>The brightness of the specular highlight for a particular viewing direction is based
+            on raising the cosine of the angle between the view direction and the reflection
+            direction to a power. As previously stated, this model is not based on anything real. It
+            simply creates a bright somewhat-circular area on the surface. This area gets dimmer as
+            the viewer is farther from the direction of perfect reflection.</para>
+        <para>The <varname>s</varname> term in the equation represents the roughness of the surface.
+            A smooth surface, which should have a smaller highlight, has a large
+                <varname>s</varname>. Since the cosine of the angle is a number on [0, 1], taking it
+            to a power greater than 1.0 will make the number smaller. Therefore, a large
+                <varname>s</varname> exponent will make for a small highlight.</para>
+        <para>The specular exponent can range from (0, ∞). A small exponent makes for a rougher
+            appearance, while a large exponent suggests a shiny surface.</para>
+        <section>
+            <title>Specular Absorption</title>
+            <para>The Phong term computed above is then multiplied with the light intensity. This
+                represents the maximum light reflected along the view direction.</para>
+            <para>However, just as with diffuse lighting, surfaces can absorb some quantity of the
+                light that would be specularly reflected. We could use the diffuse color here,
+                multiplying it by the specular term. But this would not be physically correct for
+                many kinds of objects.</para>
+            <para>Many surfaces, particularly certain man-made pigments and plastics, have multiple
+                layers to them. The top layer will specularly reflect some portion of the light.
+                However, it will also let some portion of that light reach lower layers. These
+                layers have stronger diffuse reflectance. So the specular absorption on the surface
+                has different characteristics than the diffuse absorption in the lower layers.
+                Usually, the specular layer reflects equally on all wavelenths, so the specular
+                highlight tends to be the color of the light itself.</para>
+            <para>Notably, metals do not do this. Their diffuse absorption tends to be the same as
+                their specular absorption. So while blue plastic under white light has a white
+                specular highlight, gold metal under white light has a gold highlight.</para>
+        </section>
+        <section>
+            <title>Drawing Phong</title>
+            <para>The <phrase role="propername">Phong Lighting</phrase> tutorial demonstrates the
+                Phong specular model.</para>
+            <!--TODO: Show a picture of the tutorial.-->
+            <para>The tutorial is controlled similarly to previous lighting tutorials. The
+                    <keycap>W</keycap>, <keycap>A</keycap>, <keycap>S</keycap>, and
+                    <keycap>D</keycap> keys control the orientation of the cylinder. Pressing the
+                    <keycap>T</keycap> key will swap between the scaled and unscaled cylinder. The
+                    <keycap>Y</keycap> key toggles the drawing of the light source. The
+                    <keycap>B</keycap> key will toggle the light's rotation on/off. Pressing the
+                    <keycap>Space Bar</keycap> toggles between drawing the uncolored cylinder and
+                the colored one.</para>
+            <para>The light's position is mostly controlled as before, with the
+                    <keycap>I</keycap>,<keycap>J</keycap>, <keycap>K</keycap>, and
+                    <keycap>L</keycap> keys. The specular value is controlled by the
+                    <keycap>U</keycap> and <keycap>O</keycap> keys. They raise and low the specular
+                exponent. Using <keycap>Shift</keycap> in combination with them will raise/lower the
+                exponent by smaller amounts.</para>
+            <para>The <keycap>G</keycap> key toggles between a diffuse color of (1, 1, 1) and a
+                darker diffuse color of (0.2, 0.2, 0.2). This is useful for seeing what the specular
+                would look like on a darker surface color.</para>
+            <para>The <keycap>H</keycap> key selects between specular and diffuse, just specular and
+                just diffuse. The ambient term is always used. Pressing <keycombo>
+                    <keycap>Shift</keycap>
+                    <keycap>H</keycap>
+                </keycombo> will toggle between diffuse only and diffuse+specular.</para>
+            <para>The rendering code is nothing you have not seen in earlier tutorials. It loads 6
+                programs, and uses the various controls to select which to use to render.</para>
+            <para>There are two vertex shaders in use. One that takes the position and normal
+                attributes, and one that takes them plus a per-vertex color. Both of them output the
+                camera-space vertex normal (computed with a normal matrix), the camera-space vertex
+                position, and the diffuse color. In the case of the shader that does not take a
+                per-vertex color, the diffuse color output is taken from a uniform set by the
+                code.</para>
+            <para>The fragment shaders are more interesting. They do lighting in camera space, so
+                there is no need for the reverse-transform trick we used previously. The shaders
+                also use light attenuation, but it only varies with the inverse of the distance,
+                rather than the inverse squared.</para>
+            <para>The main portion of the specular+diffuse fragment shader is as follows:</para>
+            <example>
+                <title>Phong Lighting Shader</title>
+                <programlisting language="glsl">vec3 lightDir = vec3(0.0);
+float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+vec4 attenIntensity = atten * lightIntensity;
+vec3 surfaceNormal = normalize(vertexNormal);
+float cosAngIncidence = dot(surfaceNormal, lightDir);
+cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+vec3 viewDirection = normalize(-cameraSpacePosition);
+vec3 reflectDir = reflect(-lightDir, surfaceNormal);
+float phongTerm = dot(viewDirection, reflectDir);
+phongTerm = clamp(phongTerm, 0, 1);
+phongTerm = cosAngIncidence != 0.0 ? phongTerm : 0.0;
+phongTerm = pow(phongTerm, shininessFactor);
+outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+    (specularColor * attenIntensity * phongTerm) +
+    (diffuseColor * ambientIntensity);</programlisting>
+            </example>
+            <para>The initial section of code should be familiar. The Phong specular computations
+                start with computing the direction to the camera. Since we are working in camera
+                space, we know that the camera is at the origin (0, 0, 0). The direction from point
+                A to point B is the normalization of B - A. Since the destination point is at the
+                origin, that becomes simply -A, normalized.</para>
+            <para>The next line computes the direction of perfect reflection, given the light
+                direction and the surface normal. The function here, <function>reflect</function>,
+                is a standard GLSL function used for precisely this purpose. Notice that the
+                function in question requires the that the light direction is the direction
+                    <emphasis>from</emphasis> the light. Our light direction is the direction to the
+                light. This is why it is negated.</para>
+            <para>Using the function is useful, but it is important to know how to compute the
+                reflection direction on your own. Here is the formula:</para>
+            <!--TODO: equation of the reflection direction computation.-->
+            <para>Again, this equation assumes that L is the direction <emphasis>from</emphasis> the
+                light.</para>
+            <para>From here, the Phong term is computed by taking the dot product of the reflection
+                direction and the view direction, clamping it to 0, 1. The next line, where we use
+                the angle of incidence, is very important. What this line does is prevent us from
+                having a specular term when the surface normal is oriented away from the light. If
+                this line were not here, it would be possible to have specular highlights appear to
+                shine <emphasis>through</emphasis> a surface. Which is not particularly
+                realistic.</para>
+            <para>The GLSL standard function <function>pow</function> is next used to raise the
+                Phong term to the power. This function seems generally useful, but it has a large
+                number of limitations. The <function>pow</function> function computes <inlineequation>
+                    <mathphrase>X<superscript>Y</superscript></mathphrase>
+                </inlineequation>, where X is the first parameter and Y is the second.</para>
+            <para>This function only works for values of X that are greater than or equal to 0; it
+                returns undefined values (ie: anything) otherwise. Clamping the Phong term ensures
+                this. Also, if X is exactly 0.0, then Y must be strictly greater than zero;
+                undefined values are returned otherwise. These limitations exist to make computing
+                the power function much faster.</para>
+            <para>And for Phong specular computations, the limitations almost never come into play.
+                The cosine of the angle is clamped, and the specular exponent is not allowed to be
+                zero.</para>
+            <para>Notice that the specular term is added into the diffuse and ambient terms. This
+                has meaning for the intensity issue we have seen before. If the diffuse and specular
+                colors are too large, and the light attenuation is quite small, then the resulting
+                values from the lighting equations can be larger than 1.0 in magnitude. Since OpenGL
+                automatically clamps the colors to 1.0, this can cause unpleasant effects, where
+                there appears to be a very bright, white area on a surface.</para>
+        </section>
+        <section>
+            <title>Visual Specular</title>
+            <para>Having even a weak specular term can make a significant, if subtle, difference. In
+                our case, the specular color of the material is a fairly weak (0.25, 0.25, 0.25).
+                But even with a rough specular highlight, the surface looks more physically
+                reasonable.</para>
+            <para>In particular, it is interesting to note what happens when you use a very dark
+                diffuse color. You can activate this by pressing the <keycap>G</keycap> key.</para>
+            <!--TODO: Show dark diffuse color.-->
+            <para>If there was no specular term at all, you would a virtually scene. The specular
+                highlight, even with the fairly weak specular reflection of 0.25, is strong enough
+                to give some definition to the object when seen from various angles. This more
+                accurately shows what a black plastic object might look like.</para>
+            <para>One thing you may notice is that, if you bring the light close to the surface, the
+                specular area tends to have very sharp edges.</para>
+            <!--TODO: Show a picture of the clipping.-->
+            <para>This is part of the nature of specular reflections. If the light is almost
+                perpendicular to the surface, the specular reflection will shine brightest when the
+                light is almost eclipsed by the surface. This creates a strong discontinuity at the
+                point where the light is no longer in view.</para>
+            <para>You generally see this most with rough surfaces (small exponents). With smoother
+                surfaces, this is rarely seen. But this is not the only visual oddity with Phong and
+                having small exponents.</para>
+            <para>If you drop the exponent down to the minimum value the code will allow, you will
+                see something like this:</para>
+            <!--TODO: show a picture of the Phong distortion.-->
+            <para>This ring area shows one of the main limitations of the Phong model. When trying
+                to depict a surface that is rough but still has specular highlights, the Phong model
+                starts to break down. It will not allow any specular contribution from areas outside
+                of a certain region.</para>
+            <para>This region comes from the angle between the reflection direction and the view
+                direction. This area is the region where the reflection direction and view direction
+                are more than 90 degrees apart.</para>
+            <para>Under the microfacet model, there is still some chance that some microfacets are
+                oriented towards the camera, even if reflection direction is pointed sharply away.
+                Thus, there should be at least some specular contribution from those areas. The
+                Phong model cannot allow this, due to how it is computed.</para>
+            <para>What all this tells us is that Phong works best with larger exponents. Small
+                exponents show its problems and limitations.</para>
+        </section>
+    </section>
+    <section>
+        <title>Blinn-Phong Model</title>
+        <para>The problem with Phong, with regard to the reflection and view directions being
+            greater than 90 degrees, can be solved by changing the computation. This modified model
+            is called the <glossterm>Blinn-Phong specular model</glossterm> or just the
+                <glossterm>Blinn specular model.</glossterm></para>
+        <para>It is no more physically correct than the Phong model. But it does tend to account for
+            more than Phong.</para>
+        <para>The main problem with Phong is that the angle between the view direction and the
+            reflection direction has to be less than 90 degrees in order for the specular term to be
+            non-zero. So cases like this:</para>
+        <!--TODO: Show the Phong problem in 2D-->
+        <para>These are not modeled correctly. These could have microfacets that are oriented
+            towards the camera, but Phong cannot properly render this. The problem is that the dot
+            product between the view direction and reflection direction can be negative, which does
+            not lead to a reasonable result when passed through the rest of the equation.</para>
+        <para>The Blinn model uses a different set of vectors for its computations, one that are
+            less than 90 degrees in all valid cases. The Blinn model requires computing the
+                <glossterm>half-angle vector</glossterm>. The half-angle vector is the direction
+            halfway between the view direction and the light position.</para>
+        <!--TODO: Show a 2D representation of the half-angle vector.-->
+        <!--TODO: Equation for the half-angle vector.-->
+        <para>When the view direction is perfectly aligned with the reflected direction, the
+            half-angle vector is perfectly aligned with the surface normal. To describe the
+            half-angle vector another way, it is the direction the surface normal would need to be
+            oriented in in order for the viewer to see a specular reflection from the light
+            source.</para>
+        <!--TODO: Show the halfangle vector for a view direction equal to the reflection direction.-->
+        <para>So instead of comparing the reflection vector to the view direction, the Blinn model
+            compares the half-angle vector to the surface normal. It then raises this value to a
+            power representing the shininess of the surface.</para>
+        <!--TODO: Equation of the Blinn term: cos(H, N) ^ s-->
+        <para>The angle between the half-angle vector and the normal is always less than 90 degrees.
+            So the Blinn specular model produces similar results to the Phong model, but without
+            some of Phong's problems. This is demonstrated in the <phrase role="propername">Blinn vs
+                Phong Lighting</phrase> tutorial.</para>
+        <!--TODO: Show an image of Blinn from the tutorial.-->
+        <para>The controls are similar to the last tutorial. Pressing the <keycap>H</keycap> key
+            will switch between Blinn and Phong specular. Pressing <keycombo>
+                <keycap>Shift</keycap>
+                <keycap>H</keycap>
+            </keycombo> will switch between diffuse+specular and specular only. Because the specular
+            exponents have different meanings between the two lighting models, each model has a
+            separate exponent. The keys for changing the exponent values will only change the value
+            for the lighting model currently being viewed.</para>
+        <para>The real work here is, as before, in the shader computations. Here is the main code
+            for computing the diffuse + Blinn illumination.</para>
+        <example>
+            <title>Blinn-Phong Lighting Shader</title>
+            <programlisting language="glsl">vec3 lightDir = vec3(0.0);
+    float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+    vec4 attenIntensity = atten * lightIntensity;
+    vec3 surfaceNormal = normalize(vertexNormal);
+    float cosAngIncidence = dot(surfaceNormal, lightDir);
+    cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+    vec3 viewDirection = normalize(-cameraSpacePosition);
+    vec3 halfAngle = normalize(lightDir + viewDirection);
+    float blinnTerm = dot(surfaceNormal, halfAngle);
+    blinnTerm = clamp(blinnTerm, 0, 1);
+    blinnTerm = cosAngIncidence != 0.0 ? blinnTerm : 0.0;
+    blinnTerm = pow(blinnTerm, shininessFactor);
+    outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+        (specularColor * attenIntensity * blinnTerm) +
+        (diffuseColor * ambientIntensity);</programlisting>
+        </example>
+        <para>The half-angle vector is computed by normalizing the sum of the light direction and
+            view direction vectors. As before, we take the dot product between that and the surface
+            normal, clamp, then raise the result to a power.</para>
+        <para>Blinn specular solves the Phong problem with the reflection direction.</para>
+        <!--TODO: Picture comparing Phong and Blinn with same light positions and low shininess.-->
+        <para>The Blinn specular exponent does not mean quite the same thing as the Phong exponent.
+            In general, to produce a highlight the same size as a Phong one, you will need a larger
+            Blinn exponent. Play around with the different exponents, to get a feel for what Blinn
+            and Phong can and cannot achieve.</para>
+    </section>
+    <section>
+        <title>Gaussian</title>
+        <para>Phong and Blinn are nice toy heuristics that take relatively little computational
+            power. But if you're truly serious about computing specular highlights, you need a model
+            that actually <emphasis>models</emphasis> microfacets.</para>
+        <para>Real microfacet models are primarily based on the answer to the question <quote>What
+                proportion of the microfacets of this surface are oriented in such a way as to
+                specularly reflect light towards the viewer?</quote> The greater the proportion of
+            properly oriented microfacets, the stronger the reflected light. This question is
+            ultimately one of statistics.</para>
+        <para>Thus it makes sense to model this as a probability distribution. We know that the
+            average microfacet orientation is the surface normal. So it's just a matter of
+            developing a probability distribution function that says what portion of the surface's
+            microfacets are oriented to provide specular reflections given the light direction and
+            the view direction.</para>
+        <para>In statistics, the very first place you go for modelling anything with a probability
+            distribution is to the <glossterm>normal distribtuion</glossterm> or <glossterm>Gaussian
+                distribution.</glossterm> It may not be the correct distribution that physically
+            models what the microfacet distribution of a surface looks like, but it's usually a good
+            starting point.</para>
+        <para>The Gaussian distribution is the classic <quote>bell-shaped curve</quote>
+            distribution. The mathematical function for computing the probability density of the
+            Gaussian distribution at a particular point X is:</para>
+        <!--TODO: Equation for Gaussian distribution.-->
+        <!--TODO: Picture of Gaussian curve.-->
+        <para>This represents the percentage of the items in the distribution that satisfy the
+            property that the X in the distribution is trying to model. The <literal>e</literal> in
+            this equation is a common mathematical constant, equivalent to ~2.718.The value of
+                <varname>μ</varname> is the average. So the absolute value of X is not important;
+            what matters is how far X is from the average.</para>
+        <para>The value <varname>σ<superscript>2</superscript></varname> is the variance of the
+            Gaussian distribution. Without getting too technical, the larger this value becomes, the
+            flatter and wider the distribution is. The variance specifies how far from the average
+            you can get to achieve a certain probability density. The area of the distribution that
+            is positive and negative <varname>σ</varname> away from the average takes up ~68% of the
+            possible values. The area that is 2<varname>σ</varname> away represents ~95% of the
+            possible values.</para>
+        <para>We know what the average is for us: the surface normal. We can incorporate what we
+            learned from Blinn, by measuring the distance from perfect reflection by comparing the
+            surface normal to the half-angle vector. Thus, the X values represents the angle between
+            the surface normal and half-angle vector. The value <varname>μ</varname>, the average,
+            is zero.</para>
+        <para>The equation we will be using for modelling the microfacet distribution with a
+            Gaussian distribution is a slightly simplified form of the Gaussian distribution
+            equation.</para>
+        <!--TODO: Equation for Guassian lighting distribution.-->
+        <para>This replaces our Phong and Blinn terms in our specular lighting equation and gives us
+            the <glossterm>Gaussian specular model</glossterm>. The value <varname>m</varname>
+            ranges from (0, 1], with larger values representing an increasingly rougher surface.
+            Technically, you can use values larger than 1, but the results begin looking
+            increasingly less useful. A value of 1 is plenty rough enough for specular reflection;
+            properly modelling extremely rough surfaces requires additional computations besides
+            determining the distribution of microfacets.</para>
+        <para>The <phrase>Gaussian Specular Lighting</phrase> tutorial shows an implementation of
+            Gaussian specular. It allows a comparison between Phong, Blinn, and Gaussian. It
+            controls the same as the previous tutorial, with the <keycap>H</keycap> key switching
+            between the three specular computations, and the <keycombo>
+                <keycap>Shift</keycap>
+                <keycap>H</keycap>
+            </keycombo> switching between diffuse+specular and specular only.</para>
+        <para>Here is the fragment shader for doing Gaussian lighting.</para>
+        <example>
+            <title>Gaussian Lighting Shader</title>
+            <programlisting language="glsl">vec3 lightDir = vec3(0.0);
+float atten = CalcAttenuation(cameraSpacePosition, lightDir);
+vec4 attenIntensity = atten * lightIntensity;
+vec3 surfaceNormal = normalize(vertexNormal);
+float cosAngIncidence = dot(surfaceNormal, lightDir);
+cosAngIncidence = clamp(cosAngIncidence, 0, 1);
+vec3 viewDirection = normalize(-cameraSpacePosition);
+vec3 halfAngle = normalize(lightDir + viewDirection);
+float angleNormalHalf = acos(dot(halfAngle, surfaceNormal));
+float exponent = angleNormalHalf / shininessFactor;
+exponent = -(exponent * exponent);
+float gaussianTerm = exp(exponent);
+gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
+outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
+    (specularColor * attenIntensity * gaussianTerm) +
+    (diffuseColor * ambientIntensity);</programlisting>
+        </example>
+        <para>Computing the angle between the half-angle vector and the surface normal requires the
+            use of the <function>acos</function> function. We use the dot-product to compute the
+            cosine of the angle, so we need a function to undo the cosine operation. The
+                <glossterm>arc cosine</glossterm> or <glossterm>inverse cosine</glossterm> function
+            takes the result of a cosine and returns the angle that produced that value.</para>
+        <para>To do the exponentiation, we use the <function>exp</function> function. This function
+            raises the constant <literal>e</literal> to the power of the argument. Everything else
+            proceeds as expected.</para>
+        <section>
+            <title>What Gaussian Offers</title>
+            <para>If you play around with the controls, you can see how much the Gaussian
+                distribution offers over Phong and Blinn. For example, set the Gaussian smoothness
+                value to 0.05.</para>
+            <!--TODO: Show a picture of a Gaussian highlight with smoothness at 0.05-->
+            <para>It requires very large exponents, well in excess of 100, to match the small size
+                and focus of that specular highlight with Phong or Blinn. It takes even larger
+                exponents to match the Gaussian value of 0.02.</para>
+            <para>Otherwise the differences between Gaussian and Blinn are fairly subtle. For rough
+                surfaces, there is little substantive difference. But Gaussian tends to have a
+                sharper, more distinct highlight for shiny surfaces.</para>
+        </section>
+    </section>
+    <section>
+        <title>On Performance</title>
+        <para>The three specular highlight models seen here are obviously more computationally
+            expensive than diffuse lighting. But which is ultimately more expensive than the
+            others?</para>
+        <para>The difference between Phong and Blinn is that Phong must compute the reflection
+            vector, while Blinn computes the half-angle vector. The equation for computing the
+            reflection vector is:</para>
+        <!--TODO: Show the reflection vector equation again-->
+        <para>This involves a vector dot product, a scalar multiply, a vector-scalar multiply, and a
+            vector addition (subtraction). Computing the half-angle vector requires doing a vector
+            addition and performing a normalize operation. Normalizing a vector requires a vector
+            dot product (dotting the vector with itself), taking the square-root of that value, and
+            then a vector-scalar divide by that value.</para>
+        <para>Time once was that it was easy to know what was faster. The presence of a square-root
+            operation alone would have condemned Blinn as the slower method. On modern 3D graphics
+            hardware however, taking the reciprocal square-root (1 / √X) is generally about as fast
+            as doing a vector multiply. This puts Blinn as approximately equal in performance to
+            Phong; on some hardware, it may even be faster. In general, the performance difference
+            between the two will be negligable.</para>
+        <para>Gaussian is a different story. It would be reasonable to expect the
+                <function>pow</function> function, taking <inlineequation>
+                <mathphrase>x<superscript>y</superscript></mathphrase>
+            </inlineequation> for arbitrary values, to be slower than executing
+                <function>exp</function>, <inlineequation>
+                <mathphrase>e<superscript>x</superscript></mathphrase>
+            </inlineequation>. They might have the same performance, but if one is going to be
+            faster, it is more likely to be <function>exp</function> than <function>pow</function>.
+            However, Gaussian also uses the inverse cosine; that pretty much negates any possibility
+            of performance parity. The inverse cosine computation is certainly not built into the
+            hardware, and thus must be computed using the shader logic. And while this is likely
+            true of exponentiation and power functions, Gaussian has to do <emphasis>two</emphasis>
+            of these operations, compared to just one for Phong or Blinn.</para>
+        <para>One might consider using Gouraud shading with specular reflections as a method of
+            optimization. This is not for the best. Specular highlights do not interpolate linearly
+            at all, so unless the mesh is finely divided, it will generally look awful.</para>
+    </section>
         <?dbhtml filename="Tut10 In Review.html" ?>
         <title>In Review</title>
         <para>In this tutorial, you have learned the following:</para>
-                <para/>
+                <para>Specular lighting represents direct, mirror-like reflections from a surface.
+                    Specular highlights are mirror-like reflections directly from a light source.
+                    Adding weak specular highlights to even rough surfaces can increase visual
+                    realism.</para>
-                <para/>
+                <para>The microfacet model of specular reflection means that, for a given surface
+                    area, there are many mirror-like surfaces. Each microfacet reflects perfectly in
+                    its direction. The average of the microfacets </para>
+            </listitem>
+            <listitem>
+                <para>The Phong and Blinn models of specular reflection use a power function based
+                    on how close the viewer is to perfect reflection to approximate a microfacet
+                    distribution.</para>
+            </listitem>
+            <listitem>
+                <para>A Gaussian statistical distribution can be used to more accurately model the
+                    distributions of microfacets on a surface.</para>
             <para>Try doing these things with the given programs.</para>
-                    <para/>
+                    <para>Change the shaders to use the diffuse color as the specular color. You may
+                        need to drop the specular color somewhat to keep from over-brightening the
+                        scene. How this all looks will be particularly evident with the colored
+                        cylinder.</para>
+            <title>Further Research</title>
+            <para>As you might guess, this is far from the end on specular reflections and specular
+                highlights. Accurately modelling specular reflection is very difficult; doing so
+                while maintaining high performance is even moreso.</para>
+            <para>If you are interested in more accurate models of specular highlights, there is the
+                Beckmann distribution. This is a particular statistical distribution of microfacets
+                that is more physically based than a Gaussian distribution. It may be a bit more
+                computationally expensive than Gaussian (due to being able to avoid the
+                    <function>acos</function>). The two do have a roughness factor that has the same
+                range, (0, 1].</para>
+            <para>If you want to go even farther, investigate the <quote>Cook-Torrance</quote> model
+                of specular reflection. It incorporates several terms. It uses a statistical
+                distribution to determine the number of microfacets oriented in a direction. This
+                distribution can be Gaussian, Beckmann, or some other distribution. It modifies this
+                result based on a geometric component that models microfacet self-shadowing and the
+                possibility for multiple interreflections among a microfaceted surface. And it adds
+                a term to compensate for the Fresnel effect: an effect where specular reflection
+                from a surface is more intense when viewed edge-on than directly top-down.</para>
+        </section>
+        <section>
             <title>GLSL Functions of Note</title>
-            <para/>
+            <funcsynopsis>
+                <funcprototype>
+                    <funcdef>vec <function>reflect</function></funcdef>
+                    <paramdef>vec <parameter>I</parameter></paramdef>
+                    <paramdef>vec <parameter>N</parameter></paramdef>
+                </funcprototype>
+            </funcsynopsis>
+            <para>Computes the vector that would be reflected across the normal <varname>N</varname>
+                from an incident vector <varname>I</varname>. The vector result will be normalized
+                if the input vectors are normalized. Note that <varname>I</varname> vector is the
+                vector <emphasis>towards</emphasis> the surface.</para>
+            <funcsynopsis>
+                <funcprototype>
+                    <funcdef>vec <function>pow</function></funcdef>
+                    <paramdef>vec <parameter>X</parameter></paramdef>
+                    <paramdef>vec <parameter>Y</parameter></paramdef>
+                </funcprototype>
+            </funcsynopsis>
+            <para>Raises <varname>X</varname> to the power of <varname>Y</varname>, component-wise.
+                If a component of <varname>X</varname> is less than 0, then the resulting value is
+                undefined. If <varname>X</varname> is exactly zero, and <varname>Y</varname> is less
+                than or equal to 0, then the resulting value is undefined.</para>
+            <funcsynopsis>
+                <funcprototype>
+                    <funcdef>vec <function>acos</function></funcdef>
+                    <paramdef>vec <parameter>X</parameter></paramdef>
+                </funcprototype>
+            </funcsynopsis>
+            <para>Returns the inverse cosine of <varname>X</varname>, component-wise. This returns
+                the angle in radians, which is on the range [0, π]. If any component of
+                    <varname>X</varname> is outside of the [-1, 1] range, then that component of the
+                result will be undefined. This is because the cosine of a value is always on [-1,
+                1], so the inverse-cosine function cannot take values outside of this range.</para>
+            <funcsynopsis>
+                <funcprototype>
+                    <funcdef>vec <function>exp</function></funcdef>
+                    <paramdef>vec <parameter>exponent</parameter></paramdef>
+                </funcprototype>
+            </funcsynopsis>
+            <para>Returns the value of <inlineequation>
+                    <mathphrase>e<superscript>exponent</superscript></mathphrase>
+                </inlineequation>, component-wise.</para>
-                <glossterm/>
+                <glossterm>specular reflection</glossterm>
-                    <para/>
+                    <para>A mirror-like reflection of light from a surface. Specular reflections
+                        reflect light; thus, the color the viewer sees is strongly based on the view
+                        angle relative to the light. Specular reflections often do not affect the
+                        color of the incoming light.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>specular highlights</glossterm>
+                <glossdef>
+                    <para>Mirror-like reflections directly from light sources. Since light sources
+                        are brighter than light reflected by other objects, modelling only specular
+                        highlights can provide useful realism without having to model reflections
+                        from light produced by other objects in the scene.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>angle of view, viewing angle</glossterm>
+                <glossdef>
+                    <para>The angle between the surface normal and the direction to the
+                        viewer/camera.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>microfacet model</glossterm>
+                <glossdef>
+                    <para>Describes a surface as a number of flat planes called microfacets. Each
+                        microfacet reflects light using a simple lighting model. The light from a
+                        portion of the surface is simply the aggregate of the light from all of the
+                        microfacets of the surface. The statistical distribution of microfacet
+                        directions on a surface becomes an integral part of the lighting equation.
+                        The normal of a surface at a point is the average normal of the microfacets
+                        of that part of the surface.</para>
+                    <para>The microfacet model can be used to model the reflectance characteristics
+                        of rough surfaces.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>Phong specular model</glossterm>
+                <glossdef>
+                    <para>A simple model for creating specular highlights. It uses a power function
+                        to determine the distribution of microfacets of the surface. The base of the
+                        power function is the cosine of the angle between the view direction and the
+                        direction of perfect reflection along the surface normal. The exponent is an
+                        arbitrary value on the range (0, ∞); large values describe increasingly
+                        shiny surfaces, while small values are for rough surfaces.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>half-angle vector</glossterm>
+                <glossdef>
+                    <para>The vector halfway between the direction towards the light and the view
+                        direction. When the half-angle vector is oriented exactly with the surface
+                        normal, then the view direction is oriented along the reflection
+                        direction.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>Blinn-Phong specular model</glossterm>
+                <glossdef>
+                    <para>A simple model for creating specular highlights. Like standard Phong, it
+                        uses a power function to model the distribution of microfacets. The base of
+                        the power function is the cosine of the angle between the half-angle vector
+                        and the surface normal. The exponent is an arbitrary value on the range (0,
+                        ∞); large values describe increasingly shiny surfaces, while small values
+                        are for rough surfaces.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>Gaussian distribution, normal distribution</glossterm>
+                <glossdef>
+                    <para>A common statistical distribution. It defines the familiar
+                            <quote>bell-shaped curve,</quote> with the average value at the highest
+                        point of the distribution.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>Gaussian specular model</glossterm>
+                <glossdef>
+                    <para>A model for creating specular highlights. It uses the Gaussian
+                        distribution to model the distribution of microfacets on a surface. It uses
+                        a value to control the distribution; this value ranges on (0, 1], where
+                        small numbers are smooth surfaces and large numbers are rough
+                        surfaces.</para>
+                </glossdef>
+            </glossentry>
+            <glossentry>
+                <glossterm>inverse cosine, arc cosine</glossterm>
+                <glossdef>
+                    <para>Performs the opposite of the cosine function. The cosine function takes
+                        angles and returns a value on the range (-1, 1). The inverse cosine takes
+                        values on the range (-1, 1) and returns an angle in radians.</para>

File Tut 10 Shinies/Blinn vs Phong Lighting.cpp

 static float g_CylPitch = -90.0f;
 static float g_CylRoll = 0.0f;
-static int g_eLightModel = LM_PHONG_SPECULAR;
+static int g_eLightModel = LM_BLINN_SPECULAR;
 static bool g_bUseFragmentLighting = true;
 static bool g_bDrawColoredCyl = false;

File Tut 10 Shinies/data/GaussianLighting.frag

 	exponent = -(exponent * exponent);
 	float gaussianTerm = exp(exponent);
-	gaussianTerm = dot(surfaceNormal, lightDir) >= 0.0 ? gaussianTerm : 0.0;
+	gaussianTerm = cosAngIncidence != 0.0 ? gaussianTerm : 0.0;
 	outputColor = (diffuseColor * attenIntensity * cosAngIncidence) +
 		(specularColor * attenIntensity * gaussianTerm) +

File Tut 10 Shinies/data/PhongLighting.frag

 	vec3 reflectDir = reflect(-lightDir, surfaceNormal);
 	float phongTerm = dot(viewDirection, reflectDir);
 	phongTerm = clamp(phongTerm, 0, 1);
-	phongTerm = dot(reflectDir, surfaceNormal) > 0.0 ? phongTerm : 0.0;
+	phongTerm = cosAngIncidence != 0.0 ? phongTerm : 0.0;
 	phongTerm = pow(phongTerm, shininessFactor);

File Tut 10 Shinies/data/PhongOnly.frag

 	vec3 surfaceNormal = normalize(vertexNormal);
 	vec3 viewDirection = normalize(-cameraSpacePosition);
-	vec3 reflectDir = reflect(-lightDir, surfaceNormal);
+	vec3 reflectDir = normalize(reflect(-lightDir, surfaceNormal));
 	float phongTerm = dot(viewDirection, reflectDir);
 	phongTerm = clamp(phongTerm, 0, 1);
-	phongTerm = dot(reflectDir, surfaceNormal) > 0.0 ? phongTerm : 0.0;
+	phongTerm = dot(surfaceNormal, lightDir) > 0.0 ? phongTerm : 0.0;
 	phongTerm = pow(phongTerm, shininessFactor);
 	outputColor = (specularColor * attenIntensity * phongTerm) +