LearnOpenGL

Translation in progress of learnopengl.com.
git clone https://git.mtkn.jp/LearnOpenGL
Log | Files | Refs

Advanced-GLSL.html (36293B)


      1     <div id="content">
      2     <h1 id="content-title">Advanced GLSL</h1>
      3 <h1 id="content-url" style='display:none;'>Advanced-OpenGL/Advanced-GLSL</h1>
      4 <p>
      5   This chapter won't really show you super advanced cool new features that give an enormous boost to your scene's visual quality. This chapter goes more or less into some interesting aspects of GLSL and some nice tricks that may help you in your future endeavors. Basically some <em>good to knows</em> and <em>features that may make your life easier</em> when creating OpenGL applications in combination with GLSL.
      6 </p>
      7 
      8 <p>
      9   We'll discuss some interesting <def>built-in variables</def>, new ways to organize shader input and output, and a very useful tool called <def>uniform buffer objects</def>.
     10 </p>
     11 
     12 <h1>GLSL's built-in variables</h1>
     13 <p>
     14   Shaders are extremely pipelined, if we need data from any other source outside of the current shader we'll have to pass data around. We learned to do this via vertex attributes, uniforms, and samplers. There are however a few extra variables defined by GLSL prefixed with <code>gl_</code> that give us an extra means to gather and/or write data. We've already seen two of them in the chapters so far: <var>gl_Position</var> that is the output vector of the vertex shader, and the fragment shader's <var>gl_FragCoord</var>.  
     15 </p>
     16 
     17 <p>
     18   We'll discuss a few interesting built-in input and output variables that are built-in in GLSL and explain how they may benefit us. Note that we won't discuss all built-in variables that exist in GLSL so if you want to see all built-in variables you can check OpenGL's <a href="https://www.khronos.org/opengl/wiki/Built-in_Variable_(GLSL)" target="_blank">wiki</a>.
     19 </p>
     20 
     21 <h2>Vertex shader variables</h2>
     22 <p>
     23   We've already seen <var>gl_Position</var> which is the clip-space output position vector of the vertex shader. Setting <var>gl_Position</var> in the vertex shader is a strict requirement if you want to render anything on the screen. Nothing we haven't seen before.
     24 </p>
     25 
     26 <h3>gl_PointSize</h3>
     27 <p>
     28   One of the render primitives we're able to choose from is <var>GL_POINTS</var> in which case each single vertex is a primitive and rendered as a point. It is possible to set the size of the points being rendered via OpenGL's <fun>glPointSize</fun> function, but we can also influence this value in the vertex shader.
     29 </p>
     30 
     31 <p>
     32   One output variable defined by GLSL is called <var>gl_PointSize</var> that is a <fun>float</fun> variable where you can set the point's width and height in pixels. By setting the point's size in the vertex shader we get per-vertex control over this point's dimensions.
     33 </p>
     34 
     35 <p>
     36   Influencing the point sizes in the vertex shader is disabled by default, but if you want to enable this you'll have to enable OpenGL's <var>GL_PROGRAM_POINT_SIZE</var>:
     37 </p>
     38 
     39 <pre><code>
     40 <function id='60'>glEnable</function>(GL_PROGRAM_POINT_SIZE);  
     41 </code></pre>
     42 
     43 <p>
     44   A simple example of influencing point sizes is by setting the point size equal to the clip-space position's z value which is equal to the vertex's distance to the viewer. The point size should then increase the further we are from the vertices as the viewer.
     45 </p>
     46 
     47 <pre><code>
     48 void main()
     49 {
     50     gl_Position = projection * view * model * vec4(aPos, 1.0);    
     51     gl_PointSize = gl_Position.z;    
     52 }  
     53 </code></pre>
     54 
     55 <p>
     56   The result is that the points we've drawn are rendered larger the more we move away from them:
     57 </p>
     58 
     59 <img src="/img/advanced/advanced_glsl_pointsize.png" class="clean" alt="Points in OpenGL drawn with their gl_PointSize influenced in the vertex shader"/>
     60 
     61 <p>
     62   You can imagine that varying the point size per vertex is interesting for techniques like particle generation.
     63 </p>
     64 
     65 <h3>gl_VertexID</h3>
     66 <p>
     67   The <var>gl_Position</var> and <var>gl_PointSize</var> are <em>output variables</em> since their value is read as output from the vertex shader; we can influence the result by writing to them. The vertex shader also gives us an interesting <em>input variable</em>, that we can only read from, called <var>gl_VertexID</var>.
     68 </p>
     69 
     70 <p>
     71   The integer variable <var>gl_VertexID</var> holds the current ID of the vertex we're drawing. When doing <em>indexed rendering</em> (with <fun><function id='2'>glDrawElements</function></fun>) this variable holds the current index of the vertex we're drawing. When drawing without indices (via <fun><function id='1'>glDrawArrays</function></fun>) this variable holds the number of the currently processed vertex since the start of the render call.
     72 </p>
     73 
     74 <h2>Fragment shader variables</h2>
     75 <p>
     76   Within the fragment shader we also have access to some interesting variables. GLSL gives us two interesting input variables called <var>gl_FragCoord</var> and <var>gl_FrontFacing</var>.
     77 </p>
     78 
     79 <h3>gl_FragCoord</h3>
     80 <p>
     81   We've seen the <var>gl_FragCoord</var> a couple of times before during the discussion of depth testing, because the <code>z</code> component of the <var>gl_FragCoord</var> vector is equal to the depth value of that particular fragment. However, we can also use the x and y component of that vector for some interesting effects.
     82 </p>
     83 
     84 <p>
     85   The <var>gl_FragCoord</var>'s <code>x</code> and <code>y</code> component are the window- or screen-space coordinates of the fragment, originating from the bottom-left of the window. We specified a render window of 800x600 with <fun><function id='22'>glViewport</function></fun> so the screen-space coordinates of the fragment will have <code>x</code> values between 0 and 800, and <code>y</code> values between 0 and 600.
     86 </p>
     87 
     88 <p>
     89   Using the fragment shader we could calculate a different color value based on the screen coordinate of the fragment. A common usage for the <var>gl_FragCoord</var> variable is for comparing visual output of different fragment calculations, as usually seen in tech demos. We could for example split the screen in two by rendering one output to the left side of the window and another output to the right side of the window. An example fragment shader that outputs a different color based on the fragment's screen coordinates is given below:
     90 </p>
     91 
     92 <pre><code>
     93 void main()
     94 {             
     95     if(gl_FragCoord.x &lt; 400)
     96         FragColor = vec4(1.0, 0.0, 0.0, 1.0);
     97     else
     98         FragColor = vec4(0.0, 1.0, 0.0, 1.0);        
     99 }  
    100 </code></pre>
    101 
    102 <p>
    103   Because the width of the window is equal to 800, whenever a pixel's x-coordinate is less than 400 it must be at the left side of the window and we'll give that fragment a different color.
    104 </p>
    105 
    106 <img src="/img/advanced/advanced_glsl_fragcoord.png" class="clean" alt="Cube in OpenGL drawn with 2 colors using gl_FragCoord"/>
    107 
    108 <p>
    109   We can now calculate two completely different fragment shader results and display each of them on a different side of the window. This is great for testing out different lighting techniques for example.
    110 </p>
    111 
    112 <h3>gl_FrontFacing</h3>
    113 <p>
    114   Another interesting input variable in the fragment shader is the <var>gl_FrontFacing</var> variable. In the <a href="https://learnopengl.com/Advanced-OpenGL/Face-culling" target="_blank">face culling</a> chapter we mentioned that OpenGL is able to figure out if a face is a front or back face due to the winding order of the vertices. The <var>gl_FrontFacing</var> variable tells us if the current fragment is part of a front-facing or a back-facing face. We could, for example, decide to output different colors for all back faces.
    115 </p>
    116 
    117 <p>
    118   The <var>gl_FrontFacing</var> variable is a <fun>bool</fun> that is <code>true</code> if the fragment is part of a front face and <code>false</code> otherwise. We could create a cube this way with a different texture on the inside than on the outside:
    119 </p>
    120 
    121 <pre><code>
    122 #version 330 core
    123 out vec4 FragColor;
    124   
    125 in vec2 TexCoords;
    126 
    127 uniform sampler2D frontTexture;
    128 uniform sampler2D backTexture;
    129 
    130 void main()
    131 {             
    132     if(gl_FrontFacing)
    133         FragColor = texture(frontTexture, TexCoords);
    134     else
    135         FragColor = texture(backTexture, TexCoords);
    136 }  
    137 </code></pre>
    138 
    139 <p>
    140   If we take a peek inside the container we can now see a different texture being used.
    141 </p>
    142 
    143 <img src="/img/advanced/advanced_glsl_frontfacing.png" class="clean" alt="OpenGL container using two different textures via gl_FrontFacing"/>
    144 
    145 <p>
    146   Note that if you enabled face culling you won't be able to see any faces inside the container and using <var>gl_FrontFacing</var> would then be pointless.
    147 </p>
    148 
    149 <h3>gl_FragDepth</h3>
    150 <p>
    151   The input variable <var>gl_FragCoord</var> is an input variable that allows us to read screen-space coordinates and get the depth value of the current fragment, but it is a <def>read-only</def> variable. We can't influence the screen-space coordinates of the fragment, but it is possible to set the depth value of the fragment. GLSL gives us an output variable called <var>gl_FragDepth</var> that we can use to manually set the depth value of the fragment within the shader.
    152 </p>
    153 
    154 <p>
    155   To set the depth value in the shader we write any value between <code>0.0</code> and <code>1.0</code> to the output variable:
    156 </p>
    157 
    158 <pre><code>
    159 gl_FragDepth = 0.0; // this fragment now has a depth value of 0.0
    160 </code></pre>
    161 
    162 <p>
    163   If the shader does not write anything to <var>gl_FragDepth</var>, the variable will automatically take its value from <code>gl_FragCoord.z</code>.
    164 </p>
    165 
    166 <p>
    167   Setting the depth value manually has a major disadvantage however. That is because OpenGL disables <def>early depth testing</def> (as discussed in the <a href="https://learnopengl.com/Advanced-OpenGL/Depth-testing" target="_blank">depth testing</a> chapter) as soon as we write to <var>gl_FragDepth</var> in the fragment shader. It is disabled, because OpenGL cannot know what depth value the fragment will have <em>before</em> we run the fragment shader, since the fragment shader may actually change this value.
    168 </p>
    169 
    170 <p>
    171   By writing to <var>gl_FragDepth</var> you should take this performance penalty into consideration. From OpenGL 4.2 however, we can still sort of mediate between both sides by redeclaring the <var>gl_FragDepth</var> variable at the top of the fragment shader with a <def>depth condition</def>:
    172 </p>
    173 
    174 <pre><code>
    175 layout (depth_&ltcondition&gt;) out float gl_FragDepth;
    176 </code></pre>
    177 
    178 <p>
    179   This <code>condition</code> can take the following values:
    180 </p>
    181 
    182 <table>
    183   <tr>
    184   	<th>Condition</th>
    185   	<th>Description</th>
    186   </tr>  
    187   <tr>
    188     <td><code>any</code></td>
    189  	<td>The default value. Early depth testing is disabled.</td>
    190   </tr>
    191   <tr>
    192     <td><code>greater</code></td>
    193     <td>You can only make the depth value larger compared to <code>gl_FragCoord.z</code>.</td>
    194   </tr>
    195   <tr>
    196     <td><code>less</code></td>
    197  	<td>You can only make the depth value smaller compared to <code>gl_FragCoord.z</code>.</td>
    198   </tr>
    199   <tr>
    200     <td><code>unchanged</code></td>
    201     <td>If you write to <code>gl_FragDepth</code>, you will write exactly <code>gl_FragCoord.z</code>.</td>
    202   </tr>
    203 </table>
    204 
    205 <p>
    206   By specifying <code>greater</code> or <code>less</code> as the depth condition, OpenGL can make the assumption that you'll only write depth values larger or smaller than the fragment's depth value. This way OpenGL is still able to do early depth testing when the depth buffer value is part of the other direction of <code>gl_FragCoord.z</code>.  
    207 </p>
    208 
    209 <p>
    210   An example of where we increase the depth value in the fragment shader, but still want to preserve some of the early depth testing is shown in the fragment shader below:
    211 </p>
    212 
    213 <pre><code>
    214 #version 420 core // note the GLSL version!
    215 out vec4 FragColor;
    216 layout (depth_greater) out float gl_FragDepth;
    217 
    218 void main()
    219 {             
    220     FragColor = vec4(1.0);
    221     gl_FragDepth = gl_FragCoord.z + 0.1;
    222 }  
    223 </code></pre>
    224 
    225 <p>
    226   Do note that this feature is only available from OpenGL version 4.2 or higher.
    227 </p>
    228 
    229 <h1>Interface blocks</h1>
    230 <p>
    231   So far, every time we sent data from the vertex to the fragment shader we declared several matching input/output variables. Declaring these one at a time is the easiest way to send data from one shader to another, but as applications become larger you probably want to send more than a few variables over.
    232 </p>
    233 
    234 <p>
    235   To help us organize these variables GLSL offers us something called <def>interface blocks</def> that allows us to group variables together. The declaration of such an interface block looks a lot like a <fun>struct</fun> declaration, except that it is now declared using an <fun>in</fun> or <fun>out</fun> keyword based on the block being an input or an output block.
    236 </p>
    237 
    238 <pre><code>
    239 #version 330 core
    240 layout (location = 0) in vec3 aPos;
    241 layout (location = 1) in vec2 aTexCoords;
    242 
    243 uniform mat4 model;
    244 uniform mat4 view;
    245 uniform mat4 projection;
    246 
    247 out VS_OUT
    248 {
    249     vec2 TexCoords;
    250 } vs_out;
    251 
    252 void main()
    253 {
    254     gl_Position = projection * view * model * vec4(aPos, 1.0);    
    255     vs_out.TexCoords = aTexCoords;
    256 }  
    257 </code></pre>
    258 
    259 <p>
    260   This time we declared an interface block called <var>vs_out</var> that groups together all the output variables we want to send to the next shader. This is kind of a trivial example, but you can imagine that this helps organize your shaders' inputs/outputs. It is also useful when we want to group shader input/output into arrays as we'll see in the <a href="https://learnopengl.com/Advanced-OpenGL/Geometry-Shader" target="_blank">next</a> chapter about geometry shaders.
    261 </p>
    262 
    263 <p>
    264   Then we also need to declare an input interface block in the next shader which is the fragment shader. The <def>block name</def> (<fun>VS_OUT</fun>) should be the same in the fragment shader, but the <def>instance name</def> (<var>vs_out</var> as used in the vertex shader) can be anything we like - avoiding confusing names like <var>vs_out</var> for a fragment struct containing input values.
    265 </p>
    266 
    267 <pre><code>
    268 #version 330 core
    269 out vec4 FragColor;
    270 
    271 in VS_OUT
    272 {
    273     vec2 TexCoords;
    274 } fs_in;
    275 
    276 uniform sampler2D texture;
    277 
    278 void main()
    279 {             
    280     FragColor = texture(texture, fs_in.TexCoords);   
    281 } 
    282 </code></pre>
    283 
    284 <p>
    285   As long as both interface block names are equal, their corresponding input and output is matched together. This is another useful feature that helps organize your code and proves useful when crossing between certain shader stages like the geometry shader.
    286 </p>
    287 
    288 <h1>Uniform buffer objects</h1>
    289 <p>
    290   We've been using OpenGL for quite a while now and learned some pretty cool tricks, but also a few annoyances. For example, when using more than one shader we continuously have to set uniform variables where most of them are exactly the same for each shader.
    291 </p>
    292 
    293 <p>
    294   OpenGL gives us a tool called <def>uniform buffer objects</def> that allow us to declare a set of <em>global</em> uniform variables that remain the same over any number of shader programs. When using uniform buffer objects we set the relevant uniforms only <strong>once</strong> in fixed GPU memory. We do still have to manually set the uniforms that are unique per shader. Creating and configuring a uniform buffer object requires a bit of work though.
    295 </p>
    296 
    297 <p>
    298   Because a uniform buffer object is a buffer like any other buffer we can create one via <fun><function id='12'>glGenBuffers</function></fun>, bind it to the <var>GL_UNIFORM_BUFFER</var> buffer target and store all the relevant uniform data into the buffer. There are certain rules as to how the data for uniform buffer objects should be stored and we'll get to that later. First, we'll take a simple vertex shader and store our <var>projection</var> and <var>view</var> matrix in a so called <def>uniform block</def>:
    299 </p>
    300 
    301 <pre><code>
    302 #version 330 core
    303 layout (location = 0) in vec3 aPos;
    304 
    305 layout (std140) uniform Matrices
    306 {
    307     mat4 projection;
    308     mat4 view;
    309 };
    310 
    311 uniform mat4 model;
    312 
    313 void main()
    314 {
    315     gl_Position = projection * view * model * vec4(aPos, 1.0);
    316 }  
    317 </code></pre>
    318 
    319 <p>
    320   In most of our samples we set a projection and view uniform matrix every frame for each shader we're using. This is a perfect example of where uniform buffer objects become useful since now we only have to store these matrices once. 
    321 </p>
    322 
    323 <p>
    324   Here we declared a uniform block called <var>Matrices</var> that stores two 4x4 matrices. Variables in a uniform block can be directly accessed without the block name as a prefix. Then we store these matrix values in a buffer somewhere in the OpenGL code and each shader that declares this uniform block has access to the matrices.
    325 </p> 
    326 
    327 <p>
    328   You're probably wondering right now what the <code>layout</code> <code>(std140)</code> statement means. What this says is that the currently defined uniform block uses a specific memory layout for its content; this statement sets the <def>uniform block layout</def>.
    329 </p>
    330 
    331 <h2>Uniform block layout</h2>
    332 <p>
    333   The content of a uniform block is stored in a buffer object, which is effectively nothing more than a reserved piece of global GPU memory. Because this piece of memory holds no information on what kind of data it holds, we need to tell OpenGL what parts of the memory correspond to which uniform variables in the shader. 
    334 </p>
    335 
    336 <p>
    337   Imagine the following uniform block in a shader:
    338 </p>
    339 
    340 <pre><code>
    341 layout (std140) uniform ExampleBlock
    342 {
    343     float value;
    344     vec3  vector;
    345     mat4  matrix;
    346     float values[3];
    347     bool  boolean;
    348     int   integer;
    349 };  
    350 </code></pre>
    351 
    352 <p>
    353   What we want to know is the size (in bytes) and the offset (from the start of the block) of each of these variables so we can place them in the buffer in their respective order. The size of each of the elements is clearly stated in OpenGL and directly corresponds to C++ data types; vectors and matrices being (large) arrays of floats. What OpenGL doesn't clearly state is the <def>spacing</def> between the variables. This allows the hardware to position or pad variables as it sees fit. The hardware is able to place a <fun>vec3</fun> adjacent to a <fun>float</fun> for example. Not all hardware can handle this and pads the <fun>vec3</fun> to an array of 4 floats before appending the <fun>float</fun>. A great feature, but inconvenient for us.
    354 </p>
    355 
    356 <p>
    357   By default, GLSL uses a uniform memory layout called a <def>shared</def> layout - shared because once the offsets are defined by the hardware, they are consistently <em>shared</em> between multiple programs. With a shared layout GLSL is allowed to reposition the uniform variables for optimization as long as the variables' order remains intact. Because we don't know at what offset each uniform variable will be we don't know how to precisely fill our uniform buffer. We can query this information with functions like <fun>glGetUniformIndices</fun>, but that's not the approach we're going to take in this chapter.
    358 </p>
    359 
    360 <p>
    361   While a shared layout gives us some space-saving optimizations, we'd need to query the offset for each uniform variable which translates to a lot of work. The general practice however is to not use the shared layout, but to use the <def>std140</def> layout. The std140 layout <strong>explicitly</strong> states the memory layout for each variable type by standardizing their respective offsets governed by a set of rules. Since this is standardized we can manually figure out the offsets for each variable. 
    362 </p>
    363 
    364 <p>
    365   Each variable has a <def>base alignment</def> equal to the space a variable takes (including padding) within a uniform block using the std140 layout rules. For each variable, we calculate its <def>aligned offset</def>: the byte offset of a variable from the start of the block. The aligned byte offset of a variable <strong>must</strong> be equal to a multiple of its base alignment. This is a bit of a mouthful, but we'll get to see some examples soon enough to clear things up.
    366 </p>
    367 
    368 <p>
    369   The exact layout rules can be found at OpenGL's uniform buffer specification <a href="http://www.opengl.org/registry/specs/ARB/uniform_buffer_object.txt" target="_blank">here</a>, but we'll list the most common rules below. Each variable type in GLSL such as <fun>int</fun>, <fun>float</fun> and <fun>bool</fun> are defined to be four-byte quantities with each entity of 4 bytes represented as <code>N</code>. 
    370 </p>
    371 
    372 <table>
    373   <tr>
    374     <th>Type</th>
    375     <th>Layout rule</th>
    376   </tr>
    377   
    378   <tr>
    379     <td>Scalar e.g. <fun>int</fun> or <fun>bool</fun></td>
    380     <td>Each scalar has a base alignment of N.</td>
    381   </tr>
    382   <tr>
    383     <td>Vector</td>
    384     <td>Either 2N or 4N. This means that a <fun>vec3</fun> has a base alignment of 4N.</td>
    385   </tr>
    386   <tr>
    387     <td>Array of scalars or vectors</td>
    388     <td>Each element has a base alignment equal to that of a <fun>vec4</fun>.</td>
    389   </tr>
    390   <tr>
    391     <td>Matrices</td>
    392     <td>Stored as a large array of column vectors, where each of those vectors has a base alignment of <fun>vec4</fun>.</td>
    393   </tr>
    394   <tr>
    395     <td>Struct</td>
    396     <td>Equal to the computed size of its elements according to the previous rules, but padded to a multiple of the size of a <fun>vec4</fun>.</td>
    397   </tr>    
    398 </table>
    399 
    400 <p>
    401   Like most of OpenGL's specifications it's easier to understand with an example. We're taking the uniform block called <var>ExampleBlock</var> we introduced earlier and calculate the aligned offset for each of its members using the std140 layout:
    402 </p>
    403 
    404 <pre><code>
    405 layout (std140) uniform ExampleBlock
    406 {
    407                      // base alignment  // aligned offset
    408     float value;     // 4               // 0 
    409     vec3 vector;     // 16              // 16  (offset must be multiple of 16 so 4->16)
    410     mat4 matrix;     // 16              // 32  (column 0)
    411                      // 16              // 48  (column 1)
    412                      // 16              // 64  (column 2)
    413                      // 16              // 80  (column 3)
    414     float values[3]; // 16              // 96  (values[0])
    415                      // 16              // 112 (values[1])
    416                      // 16              // 128 (values[2])
    417     bool boolean;    // 4               // 144
    418     int integer;     // 4               // 148
    419 }; 
    420 </code></pre>
    421 
    422 <p>
    423   As an exercise, try to calculate the offset values yourself and compare them to this table. With these calculated offset values, based on the rules of the std140 layout, we can fill the buffer with data at the appropriate offsets using functions like <fun><function id='90'>glBufferSubData</function></fun>. While not the most efficient, the std140 layout does guarantee us that the memory layout remains the same over each program that declared this uniform block.
    424 </p>
    425 
    426 <p>
    427   By adding the statement <code>layout</code> <code>(std140)</code> in the definition of the uniform block we tell OpenGL that this uniform block uses the std140 layout. There are two other layouts to choose from that require us to query each offset before filling the buffers. We've already seen the <code>shared</code> layout, with the other remaining layout being <code>packed</code>. When using the <code>packed</code> layout, there is no guarantee that the layout remains the same between programs (not shared) because it allows the compiler to optimize uniform variables away from the uniform block which may differ per shader.
    428 </p>
    429 
    430 <h2>Using uniform buffers</h2>
    431 <p>
    432   We've defined uniform blocks and specified their memory layout, but we haven't discussed how to actually use them yet.
    433 </p>
    434 
    435 <p>
    436   First, we need to create a uniform buffer object which is done via the familiar <fun><function id='12'>glGenBuffers</function></fun>. Once we have a buffer object we bind it to the <var>GL_UNIFORM_BUFFER</var> target and allocate enough memory by calling <fun><function id='31'>glBufferData</function></fun>.
    437 </p>
    438 
    439 <pre><code>
    440 unsigned int uboExampleBlock;
    441 <function id='12'>glGenBuffers</function>(1, &uboExampleBlock);
    442 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, uboExampleBlock);
    443 <function id='31'>glBufferData</function>(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // allocate 152 bytes of memory
    444 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, 0);
    445 </code></pre>
    446 
    447 <p>
    448   Now whenever we want to update or insert data into the buffer, we bind to <var>uboExampleBlock</var> and use <fun><function id='90'>glBufferSubData</function></fun> to update its memory. We only have to update this uniform buffer once, and all shaders that use this buffer now use its updated data. But, how does OpenGL know what uniform buffers correspond to which uniform blocks?
    449 </p>
    450 
    451 <p>
    452   In the OpenGL context there is a number of <def>binding points</def> defined where we can link a uniform buffer to. Once we created a uniform buffer we link it to one of those binding points and we also link the uniform block in the shader to the same binding point, effectively linking them together. The following diagram illustrates this:
    453 </p>
    454 
    455 <img src="/img/advanced/advanced_glsl_binding_points.png" class="clean" alt="Diagram of uniform binding points in OpenGL"/>
    456 
    457 <p>
    458   As you can see we can bind multiple uniform buffers to different binding points. Because shader A and shader B both have a uniform block linked to the same binding point <code>0</code>, their uniform blocks share the same uniform data found in <var>uboMatrices</var>; a requirement being that both shaders defined the same <var>Matrices</var> uniform block.
    459 </p>
    460 
    461 <p>
    462   To set a shader uniform block to a specific binding point we call <fun><function id='95'><function id='44'>glUniform</function>BlockBinding</function></fun> that takes a program object, a uniform block index, and the binding point to link to. The <def>uniform block index</def> is a location index of the defined uniform block in the shader. This can be retrieved via a call to <fun><function id='94'>glGetUniformBlockIndex</function></fun> that accepts a program object and the name of the uniform block. We can set the <var>Lights</var> uniform block from the diagram to binding point <code>2</code> as follows:
    463 </p>
    464 
    465 <pre><code>
    466 unsigned int lights_index = <function id='94'>glGetUniformBlockIndex</function>(shaderA.ID, "Lights");   
    467 <function id='95'><function id='44'>glUniform</function>BlockBinding</function>(shaderA.ID, lights_index, 2);
    468 </code></pre>
    469 
    470 <p>
    471   Note that we have to repeat this process for <strong>each</strong> shader.
    472 </p>
    473 
    474 <note>
    475   From OpenGL version 4.2 and onwards it is also possible to store the binding point of a uniform block explicitly in the shader by adding another layout specifier, saving us the calls to <fun><function id='94'>glGetUniformBlockIndex</function></fun> and <fun><function id='95'><function id='44'>glUniform</function>BlockBinding</function></fun>. The following code sets the binding point of the <var>Lights</var> uniform block explicitly:	
    476 <pre class="cpp"><code>
    477 layout(std140, binding = 2) uniform Lights { ... };
    478 </code></pre>  
    479 </note>
    480 
    481 <p>
    482   Then we also need to bind the uniform buffer object to the same binding point and this can be accomplished with either <fun><function id='96'><function id='32'>glBindBuffer</function>Base</function></fun> or <fun><function id='97'><function id='32'>glBindBuffer</function>Range</function></fun>.
    483 </p>
    484 
    485 <pre><code>
    486 <function id='96'><function id='32'>glBindBuffer</function>Base</function>(GL_UNIFORM_BUFFER, 2, uboExampleBlock); 
    487 // or
    488 <function id='97'><function id='32'>glBindBuffer</function>Range</function>(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);
    489 </code></pre>
    490 
    491 <p>
    492   The function <fun><function id='96'><function id='32'>glBindbuffer</function>Base</function></fun> expects a target, a binding point index and a uniform buffer object. This function links <var>uboExampleBlock</var> to binding point <code>2</code>; from this point on, both sides of the binding point are linked. You can also use <fun><function id='97'><function id='32'>glBindBuffer</function>Range</function></fun> that expects an extra offset and size parameter - this way you can bind only a specific range of the uniform buffer to a binding point. Using <fun><function id='97'><function id='32'>glBindBuffer</function>Range</function></fun> you could have multiple different uniform blocks linked to a single uniform buffer object.
    493 </p>
    494 
    495 <p>
    496   Now that everything is set up, we can start adding data to the uniform buffer. We could add all the data as a single byte array, or update parts of the buffer whenever we feel like it using  <fun><function id='90'>glBufferSubData</function></fun>. To update the uniform variable <var>boolean</var> we could update the uniform buffer object as follows:
    497 </p>
    498 
    499 <pre><code>
    500 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, uboExampleBlock);
    501 int b = true; // bools in GLSL are represented as 4 bytes, so we store it in an integer
    502 <function id='90'>glBufferSubData</function>(GL_UNIFORM_BUFFER, 144, 4, &b); 
    503 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, 0);
    504 </code></pre>
    505 
    506 <p>
    507   And the same procedure applies for all the other uniform variables inside the uniform block, but with different range arguments.
    508 </p>
    509 
    510 <h2>A simple example</h2>
    511 <p>
    512   So let's demonstrate a real example of uniform buffer objects. If we look back at all the previous code samples we've continually been using 3 matrices: the projection, view and model matrix. Of all those matrices, only the model matrix changes frequently. If we have multiple shaders that use this same set of matrices, we'd probably be better off using uniform buffer objects.
    513 </p>
    514 
    515 <p>
    516   We're going to store the projection and view matrix in a uniform block called <var>Matrices</var>. We're not going to store the model matrix in there since the model matrix tends to change frequently between shaders, so we wouldn't really benefit from uniform buffer objects.
    517 </p>
    518 
    519 <pre><code>
    520 #version 330 core
    521 layout (location = 0) in vec3 aPos;
    522 
    523 layout (std140) uniform Matrices
    524 {
    525     mat4 projection;
    526     mat4 view;
    527 };
    528 uniform mat4 model;
    529 
    530 void main()
    531 {
    532     gl_Position = projection * view * model * vec4(aPos, 1.0);
    533 }  
    534 </code></pre>
    535 
    536 <p>
    537   Not much going on here, except that we now use a uniform block with a std140 layout. What we're going to do in our sample application is display 4 cubes where each cube is displayed with a different shader program. Each of the 4 shader programs uses the same vertex shader, but has a unique fragment shader that only outputs a single color that differs per shader.
    538 </p>
    539 
    540 <p>
    541   First, we set the uniform block of the vertex shaders equal to binding point <code>0</code>. Note that we have to do this for each shader:
    542 </p>
    543 
    544 <pre><code>
    545 unsigned int uniformBlockIndexRed    = <function id='94'>glGetUniformBlockIndex</function>(shaderRed.ID, "Matrices");
    546 unsigned int uniformBlockIndexGreen  = <function id='94'>glGetUniformBlockIndex</function>(shaderGreen.ID, "Matrices");
    547 unsigned int uniformBlockIndexBlue   = <function id='94'>glGetUniformBlockIndex</function>(shaderBlue.ID, "Matrices");
    548 unsigned int uniformBlockIndexYellow = <function id='94'>glGetUniformBlockIndex</function>(shaderYellow.ID, "Matrices");  
    549   
    550 <function id='95'><function id='44'>glUniform</function>BlockBinding</function>(shaderRed.ID,    uniformBlockIndexRed, 0);
    551 <function id='95'><function id='44'>glUniform</function>BlockBinding</function>(shaderGreen.ID,  uniformBlockIndexGreen, 0);
    552 <function id='95'><function id='44'>glUniform</function>BlockBinding</function>(shaderBlue.ID,   uniformBlockIndexBlue, 0);
    553 <function id='95'><function id='44'>glUniform</function>BlockBinding</function>(shaderYellow.ID, uniformBlockIndexYellow, 0);
    554 </code></pre>
    555 
    556 <p>
    557   Next we create the actual uniform buffer object and bind that buffer to binding point <code>0</code>:
    558 </p>
    559 
    560 <pre><code>
    561 unsigned int uboMatrices
    562 <function id='12'>glGenBuffers</function>(1, &uboMatrices);
    563   
    564 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, uboMatrices);
    565 <function id='31'>glBufferData</function>(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW);
    566 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, 0);
    567   
    568 <function id='97'><function id='32'>glBindBuffer</function>Range</function>(GL_UNIFORM_BUFFER, 0, uboMatrices, 0, 2 * sizeof(glm::mat4));
    569 </code></pre>
    570 
    571 <p>
    572   First we allocate enough memory for our buffer which is equal to 2 times the size of <fun>glm::mat4</fun>. The size of GLM's matrix types correspond directly to <fun>mat4</fun> in GLSL. Then we link a specific range of the buffer, in this case the entire buffer, to binding point <code>0</code>.
    573 </p>
    574 
    575 <p>
    576   Now all that's left to do is fill the buffer. If we keep the <em>field of view</em> value constant of the projection matrix (so no more camera zoom) we only have to update it once in our application - this means we only have to insert this into the buffer only once as well. Because we already allocated enough memory in the buffer object we can use <fun><function id='90'>glBufferSubData</function></fun> to store the projection matrix before we enter the render loop:
    577 </p>
    578 
    579 <pre><code>
    580 glm::mat4 projection = <function id='58'>glm::perspective</function>(<function id='63'>glm::radians</function>(45.0f), (float)width/(float)height, 0.1f, 100.0f);
    581 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, uboMatrices);
    582 <function id='90'>glBufferSubData</function>(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));
    583 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, 0);  
    584 </code></pre>
    585 
    586 <p>
    587   Here we store the first half of the uniform buffer with the projection matrix. Then before we render the objects each frame we update the second half of the buffer with the view matrix:
    588 </p>
    589 
    590 <pre><code>
    591 glm::mat4 view = camera.GetViewMatrix();	       
    592 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, uboMatrices);
    593 <function id='90'>glBufferSubData</function>(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
    594 <function id='32'>glBindBuffer</function>(GL_UNIFORM_BUFFER, 0);  
    595 </code></pre>
    596 
    597 <p>
    598   And that's it for uniform buffer objects. Each vertex shader that contains a <var>Matrices</var> uniform block will now contain the data stored in <var>uboMatrices</var>. So if we now were to draw 4 cubes using 4 different shaders, their projection and view matrix should be the same:
    599 </p>
    600 
    601 <pre><code>
    602 <function id='27'>glBindVertexArray</function>(cubeVAO);
    603 shaderRed.use();
    604 glm::mat4 model = glm::mat4(1.0f);
    605 model = <function id='55'>glm::translate</function>(model, glm::vec3(-0.75f, 0.75f, 0.0f));	// move top-left
    606 shaderRed.setMat4("model", model);
    607 <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 36);        
    608 // ... draw Green Cube
    609 // ... draw Blue Cube
    610 // ... draw Yellow Cube	  
    611 </code></pre>
    612 
    613 <p>
    614   The only uniform we still need to set is the <var>model</var> uniform. Using uniform buffer objects in a scenario like this saves us from quite a few uniform calls per shader. The result looks something like this:
    615 </p>
    616 
    617 <img src="/img/advanced/advanced_glsl_uniform_buffer_objects.png" class="clean" alt="Image of 4 cubes with their uniforms set via OpenGL's uniform buffer objects"/>
    618 
    619 <p>
    620   Each of the cubes is moved to one side of the window by translating the model matrix and, thanks to the different fragment shaders, their colors differ per object. This is a relatively simple scenario of where we could use uniform buffer objects, but any large rendering application can have over hundreds of shader programs active which is where uniform buffer objects really start to shine.
    621 </p>
    622 
    623 <p>
    624   You can find the full source code of the uniform example application <a href="/code_viewer_gh.php?code=src/4.advanced_opengl/8.advanced_glsl_ubo/advanced_glsl_ubo.cpp" target="_blank">here</a>.
    625 </p>
    626 
    627 <p>
    628   Uniform buffer objects have several advantages over single uniforms. First, setting a lot of uniforms at once is faster than setting multiple uniforms one at a time. Second, if you want to change the same uniform over several shaders, it is much easier to change a uniform once in a uniform buffer. One last advantage that is not immediately apparent is that you can use a lot more uniforms in shaders using uniform buffer objects. OpenGL has a limit to how much uniform data it can handle which can be queried with <var>GL_MAX_VERTEX_UNIFORM_COMPONENTS</var>. When using uniform buffer objects, this limit is much higher. So whenever you reach a maximum number of uniforms (when doing skeletal animation for example) there's always uniform buffer objects.
    629 </p>       
    630 
    631     </div>
    632