gltut / Documents / Positioning / Tutorial 06.xml

   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
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
<?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 06.html" ?>
    <title>Objects in Motion</title>
    <para>In this tutorial, we will look at a number of ways to transform objects, rendering them in
        different locations and orientations in the world. And we will also solve the secret of why
        we overcomplicated everything with those matrices.</para>
    <section>
        <title>Spaces</title>
        <para>Throughout this series of tutorials, we have discussed a number of different spaces.
            We have seen OpenGL-defined spaces like normalized device coordinate (NDC) space,
            clip-space, and window space. And we have seen user-defined spaces like camera space.
            But we have yet to formally discuss about what a space actually is.</para>
        <para>A <glossterm>space</glossterm> is a shorthand term for a <glossterm>coordinate
                system.</glossterm> For the purposes of this conversation, a coordinate system or
            space consists of the following:</para>
        <itemizedlist>
            <listitem>
                <para>The dimensionality of the space. 2D, 3D, 4D, etc.</para>
            </listitem>
            <listitem>
                <para>A series of vectors in those dimensions that define the axes of the space. The
                    directions do not have to be orthogonal (at right-angles) to one another, but
                    there must be one axis per dimension. Each axis vector in the space has a name,
                    like X, Y, Z, etc. These are called the <glossterm>basis vectors</glossterm> of
                    a space.</para>
            </listitem>
            <listitem>
                <para>A location in the space that defines the central <glossterm>origin</glossterm>
                    point. The origin is the point from which all other points in the space are
                    derived.</para>
            </listitem>
            <listitem>
                <para>An area within this space in which points are valid. Outside of this range,
                    positions are not valid. The range can be infinite depending on the
                    space.</para>
            </listitem>
        </itemizedlist>
        <para>A position or vertex in a space is defined as the sum of the axis vectors, where each
            basis vector is multiplied by a value called a coordinate. Geometrically, this looks
            like the following:</para>
        <figure>
            <title>Two 2D Coordinate Systems</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="CoordSys2D.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>These are two different coordinate systems. The same coordinate, in this case (2, 2)
            (each basis vector is added twice) can have two very different positions, from the point
            of view of a neutral observer. What is interesting to note is that (2, 2) is the same
            value in their own coordinate system. This means that a coordinate itself is not enough
            information to know what it means; one must also know what coordinate system it is in
            before you can know anything about it.</para>
        <para>The numerical version of the coordinate system equation is as follows:</para>
        <equation>
            <title>Coordinate System</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="FullCoordinateEquation.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>The geometric version is all well and good when dealing with the geometric basis
            vectors and origin point. The origin point is just a position, and the basis vectors are
            simply drawn. But what does it mean to give actual numbers to these concepts in the
            numerical version? A position, like the origin point, is itself a coordinate. Which
            means that it must be defined relative to some coordinate system. The same goes for the
            basis vectors.</para>
        <para>For the purpose of this discussion, there is a coordinate system that acts as a kind
            of neutral coordinate system; it can be used as a generic viewpoint for a coordinate
            system. For a three-dimensional coordinate system, this identity space has the origin at
            (0, 0, 0), with the X, Y and Z basis vectors as (1, 0, 0), (0, 1, 0), and (0, 0, 1). The
            range of the space is infinite. Any space can be defined relative to this identity
            space. And unless otherwise noted, this is the space of any basis vectors or origin
            points.</para>
        <section>
            <title>Transformation</title>
            <para>In the more recent tutorials, the ones dealing with perspective projections, we
                have been taking positions in one coordinate system (space) and putting them in
                another coordinate system. Specifically, we had objects in camera space that we
                moved into clip space. The process of taking a coordinate in one space and
                specifying it as a coordinate in another space is called
                    <glossterm>transformation</glossterm>. The coordinate's actual meaning has not
                changed; all that has changed is the coordinate system that this coordinate is
                relative to.</para>
            <para>We have seen a number of coordinate system transformations. OpenGL implements the
                transformation from clip-space to NDC space and the transformation from NDC to
                window space. Our shaders implement the transformation from camera space to
                clip-space, and this was done using a matrix. Perspective projection (and
                orthographic, for that matter) are simply a special kind of transformation.</para>
            <para>This tutorial will cover a large number of different kinds of transform
                operations and how to implement them in OpenGL.</para>
        </section>
        <section>
            <title>Model Space</title>
            <para>Before we begin, we must define a new kind of space: <glossterm>model
                    space.</glossterm> This is a user-defined space, but unlike camera space, model
                space does not have a single definition. It is instead a catch-all term for the
                space that a particular object begins in. Coordinates in vertex buffers, passed to
                the vertex shaders as vertex attributes are <foreignphrase>de facto</foreignphrase>
                in model space.</para>
            <para>There are an infinite variety of model spaces. Each object one intends to render
                can, and often does, have its own model space, even if the difference between these
                spaces is only in the origin point. Model spaces for an object are generally defined
                for the convenience of the modeller or the programmer who intends to use that
                model.</para>
            <para>The transformation operation being discussed in this tutorial is the transform
                from model space to camera space. Our shaders already know how to handle
                camera-space data; all they need is a way to transform from model space to camera
                space.</para>
        </section>
    </section>
    <section>
        <?dbhtml filename="Tut06 Translation.html" ?>
        <title>Translation</title>
        <para>The simplest space transformation operation is translation. Indeed, we have not only
            seen this transform before, it has been used in all of the tutorials with a perspective
            projection. Recall this line from the vertex shaders:</para>
        <programlisting language="glsl">vec4 cameraPos = position + vec4(offset.x, offset.y, 0.0, 0.0);</programlisting>
        <para>This is a <glossterm>translation</glossterm> transformation: it is used to position
            the origin point of the initial space relative to the destination space. Since all of
            the coordinates in a space are relative to the origin point of that space, all a
            translation needs to do is add a vector to all of the coordinates in that space. The
            vector added to these values is the location of where the user wants the origin point
            relative to the destination coordinate system.</para>
        <figure>
            <title>Coordinate System Translation in 2D</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="TranslationTransform.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>Here is a more concrete example. Let us say that an object which in its model space is
            near its origin. This means that, if we want to see that object in front of the camera,
            we must position the origin of the model in front of the camera. If the extent of the
            model is only [-1, 1] in model space, we can ensure that the object is visible by adding
            this vector to all of the model space coordinates: (0, 0, -3). This puts the origin of
            the model at that position in camera space.</para>
        <para>Translation is ultimately just that simple. So let's make it needlessly complex. And
            the best tool for doing that: matrices. Oh, we could just use a 3D uniform vector to
            pass an offset to do the transformation. But matrices have hidden benefits we will
            explore very soon.</para>
        <para>All of our position vectors are 4D vectors, with a final W coordinate that is always
            1.0. In <link linkend="Tut04_matrix">Tutorial 04,</link> we took advantage of this with
            our perspective transformation matrix. The equation for the Z coordinate needed an
            additive term, so we put that term in the W column of the transformation matrix. Matrix
            multiplication causes the value in the W column to be multiplied by the W coordinate of
            the vector (which is 1) and added to the sum of the other terms.</para>
        <para>But how do we keep the matrix from doing something to the other terms? We only want
            this matrix to apply an offset to the position. We don't want to have it modify the
            position in some other way.</para>
        <para>This is done by modifying an <glossterm>identity matrix.</glossterm> An identity
            matrix is a matrix that, when performing matrix multiplication, will return the matrix
            it is multiplied with. It is sort of like the number 1 with regular multiplication: 1*X
            = X. The 4x4 identity matrix looks like this:</para>
        <equation>
            <title>Identity Matrix</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="IdentityMatrix.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>To modify the identity matrix into one that is suitable for translation, we simply put
            the offset into the W column of the identity matrix.</para>
        <equation>
            <title>Translation Matrix</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="TranslationMatrix.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>The tutorial project cleverly titled <phrase role="propername">Translation</phrase>
            performs translation operations.</para>
        <para>This tutorial renders 3 of the same object, all in different positions. One of the
            objects is positioned in the center of the screen, and the other two's positions orbit
            it at various speeds.</para>
        <para>Because of the prevalence of matrix math, this is the first tutorial that uses the GLM
            math library. So let's take a look at the shader program initialization code to see it
            in action.</para>
        <example>
            <title>Translation Shader Initialization</title>
            <programlisting language="cpp">void InitializeProgram()
{
    std::vector&lt;GLuint> shaderList;
    
    shaderList.push_back(Framework::LoadShader(GL_VERTEX_SHADER,
        "PosColorLocalTransform.vert"));
    shaderList.push_back(Framework::LoadShader(GL_FRAGMENT_SHADER,
        "ColorPassthrough.frag"));
    
    theProgram = Framework::CreateProgram(shaderList);
    
    positionAttrib = glGetAttribLocation(theProgram, "position");
    colorAttrib = glGetAttribLocation(theProgram, "color");
    
    modelToCameraMatrixUnif = glGetUniformLocation(theProgram,
        "modelToCameraMatrix");
    cameraToClipMatrixUnif = glGetUniformLocation(theProgram,
        "cameraToClipMatrix");
    
    float fzNear = 1.0f; float fzFar = 45.0f;
    
    cameraToClipMatrix[0].x = fFrustumScale;
    cameraToClipMatrix[1].y = fFrustumScale;
    cameraToClipMatrix[2].z = (fzFar + fzNear) / (fzNear - fzFar);
    cameraToClipMatrix[2].w = -1.0f;
    cameraToClipMatrix[3].z = (2 * fzFar * fzNear) / (fzNear - fzFar);
    
    glUseProgram(theProgram);
    glUniformMatrix4fv(cameraToClipMatrixUnif, 1, GL_FALSE,
        glm::value_ptr(cameraToClipMatrix));
    glUseProgram(0);
}</programlisting>
        </example>
        <para>GLM takes a unique approach for a vector/matrix math library. It attempts to emulate
            GLSL's approach to vector operations where possible. It uses C++ operator overloading to
            effectively emulate GLSL. In many cases, GLM-based expressions would compile in
            GLSL.</para>
        <para>The matrix <varname>cameraToClipMatrix</varname> is defined as a
                <type>glm::mat4</type>, which has the same properties as a GLSL <type>mat4.</type>
            Array indexing of a <type>mat4</type>, whether GLM or GLSL, returns the zero-based
                <emphasis>column</emphasis> of the matrix as a <type>vec4</type>.</para>
        <para>The <function>glm::value_ptr</function> function is used to get a direct pointer to
            the matrix data, in column-major order. This is useful for uploading data to OpenGL, as
            shown with the call to <function>glUniformMatrix4fv</function>.</para>
        <para>With the exception of getting a second uniform location (for our model transformation
            matrix), this code functions exactly as it did in previous tutorials.</para>
        <para>There is one important note: <varname>fFrustumScale</varname> is not 1.0 anymore.
            Until now, the relative sizes of objects were not particularly meaningful. Now that we
            are starting to deal with more complex objects that have a particular scale, picking a
            proper field of view for the perspective projection is very important.</para>
        <para>The new <varname>fFrustumScale</varname> is computed with this code:</para>
        <example>
            <title>Frustum Scale Computation</title>
            <programlisting language="cpp">float CalcFrustumScale(float fFovDeg)
{
    const float degToRad = 3.14159f * 2.0f / 360.0f;
    float fFovRad = fFovDeg * degToRad;
    return 1.0f / tan(fFovRad / 2.0f);
}

