Source

gltut / Documents / Illumination / Tutorial 10.xml

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
<?xml version="1.0" encoding="UTF-8"?>
<?oxygen RNGSchema="http://docbook.org/xml/5.0/rng/docbookxi.rng" type="xml"?>
<?oxygen SCHSchema="http://docbook.org/xml/5.0/rng/docbookxi.rng"?>
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
    <?dbhtml filename="Tutorial 10.html" ?>
    <title>Shinies</title>
    <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>
        <?dbhtml filename="Tut10 Microfacets.html" ?>
        <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>
        <figure>
            <title>Perfect Specular Reflection</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="SpecularReflection.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <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 at the point P, but the viewing position
            B does not.</para>
        <para>Surfaces however are rarely perfect specular reflectors (mirrors are the most common
            perfect reflectors). 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
            appear 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. Surfaces with microfacets would look like
            this:</para>
        <figure>
            <title>Smooth and Rough Microfacets</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="MicrofacetRoughSmooth.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <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 that lie
            under the area of that pixel on the surface.</para>
        <para>The average normal of the microfacets is the surface normal at that point. The
            relative smoothness of a surface can therefore 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>
        <?dbhtml filename="Tut10 Phong Model.html" ?>
        <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>
        <equation>
            <title>Phong Specular Term</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="PhongTerm.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>The Phong term is multiplied by the light intensity in the lighting equation.</para>
        <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>
            <figure>
                <title>Phong Lighting</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="Phong%20Lighting.png"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <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>
            <equation>
                <title>Vector Reflection</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="ReflectionVector.svg" format="SVG"/>
                    </imageobject>
                </mediaobject>
            </equation>
            <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>
            <figure>
                <title>Phong with Dark Diffuse</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="Phong%20Dark%20Diffuse.png"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <para>If there was no specular term at all, you would see very little.. 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>
            <figure>
                <title>Phong Clipping</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="Phong%20Clipping.png"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <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>
            <figure>
                <title>Phong Distortion</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="Phong%20Distortion.png"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <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>
        <?dbhtml filename="Tut10 BlinnPhong Model.html" ?>
        <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.</para>
        <figure>
            <title>Large View and Reflect Angle</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="PhongReflectDirTooGreat.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>The angle between V and R is greater than 90 degrees. Cases like this are not modeled
            correctly by Phong. There could be microfacets at the point which are oriented towards
            the camera, but Phong cannot properly model 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>
        <figure>
            <title>Geometric Half-Angle Vector</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="HalfangleVectorDiagram.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <equation>
            <title>Half-Angle Vector</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="HalfAngleVector.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>When the view direction is perfectly aligned with the reflected direction, the
            half-angle vector is perfectly aligned with the surface normal. Or to put it another
            way, the half-angle is the direction the surface normal would need to be facing in order
            for the viewer to see a specular reflection from the light source.</para>
        <figure>
            <title>Perfect Reflection Half-Angle Vector</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="HalfangleVectorPerfect.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <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>
        <equation>
            <title>Blinn Specular Term</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="BlinnTerm.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <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>
        <figure>
            <title>Blinn Lighting</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="Blinn%20Lighting.png"/>
                </imageobject>
            </mediaobject>
        </figure>
        <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>
        <figure>
            <title>Blinn vs. Phong Lighting</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="Blinn%20vs%20Phong%20Compare.png"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>The Blinn version is on the left, with the Phong version on the right.</para>
        <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>
        <?dbhtml filename="Tut10 Gaussian.html" ?>
        <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>
        <equation>
            <title>Gaussian Distribution Function</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="GaussianDistributionEq.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <figure>
            <title>Gaussian Probability Distribution Curves</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="GaussianPlot.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <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>
        <equation>
            <title>Gaussian Specular Term</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="GaussianTerm.mathml"/>
                </imageobject>
            </mediaobject>
        </equation>
        <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>
            <figure>
                <title>Gaussian with Sharp Highlight</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="Gaussian%20Small%20Highlight.png"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <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>
        <?dbhtml filename="Tut10 On Performance.html" ?>
        <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>
        <informalequation>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="ReflectionVector.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </informalequation>
        <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 negligible.</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 to compute the angle between the normal
            and half-angle vector; 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. That is, doing per-vertex specular reflections. Since there are fewer
            vertices than fragments, this might sound like a good idea. However, 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>
    <section>
        <?dbhtml filename="Tut10 In Review.html" ?>
        <title>In Review</title>
        <para>In this tutorial, you have learned the following:</para>
        <itemizedlist>
            <listitem>
                <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>
            </listitem>
            <listitem>
                <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>
            </listitem>
        </itemizedlist>
        <section>
            <title>Further Study</title>
            <para>Try doing these things with the given programs.</para>
            <itemizedlist>
                <listitem>
                    <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>
                </listitem>
            </itemizedlist>
        </section>
        <section>
            <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], and the roughness has the same general meaning in both
                distributions.</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>
            <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>
        </section>
    </section>
    <section>
        <?dbhtml filename="Tut10 Glossary.html" ?>
        <title>Glossary</title>
        <glosslist>
            <glossentry>
                <glossterm>specular reflection</glossterm>
                <glossdef>
                    <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>
                </glossdef>
            </glossentry>
        </glosslist>
    </section>
</chapter>