const float fFrustumScale = CalcFrustumScale(45.0f);</programlisting>
        </example>
        <para>The function <function>CalcFrustumScale</function> computes the frustum scale based on
            a field-of-view angle in degrees. The field of view in this case is the angle between
            the forward direction and the direction of the farmost-extent of the view.</para>
        <para>This project, and many of the others in this tutorial, use a fairly complex bit of
            code to manage the transform matrices for the various object instances. There is an
                <classname>Instance</classname> object for each actual object; it has a function
            pointer that is used to compute the object's offset position. The
                <classname>Instance</classname> object then takes that position and computes a
            transformation matrix, based on the current elapsed time, with this function:</para>
        <example>
            <title>Translation Matrix Generation</title>
            <programlisting language="cpp">glm::mat4 ConstructMatrix(float fElapsedTime)
{
    glm::mat4 theMat(1.0f);
    
    theMat[3] = glm::vec4(CalcOffset(fElapsedTime), 1.0f);
    
    return theMat;
}</programlisting>
        </example>
        <para>The <type>glm::mat4</type> constructor that takes only a single value constructs what
            is known as a diagonal matrix. That is a matrix with all zeros except for along the
            diagonal from the upper-left to the lower-right. The values along that diagonal will be
            the value passed to the constructor. An identity matrix is just a diagonal matrix with 1
            as the value along the diagonal.</para>
        <para>This function simply replaces the W column of the matrix with the offset value.</para>
        <para>This all produces the following:</para>
        <figure>
            <title>Translation Project</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="Translations.png"/>
                </imageobject>
            </mediaobject>
        </figure>
    </section>
    <section>
        <?dbhtml filename="Tut06 Scale.html" ?>
        <title>Scale</title>
        <para>Another kind of transformation is <glossterm>scaling</glossterm>. In terms of our
            previous definition of a coordinate system, this means that our basis vectors are
            getting shorter or longer.</para>
        <figure>
            <title>Coordinate System Scaling in 2D</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="ScaleTransform.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>Scaling can be uniform, which means each basis vector is scaled by the same value. A
            non-uniform scale means that each basis can get a different scale or none at all.</para>
        <para>Uniform scales are used to allow objects in model space to have different units from
            the units used in camera space. For example, a modeller may have generated the model in
            inches, but the world uses centimeters. This will require applying a uniform scale to
            all of these models to compensate for this. This scale should be 2.54, which is the
            conversion factor from inches to centimeters.</para>
        <para>Note that scaling always happens relative to the origin of the space being
            scaled.</para>
        <para>Remember how we defined the way coordinate systems generate a position, based on the
            basis vectors and origin point?</para>
        <informalequation>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="CoordinateEquation.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </informalequation>
        <para>If you are increasing or decreasing the length of the basis vectors, this is the same
            as multiplying those basis vectors by the new length. So we can re-express this equation
            as follows:</para>
        <informalequation>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="ScaledCoordEquation.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </informalequation>
        <para>Since scalar-vector multiplication is both associative and commutative, we can
            multiply the scales directly into the coordinate values to achieve the same effect. So a
            scaled space can be reexpressed as simply multiplying the input coordinate
            values.</para>
        <para>This is easy enough to do in GLSL, if you pass a vector uniform containing the scale
            values. But that's just not complicated enough. Obviously, we need to get matrices
            involved, but how?</para>
        <para>This gets a bit technical, in terms of how a matrix multiplication works. But look
            back at the identity matrix:</para>
        <informalequation>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="IdentityMatrix.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </informalequation>
        <para>This matrix selects each coordinate in turn from the vector it is being multiplied
            into. Each row is multiplied with the column of the vector; all of the zeros remove the
            components of the vector that we do not want. The 1 value of each row multiplies into
            the component we do want, thus selecting it. This produces the identity result: the
            vector we started with.</para>
        <para>We can see that, if the ones were some other value, we would get a scaled version of
            the original vector, depending on which ones were changed. Thus, a scaling
            transformation matrix looks like this:</para>
        <equation>
            <title>Scaling Transformation Matrix</title>
            <mediaobject>
                <imageobject>
                    <imagedata format="SVG" fileref="ScaleMatrix.svg"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>You may start to see a pattern emerging here, something that begins to suggest why
            matrices are very, very useful. I won't spoil it for you yet though.</para>
        <para>The tutorial project <phrase role="propername">Scale</phrase> will display 5 objects
            at various scales. The objects are all at the same Z distance from the camera, so the
            only size difference between the objects is the scale effects applied to them. The
            object in the center is unscaled; each of the other objects has a scale function of some
            kind applied to them.</para>
        <figure>
            <title>Scale Project</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="Scales.png"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>Other than the way the tutorial builds its matrices, there is no difference between
            this tutorial project and the previous one. The matrix building code works as
            follows:</para>
        <programlisting language="cpp">glm::mat4 ConstructMatrix(float fElapsedTime)
{
    glm::vec3 theScale = CalcScale(fElapsedTime);
    glm::mat4 theMat(1.0f);
    theMat[0].x = theScale.x;
    theMat[1].y = theScale.y;
    theMat[2].z = theScale.z;
    theMat[3] = glm::vec4(offset, 1.0f);
    
    return theMat;
}</programlisting>
        <para>As before, the scale is supplied by a number of scale functions, depending on which
            instance is being rendered. The scale is stored in the columns of the identity matrix.
            Then the translation portion of the matrix is filled in.</para>
        <para>The <varname>offset</varname> variable is also a member of the
                <classname>Instance</classname> object. Unlike the last tutorial, the offset is a
            fixed value. We will discuss the ramifications of applying multiple transforms later;
            suffice it to say, this currently works.</para>
        <para>Scaling is only slightly more complicated than translation.</para>
        <sidebar>
            <title>Perspective and Scaling</title>
            <para>The way we construct a scale transformation matrix may seem familiar to you. Back
                in Tutorial 4, the perspective transformation involved a frustum scale value. This
                was used to make up for the fact that our projection defined a specific location for
                the plane of projection and camera eye point. Using this frustum scale, we could
                give the appearance of having a larger or smaller viewing size. Indeed, we later
                used this to define the aspect ratio as well as the field of view, using the
                function defined earlier in this tutorial.</para>
            <para>This frustum scale was ultimately nothing more than a scale factor applied the X
                and Y positions. When we constructed the perspective matrix, we used the frustum
                scale as a uniform scaling in the X and Y dimensions. The aspect ratio compensation
                code was nothing more than applying a <emphasis>non</emphasis>uniform scale.</para>
        </sidebar>
        <section>
            <title>Inversion and Winding Order</title>
            <para>Scales can be theoretically negative, or even 0. A scale of 0 causes the basis
                vector in that direction to become 0 entirely. An basis vector with no length means
                that a dimension has effectively been lost. The resulting transform squashes
                everything in that direction down to the origin. A 3D space becomes a 2D space (or
                1D or 0D, depending on how many axes were scaled).</para>
            <para>A negative scale changes the direction of an axis. This causes vertices
                transformed with this scale to flip across the origin in that axis's direction. This
                is called an <glossterm>inversion</glossterm>. This can have certain unintended
                consequences. In particular, it can change the winding order of vertices.</para>
            <para>Back in <link linkend="tut04_face_culling">Tutorial 4</link>, we introduced the
                ability to cull triangles based on the order in which the vertices appeared in
                window space. Depending on which axis you negate, relative to camera space, an
                inversion can flip the expected winding order of vertices. Thus, triangles that
                were, in model space, forward-facing now in camera space are backwards-facing. And
                vice-versa.</para>
            <para>Negative scaling can have other problems as well. This is not to say that
                inversions cannot be used, but they should be used with care.</para>
        </section>
    </section>
    <section>
        <?dbhtml filename="Tut06 Rotation.html" ?>
        <title>Rotation</title>
        <para>A <glossterm>rotation</glossterm> transformation is the result of the orientation of
            the initial space being different from the orientation of the destination space. The
            basis vectors of the space do not change orientation relative to one another, but
            relative to the destination coordinate system, they are pointed in different directions
            than they were in their own coordinate system.</para>
        <para>A rotation looks like this:</para>
        <figure>
            <title>Coordinate Rotation in 2D</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="RotationTransform.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>Rotations are usually considered the most complex of the basic transformations,
            primarily because of the math involved in computing the transformation matrix.
            Generally, rotations are looked at as an operation, such as rotating around a particular
            basis or some such. The prior part of the tutorial laid down some of the groundwork that
            will make this much simpler.</para>
        <para>First, let's look back at our equation for determining what the position of a
            coordinate is relative to certain coordinate space:</para>
        <informalequation>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="CoordinateEquation.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </informalequation>
        <para>Doesn't this look a bit familiar? No? Maybe this look at vector-matrix multiplication
            will jog your memory:</para>
        <informalequation>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="VectorMatrixMultiplication.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </informalequation>
        <para>Still nothing? Perhaps an alternate look would help:</para>
        <equation>
            <title>Vectorized Matrix Multiplication</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="CoordSysMatrixMultiply.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>Does it look familiar <emphasis>now</emphasis>?</para>
        <para>What this tells us is that the columns of our transformation matrices are, and have
                <emphasis>always</emphasis> been, nothing more than the axes of a coordinate system.
            Except for the fourth column; because the input position has a 1 in the W, it acts as an
            offset.</para>
        <para>Transformation ultimately means this: taking the basis vectors and origin point from
            the original coordinate system and re-expressing them relative to the destination
            coordinate system.</para>
        <para>Therefore, if a rotation is just using a different set of axis directions, then
            building a rotation transformation matrix simply requires computing a new set of basis
            vectors that have different directions but the same length as the original ones. Now,
            this is not easy; it requires semi-advanced math (which is easily encapsulated into
            various functions). But no matter how complex the math may be, this math is nothing more
            than a way to compute basis vectors that point in different directions.</para>
        <para>That is, a rotation matrix is not really a rotation matrix; it is an
                <emphasis>orientation</emphasis> matrix. It defines the orientation of a space
            relative to another space. Remember this, and you will avoid many pitfalls when you
            start dealing with more complex transformations.</para>
        <para>For any two spaces, the orientation transformation between then can be expressed as
            rotating the source space by some angle around a particular axis (specified in the
            initial space). This is true for any change of orientation.</para>
        <para>A common rotation question is to compute a rotation around an arbitrary axis. Or to put it more
            correctly, to determine the orientation of a space if it is rotated around an arbitrary
            axis. The axis of rotation is expressed in terms of the
            initial space. In 2D, there is only one axis that can be rotated around and still remain
            within that 2D plane: the Z-axis.</para>
        <para>In 3D, there are many possible axes of rotation. It does not have to be one of the
            initial space's basis axes; it can be any arbitrary direction. Of course, the problem is
            made much simpler if one rotates only around the primary axes.</para>
        <para>Deriving these matrix equations is beyond the scope of this tutorial; so instead, we
            will simply provide them. To perform rotations along the primary axes, use the following
            matrices:</para>
        <equation>
            <title>Axial Rotation Matrices</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="AxialRotationMatrices.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>When using the standard C/C++ library <function>sin</function> and
                <function>cos</function> functions, the angles must be in radians.</para>
        <para>As useful as these are, the more generic equation for rotation by an angle about an
            arbitrary axis is as follows.</para>
        <equation>
			<title>Angle/Axis Rotation Matrix</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="AngleAxisRotationMatrix.svg" format="SVG"/>
                </imageobject>
            </mediaobject>
        </equation>
        <para>All of these matrices are such that, from the point of view of an observer looking
            down the axis of rotation (the positive direction of the axis is pointed into the eye of
            the observer), the object rotates counter-clockwise with positive angles.</para>
        <para>The <phrase role="propername">Rotations</phrase> tutorial shows off each of these
            rotation matrix functions. Similar to how the others work, there are multiple instances
            rendered based on functions.</para>
        <figure>
            <title>Rotation Project</title>
            <mediaobject>
                <imageobject>
                    <imagedata fileref="Rotations.png"/>
                </imageobject>
            </mediaobject>
        </figure>
        <para>The function that builds the transformation matrix looks like this:</para>
        <example>
            <title>Rotation Transformation Building</title>
            <programlisting language="cpp">glm::mat4 ConstructMatrix(float fElapsedTime)
{
    const glm::mat3 &amp;rotMatrix = CalcRotation(fElapsedTime);
    glm::mat4 theMat(rotMatrix);
    theMat[3] = glm::vec4(offset, 1.0f);
    
    return theMat;
}</programlisting>
        </example>
        <para>The constructor of glm::mat4 that takes a glm::mat3 generates a 4x4 matrix with the
            3x3 matrix in the top-left corner, and all other positions 0 except the bottom-left
            corner, which is set to 1. As with the rest of GLM, this works in GLSL as well.</para>
    </section>
    <section>
        <?dbhtml filename="Tut06 Fun with Matrices.html" ?>
        <title>Fun with Matrices</title>
        <para>In all of the previous examples except for the translation one, we always combined the
            transformation with a translation operation. So the scale transform was not a pure scale
            transform; it was a scale and translate transformation matrix. The translation was there
            primarily so that we could see everything properly.</para>
        <para>But these are not the only combinations of transformations that can be performed.
            Indeed, any combination of transformation operations is possible, though it may not be
            meaningful.</para>
        <para>Successive transformations can be seen as doing successive multiplication operations.
            For example, if S is a pure scale matrix, T is a pure translation matrix, and R is a
            pure scale matrix, then the shader can compute the result of a transformation as
            follows:</para>
        <programlisting language="glsl">vec4 temp;
temp = T * position;
temp = R * temp;
temp = S * temp;
gl_Position = cameraToClipMatrix * temp;</programlisting>
        <para>In mathematical terms, this would be the following series of matrix operations: <inlineequation>
                <mathphrase>Final = C*S*R*T*position</mathphrase>
            </inlineequation>, where C is the camera-to-clip space transformation matrix.</para>
        <para>This is functional, but not particularly flexible; the series of transforms is baked
            into the shader. It is also not particularly fast, what with having to do four
            vector/matrix multiplications for every vertex.</para>
        <para>Matrix math gives us an optimization. Matrix math is not commutative: <inlineequation>
                <mathphrase>S*R</mathphrase>
            </inlineequation> is not the same as <inlineequation>
                <mathphrase>R*S</mathphrase>
            </inlineequation>. However, it is <emphasis>associative</emphasis>: <inlineequation>
                <mathphrase>(S*R)*T</mathphrase>
            </inlineequation> is the same as <inlineequation>
                <mathphrase>S*(R*T)</mathphrase>
            </inlineequation>. The usual grouping for vertex transformation is this: <inlineequation>
                <mathphrase>Final = C*(S*(R*(T*position)))</mathphrase>
            </inlineequation>. But this can easily be regrouped as: <inlineequation>
                <mathphrase>Final = (((C*S)*R)*T)*position</mathphrase>
            </inlineequation>.</para>
        <para>This would in fact be slower for the shader to compute, since full matrix-to-matrix
            multiplication is much slower than matrix-to-vector multiplication. But the combined
            matrix <inlineequation>
                <mathphrase>(((C*S)*R)*T)</mathphrase>
            </inlineequation> is <emphasis>fixed</emphasis> for all of a given object's vertices.
            This can be computed on the CPU, and all we have to do is upload a single matrix to
            OpenGL. And since we're already uploading a matrix to OpenGL for each object we render,
            this changes nothing about the overall performance characteristics of the rendering (for
            the graphics hardware).</para>
        <para><emphasis>This</emphasis> is one of the main reasons matrices are used. You can build
            an incredibly complex transformation sequence with dozens of component transformations.
            And yet, all it takes for the GPU to use this to transform positions is a single
            vector/matrix multiplication.</para>
        <section>
            <title>Order of Transforms</title>
            <para>As previously stated, matrix multiplication is not commutative. This means that
                the combined transform <inlineequation>
                    <mathphrase>S*T</mathphrase>
                </inlineequation> is not the same as <inlineequation>
                    <mathphrase>T*S</mathphrase>
                </inlineequation>. Let us explore this further. This is what these two composite
                transform matrices look like:</para>
            <equation>
                <title>Order of Transformation</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="TransformOrder.svg" format="SVG"/>
                    </imageobject>
                </mediaobject>
            </equation>
            <para>The transform <inlineequation>
                    <mathphrase>S*T</mathphrase>
                </inlineequation> actually scales the translation part of the resulting matrix. This
                means that the vertices will not just get farther from each other, but farther
                    <emphasis>from the origin</emphasis> of the destination space. It is the
                difference between these two transforms:</para>
            <figure>
                <title>Transform Order Diagram</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="TransOrderGeom.svg" format="SVG"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <para>If you think about the order of operations, this makes sense. Even though one can
                think of the combined transform <inlineequation>
                    <mathphrase>S*T</mathphrase>
                </inlineequation> as a single transform, it is ultimately a composite operation. The
                transformation T happens first; the object is translated into a new position.</para>
            <para>What you must understand is that something special happens between S and T.
                Namely, that S is now being applied to positions that are not from model space (the
                space the original vertices were in), but are in <emphasis>post translation
                    space.</emphasis> This is an intermediate coordinate system defined by T.
                Remember: a matrix, even a translation matrix, defines a full-fledged coordinate
                system.</para>
            <para>So S now acts on the T-space position of the vertices. T-space has an origin,
                which in T-space is (0, 0, 0). However, this origin back in model space is the
                translation part of the matrix T. A scaling transformation matrix performs scaling
                based on the origin point in the space of the vertices being scaled. So the scaling
                matrix S will scale the points away from the origin point in T-space. Since what you
                (probably) actually wanted was to scale the points away from the origin point in
                    <emphasis>model space</emphasis>, S needs to come first.</para>
            <para>Orientation (rotation) matrices have the same issue. The orientation is always
                local to the origin in the current space of the positions. So a rotation matrix must
                happen before the translation matrix. Scales generally should happen before
                orientation; if they happen afterwards, then the scale will be relative to the
                    <emphasis>new</emphasis> axis orientation, not the model-space one. This is fine
                if it is a uniform scale, but a non-uniform scale will be problematic.</para>
            <para>There are reasons to put a translation matrix first. If the model-space origin is
                not the point that you wish to rotate or scale around, then you will need to perform
                a translation first, so that the vertices are in the space you want to rotate from,
                then apply a scale or rotation. Doing this multiple times can allow you to scale and
                rotate about two completely different points.</para>
        </section>
        <section>
            <title>Hierarchical Models</title>
            <para>In more complex scenes, it is often desirable to specify the transform of one
                model relative to the model space transform of another model. This is useful if you
                want one object (object B) to pick up another object (object A). The object that
                gets picked up needs to follow the transform of the object that picked it up. So it
                is often easiest to specify the transform for object B relative to object A.</para>
            <para>A conceptually single model that is composed of multiple transforms for multiple
                rendered objects is called a <glossterm>hierarchical model.</glossterm> In such a
                hierarchy, the final transform for any of the component pieces is a sequence of all
                of the transforms of its parent transform, plus its own model space transform.
                Models in this transform have a parent-child relationship to other objects.</para>
            <para>For the purposes of this discussion, each complete transform for a model in the
                hierarchy will be called a <glossterm>node.</glossterm> Each node is defined by a
                specific series of transformations, which when combined yield the complete
                transformation matrix for that node. Usually, each node has a translation, rotation,
                and scale, though the specific transform can be entirely arbitrary. What matters is
                that the full transformation matrix is relative to the space of its parent, not
                camera space.</para>
            <para>So if you have a node who's translation is (3, 0, 4), then it will be 3 X-units
                and 4 Z-units from the origin of its parent transform. The node itself doesn't know
                or care what the parent transform actually is; it simply stores a transform relative
                to that.</para>
            <para>Technically, a node does not have to have a mesh. It is sometimes useful in a
                hierarchical model to have nodes that exist solely to position other, visible nodes.
                Or to act as key points for other purposes, such as identifying the position of the
                gun's muzzle to render a muzzle flash.</para>
            <para>The <phrase role="propername">Hierarchy</phrase> tutorial renders a hierarchical
                model of an arm. This tutorial is interactive; the relative angles of the nodes can
                be changed with keyboard commands. The angles are bound within certain values, so
                the model will stop bending once these values are exceeded. These commands are as
                follows:</para>
            <table frame="none">
                <title>Hierarchy Tutorial Key Commands</title>
                <tgroup cols="3">
                    <colspec colname="c1" colnum="1" colwidth="1.0*"/>
                    <colspec colname="c2" colnum="2" colwidth="1.0*"/>
                    <colspec colname="c3" colnum="3" colwidth="1.0*"/>
                    <thead>
                        <row>
                            <entry>Node Angle</entry>
                            <entry>Increase/Left</entry>
                            <entry>Decrease/Right</entry>
                        </row>
                    </thead>
                    <tbody>
                        <row>
                            <entry>Base Spin</entry>
                            <entry><keycap>a</keycap></entry>
                            <entry><keycap>d</keycap></entry>
                        </row>
                        <row>
                            <entry>Arm Raise</entry>
                            <entry><keycap>w</keycap></entry>
                            <entry><keycap>s</keycap></entry>
                        </row>
                        <row>
                            <entry>Elbow Raise</entry>
                            <entry><keycap>r</keycap></entry>
                            <entry><keycap>f</keycap></entry>
                        </row>
                        <row>
                            <entry>Wrist Raise</entry>
                            <entry><keycap>t</keycap></entry>
                            <entry><keycap>g</keycap></entry>
                        </row>
                        <row>
                            <entry>Wrist Spin</entry>
                            <entry><keycap>z</keycap></entry>
                            <entry><keycap>c</keycap></entry>
                        </row>
                        <row>
                            <entry>Finger Open/Close</entry>
                            <entry><keycap>q</keycap></entry>
                            <entry><keycap>e</keycap></entry>
                        </row>
                    </tbody>
                </tgroup>
            </table>
            <figure>
                <title>Hierarchy Project</title>
                <mediaobject>
                    <imageobject>
                        <imagedata fileref="Robot%20Arm.png"/>
                    </imageobject>
                </mediaobject>
            </figure>
            <para>The structure of the tutorial is very interesting and shows off a number of
                important data structures for doing this kind of rendering.</para>
            <para>The class <classname>Hierarchy</classname> stores the information for our
                hierarchy of nodes. It stores the relative positions for each node, as well as angle
                information and size information for the size of each rectangle. The rendering code
                in <function>display</function> simply does the usual setup work and calls
                    <function>Hierarchy::Draw()</function>, where the real work happens.</para>
            <para>The <function>Draw</function> function looks like this:</para>
            <example>
                <title>Hierarchy::Draw</title>
                <programlisting language="cpp">void Draw()
{
    MatrixStack modelToCameraStack;
    
    glUseProgram(theProgram);
    glBindVertexArray(vao);
    
    modelToCameraStack.Translate(posBase);
    modelToCameraStack.RotateY(angBase);
    
    //Draw left base.
    {
        modelToCameraStack.Push();
        modelToCameraStack.Translate(posBaseLeft);
        modelToCameraStack.Scale(glm::vec3(1.0f, 1.0f, scaleBaseZ));
        glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelToCameraStack.Top()));
        glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData),
            GL_UNSIGNED_SHORT, 0);
        modelToCameraStack.Pop();
    }
    
    //Draw right base.
    {
        modelToCameraStack.Push();
        modelToCameraStack.Translate(posBaseRight);
        modelToCameraStack.Scale(glm::vec3(1.0f, 1.0f, scaleBaseZ));
        glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE,
            glm::value_ptr(modelToCameraStack.Top()));
        glDrawElements(GL_TRIANGLES, ARRAY_COUNT(indexData),
            GL_UNSIGNED_SHORT, 0);
        modelToCameraStack.Pop();
    }
    
    //Draw main arm.
    DrawUpperArm(modelToCameraStack);
    
    glBindVertexArray(0);
    glUseProgram(0);
}</programlisting>
            </example>
            <para>The program and VAO binding code should look familiar, but most of the code should
                be fairly foreign.</para>
            <para>The <classname>MatrixStack</classname> object created in the very first line is a
                class that is also a part of this project. It implements the concept of a
                    <glossterm>matrix stack.</glossterm> The matrix stack is a method for dealing
                with transformations in hierarchical models.</para>
            <para>A stack is a particular data structure concept. Stacks store a controlled sequence
                of objects. But unlike arrays, linked lists, or other general data structures, there
                are only 3 operations available to the user of a stack: push, pop, and peek. Push
                places a value on the top of the stack. Pop removes the value on the top of the
                stack, making the previous top the current top. And peek simply returns the current
                value at the top of the stack.</para>
            <para>A matrix stack is, for the most part, a stack where the values are 4x4
                transformation matrices. Matrix stacks do have a few differences from regular
                stacks. C++ has an object, <classname>std::stack</classname>, that implements the
                stack concept. <classname>MatrixStack</classname> is a wrapper around that object,
                providing additional matrix stack functionality.</para>
            <para>A matrix stack has a current matrix value. An initially constructed matrix stack
                has an identity matrix. There are a number of functions on the matrix stack that
                multiply the current matrix by a particular transformation matrix; the result
                becomes the new current matrix. For example, the
                    <classname>MatrixStack::RotateX</classname> function multiplies the current
                matrix by a rotation around the X axis by the given angle.</para>
            <para>The <function>MatrixStack::Push</function> function takes the current matrix and
                pushes it onto the stack. The <function>MatrixStack::Pop</function> function makes
                the current matrix whatever the top of the stack is, and removes the top from the
                stack. The effect of these is to allow you to save a matrix, modify the current
                matrix, and then restore the old one after you have finished using the modified one.
                And you can store an arbitrary number of matrices, all in a specific order. This is
                invaluable when dealing with a hierarchical model, as it allows you to iterate over
                each element in the model from root to the leaf nodes, preserving older transforms
                and recovering them as needed.</para>
            <para>In the <function>Draw</function> code, the translation is applied to the stack
                first, followed by an X rotation based on the current angle. Note that the order of
                operations is <emphasis>backwards</emphasis> from what we said previously. That's
                because the matrix stack looks at transforms backwards. When we said earlier that
                the rotation should be applied before the translation, that was with respect to the
                    <emphasis>position</emphasis>. That is, the equation should be <inlineequation>
                    <mathphrase>T*R*v</mathphrase>
                </inlineequation>, where v is the position. What we meant was that R should be
                applied to v before T. This means that R comes to the right of T.</para>
            <para>Rather than applying matrices to vertices, we are applying matrices to each other.
                The matrix stack functions all perform right-multiplication; the new matrix being
                multiplied by the current is on the right side. The matrix stack starts with the
                identity matrix. To have it store T*R, you must first apply the T transform, which
                makes the current matrix the current matrix is I*T. Then you apply the R transform,
                making the current matrix I*T*R.</para>
            <para>Right-multiplication is necessary, as the whole point of using the matrix stack is
                so that we can start at the root of a hierarchical model and save each node's
                transform to the stack as we go from parent to child. That simply would not be
                possible if matrix stacks left-multiplied, since we would have to apply the child
                transforms before the parent ones.</para>
            <para>The next thing that happens is that the matrix is preserved by pushing it on the
                stack. After this, a translation and scale are applied to the matrix stack. The
                stack's current matrix is uploaded to the program, and a model is rendered. Then the
                matrix stack is popped, restoring the original transform. What is the purpose of
                this code?</para>
            <para>This code effectively introduces a new kind of space. It was not strictly
                necessary for this example, but it does show off a commonly used technique. The new
                space here does not have a widely agreed upon name, the way other user-defined
                spaces like model space and camera space do. For the purposes of these tutorials,
                let us call this <glossterm>mesh space.</glossterm></para>
            <para>Notice that, for the individual nodes of hierarchical models, model space (the
                node's transform) is propagated to all of the children. The T*R matrix we generated
                was the model space matrix for the base of the model; this transform is preserved on
                the matrix stack and passed to the child drawing functions. However, sometimes it is
                useful to use source mesh data where the mesh itself is <emphasis>not</emphasis> in
                model space.</para>
            <para>In our case, we do this because we know that all of our pieces are 3D rectangles.
                A 3D rectangle is really just a cube with scales and translations applied to them.
                The scale makes the cube into the proper size, and the translation positions the
                origin point for our model space.</para>
            <para>Rather than have this mesh space transform, we could have created 9 or so actual
                rectangle meshes, one for each rendered rectangle. However, this would have required
                more buffer object room and more vertex attribute changes when these were simply
                unnecessary. The vertex shader runs no slower this way; it's still just multiplying
                by matrices. And the minor CPU computation time is exactly that: minor.</para>
            <para>Mesh space is very useful, even though it isn't commonly talked about to the point
                where it gets a special name. As we have seen, it allows easy model reusage, but it
                has other properties as well. For example, it can be good for data compression. As
                we will see in later tutorials, there are ways to store values on the range [0, 1]
                or [-1, 1] in 16 or 8 bits, rather than 32-bit floating point values. If you can
                apply a simple mesh space scale+translation transform to go from this [-1, 1] space
                to the original space of the model, then you can cut your data in half (or less)
                with virtually no impact on visual quality.</para>
            <para>Each section of the code where it uses a mesh space transform happens between a
                    <function>MatrixStack::Push</function> and
                <function>MatrixStack::Pop</function>. This preserves the model space matrix, so
                that it may be used for rendering with other nodes.</para>
            <para>At the bottom of the base drawing function is a call to draw the upper arm. That
                function looks similar to this function: apply the model space matrix to the stack,
                push, apply a mesh space matrix, render, pop, call functions for child parts. All of
                the functions, to one degree or another, look like this. Indeed, they all looks
                similar enough that you could probably abstract this down into a very generalized
                form. And indeed, this is frequently done by scene graphs and the like. The major
                difference between the child functions and the root one is that this function has a
                push/pop wrapper around the entire thing. Though since the root creates a
                MatrixStack to begin with, this could be considered the equivalent.</para>
            <sidebar>
                <title>Matrix Stack Conventions</title>
                <para>There are two possible conventions for matrix stack behavior. The caller could
                    be responsible for pushing and popping the matrix, or the callee (the function
                    being called) could be responsible for this. These are called caller-save and
                    callee-save.</para>
                <para>In caller-save, what it is saying is that a function that takes a matrix stack
                    should feel free to do whatever they want to the current matrix, as well as
                    push/pop as much as they want. However, the callee <emphasis>must</emphasis> not
                    pop more than they push, though this is a general requirement with any function
                    taking a matrix stack. After all, a stack doesn't report how many elements it
                    has, so you can't know whether someone pushed anything at all.</para>
                <para>In callee-save, what the convention is saying is that a function must be
                    responsible for any changes it wants to make to the matrix stack. If it wants to
                    change the matrix stack, then it must push first and pop after using those
                    changes.</para>
                <para>Callee-save is probably a better convention to use. With caller-save, a
                    function that takes a matrix stack must be assumed to modify it (if it takes the
                    object as a non-const reference), so it will have to do a push/pop. Whereas with
                    callee-save, you only push/pop as you explicitly need: at the cite where you are
                    modifying the matrix stack. It groups the code together better.</para>
            </sidebar>
        </section>
    </section>
    <section>
        <?dbhtml filename="Tut06 In Review.html" ?>
        <title>In Review</title>
        <para>In this tutorial, you have learned the following:</para>
        <itemizedlist>
            <listitem>
                <para>Coordinate systems (spaces) are defined by 3 basis axes and a position.</para>
            </listitem>
            <listitem>
                <para>The transformation from one 3D space to another can be defined by a 4x4
                    matrix, which is constructed from the 3 basis axes and the position.</para>
            </listitem>
            <listitem>
                <para>Model space is the coordinate system that a particular model occupies,
                    relative to camera space. Other models can have model spaces that depend on the
                    model space of other models.</para>
            </listitem>
            <listitem>
                <para>Scale, translation, and rotation transformations have specific matrix
                    forms.</para>
            </listitem>
            <listitem>
                <para>Transformations can be composed via matrix multiplication. All transformations
                    for a model can be folded into a single matrix, which a vertex shader can
                    execute at a fixed rate. Therefore, complex transforms are no slower to execute
                    (for the graphics chip) than simple ones.</para>
            </listitem>
            <listitem>
                <para>The order that successive transforms are applied in matters. Matrix
                    multiplication is not commutative, and neither is object transformation.</para>
            </listitem>
        </itemizedlist>
        <section>
            <title>Further Study</title>
            <para>Try doing these things with the given programs.</para>
            <itemizedlist>
                <listitem>
                    <para>In the Translation tutorial, we had two objects that rotated around a
                        specific point. This was achieved by computing the offset for the rotated
                        position on the CPU, not through the use of a rotation transformation.
                        Change this code to use rotation transformations instead. Make sure that the
                        orientation of the objects do not change as they are being rotated around;
                        this will require applying more than one rotation transformation.</para>
                </listitem>
                <listitem>
                    <para>Reverse the order of rotations on the wrist in the Hierarchy tutorial.
                        Note how this affects the ability to adjust the wrist.</para>
                </listitem>
                <listitem>
                    <para>Reimplement the Hierarchy tutorial, instead using a more generic data
                        structure. Have each node be a struct/class that can be attached to an
                        arbitrary node. The scene will simply be the root node. The individual angle
                        values should be stored in the node object. The node should have a render
                        function that will render this node, given the matrix stack. It would render
                        itself, then recursively render its children. The node would also have a way
                        to define the size (in world-space) and origin point of the rectangle to be
                        drawn.</para>
                </listitem>
                <listitem>
                    <para>Given the generalized Hierarchy code, remove the matrix stack. Use objects
                        created on the C++ stack instead. The node render function would take a
                        const&amp; to a matrix rather than a matrix stack reference.</para>
                </listitem>
            </itemizedlist>
        </section>
    </section>
    <section xml:id="Tut06_Glossary">
        <?dbhtml filename="Tut06 Glossary.html" ?>
        <title>Glossary</title>
        <glosslist>
            <glossentry>
                <glossterm>space, coordinate system</glossterm>
                <glossdef>
                    <para>This defines what the coordinates used to refer to positions actually
                        mean. Coordinate systems have a dimensionality (the number of coordinates),
                        an basis vector for each of the dimensions, and an origin position. A
                        coordinate system of 3 dimensions therefore is defined by 3 vectors and a
                        position. The X, Y and Z coordinates in that coordinate system refer to the
                        value you get when you multiply the X, Y, Z values into the X, Y, and Z
                        axes, then add the origin position to those values.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>basis vector</glossterm>
                <glossdef>
                    <para>One of the vectors that define a coordinate system. The basis vectors of a
                        coordinate system do not have to be orthogonal or of unit length.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>transformation</glossterm>
                <glossdef>
                    <para>The process of moving objects defined in one space to be defined in
                        another space.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>model space</glossterm>
                <glossdef>
                    <para>The space that a particular model is expected to be in, relative to some
                        other space. This can be the camera space, or in hierarchical models, the
                        space of a parent node. This does not have to be the initial space that mesh
                        data is stored in.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>translation transform</glossterm>
                <glossdef>
                    <para>A transform between two spaces, where the origin of the spaces are not in
                        the same location. This causes objects to shift as they are transformed
                        between the two spaces.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>identity matrix</glossterm>
                <glossdef>
                    <para>The matrix I such that the following is true: <inlineequation>
                            <mathphrase>MI = M</mathphrase>
                        </inlineequation>, for any matrix M. Identity matrices only exist for square
                        matrices (a matrix with the same number of columns and rows). An identity
                        matrix consists of a matrix with ones along the diagonal from the top-left
                        to the lower-right, and zeros everywhere else.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>scale transform</glossterm>
                <glossdef>
                    <para>A transform between two spaces where the axis vectors of the source space
                        are longer or shorter than the corresponding axis vectors in the destination
                        space. This causes objects to stretch or shrink along the axes as they are
                        transformed between the two spaces.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>scale inversion</glossterm>
                <glossdef>
                    <para>Performing a scale by a negative value. This is perfectly allowed, though
                        it can change the winding order of triangles, depending on the axis being
                        scaled.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>orthogonal</glossterm>
                <glossdef>
                    <para>Two vectors are orthogonal if they are perpendicular to each other. Three
                        vectors are othogonal if each vector is perpendicular to the other
                        two.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>rotation transform, orientation transform</glossterm>
                <glossdef>
                    <para>A transform between two spaces, where the axis vectors of the two spaces
                        are not pointed in the same direction, but the angle between the axis
                        vectors stay the same. This cause a reorientation of objects as they are
                        transformed from the initial space to the destination space.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>hierarchical model</glossterm>
                <glossdef>
                    <para>Models can be conceptually composed of multiple independent pieces in a
                        hierarchy. The space of each component of that hierarchy is stored relative
                        to its parent in the hierarchy.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>node</glossterm>
                <glossdef>
                    <para>A single model space transform within a hierarchy of model transforms. The
                        node's transform is stored relative to the transform of the node beneath it,
                        called the parent. Nodes can have a single parent node and multiple child
                        nodes; the child nodes' transforms are relative to this node's space.</para>
                </glossdef>
            </glossentry>
            <glossentry>
                <glossterm>mesh space</glossterm>
                <glossdef>
                    <para>A space beyond model space in the sequence of transforms ending in clip
                        space. Mesh space is used to transform from a space that is convenient for
                        storing a mesh in into the model space that the rest of the world
                        uses.</para>
                </glossdef>
            </glossentry>
        </glosslist>
    </section>
</chapter>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.