LearnOpenGL

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

Basic-Lighting.html (38086B)


      1 <!DOCTYPE html>
      2 <html lang="ja"> 
      3 <head>
      4     <meta charset="utf-8"/>
      5     <title>LearnOpenGL</title>
      6     <link rel="shortcut icon" type="image/ico" href="/favicon.ico"  />
      7 	<link rel="stylesheet" href="../static/style.css" />
      8 	<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"> </script>
      9 	<script src="/static/functions.js"></script>
     10 </head>
     11 <body>
     12 	<nav>
     13 <ol>
     14 	<li id="Introduction">
     15 		<a href="https://learnopengl.com/Introduction">はじめに</a>
     16 	</li>
     17 	<li id="Getting-started">
     18 		<span class="closed">入門</span>
     19 		<ol>
     20 			<li id="Getting-started/OpenGL">
     21 				<a href="https://learnopengl.com/Getting-started/OpenGL">OpenGL </a>
     22 			</li>
     23 			<li id="Getting-started/Creating-a-window">
     24 				<a href="https://learnopengl.com/Getting-started/Creating-a-window">ウィンドウの作成</a>
     25 			</li>
     26 			<li id="Getting-started/Hello-Window">
     27 				<a href="https://learnopengl.com/Getting-started/Hello-Window">最初のウィンドウ</a>
     28 			</li>
     29 			<li id="Getting-started/Hello-Triangle">
     30 				<a href="https://learnopengl.com/Getting-started/Hello-Triangle">最初の三角形</a>
     31 			</li>
     32 			<li id="Getting-started/Shaders">
     33 				<a href="https://learnopengl.com/Getting-started/Shaders">シェーダー</a>
     34 			</li>
     35 			<li id="Getting-started/Textures">
     36 				<a href="https://learnopengl.com/Getting-started/Textures">テクスチャ</a>
     37 			</li>
     38 			<li id="Getting-started/Transformations">
     39 				<a href="https://learnopengl.com/Getting-started/Transformations">座標変換</a>
     40 			</li>
     41 			<li id="Getting-started/Coordinate-Systems">
     42 				<a href="https://learnopengl.com/Getting-started/Coordinate-Systems">座標系</a>
     43 			</li>
     44 			<li id="Getting-started/Camera">
     45 				<a href="https://learnopengl.com/Getting-started/Camera">カメラ</a>
     46 			</li>
     47 			<li id="Getting-started/Review">
     48 				<a href="https://learnopengl.com/Getting-started/Review">まとめ</a>
     49 			</li>
     50 		</ol>
     51 	</li>
     52 	<li id="Lighting">
     53 		<span class="closed">Lighting </span>
     54 		<ol>
     55 			<li id="Lighting/Colors">
     56 				<a href="https://learnopengl.com/Lighting/Colors">Colors </a>
     57 			</li>
     58 			<li id="Lighting/Basic-Lighting">
     59 				<a href="https://learnopengl.com/Lighting/Basic-Lighting">Basic Lighting </a>
     60 			</li>
     61 			<li id="Lighting/Materials">
     62 				<a href="https://learnopengl.com/Lighting/Materials">Materials </a>
     63 			</li>
     64 			<li id="Lighting/Lighting-maps">
     65 				<a href="https://learnopengl.com/Lighting/Lighting-maps">Lighting maps </a>
     66 			</li>
     67 			<li id="Lighting/Light-casters">
     68 				<a href="https://learnopengl.com/Lighting/Light-casters">Light casters </a>
     69 			</li>
     70 			<li id="Lighting/Multiple-lights">
     71 				<a href="https://learnopengl.com/Lighting/Multiple-lights">Multiple lights </a>
     72 			</li>
     73 			<li id="Lighting/Review">
     74 				<a href="https://learnopengl.com/Lighting/Review">Review </a>
     75 			</li>
     76 		</ol>
     77 	</li>
     78 	<li id="Model-Loading">
     79 		<span class="closed">Model Loading </span>
     80 		<ol>
     81 			<li id="Model-Loading/Assimp">
     82 				<a href="https://learnopengl.com/Model-Loading/Assimp">Assimp </a>
     83 			</li>
     84 			<li id="Model-Loading/Mesh">
     85 				<a href="https://learnopengl.com/Model-Loading/Mesh">Mesh </a>
     86 			</li>
     87 			<li id="Model-Loading/Model">
     88 				<a href="https://learnopengl.com/Model-Loading/Model">Model </a>
     89 			</li>
     90 		</ol>
     91 	</li>
     92 	<li id="Advanced-OpenGL">
     93 		<span class="closed">Advanced OpenGL </span>
     94 		<ol>
     95 			<li id="Advanced-OpenGL/Depth-testing">
     96 				<a href="https://learnopengl.com/Advanced-OpenGL/Depth-testing">Depth testing </a>
     97 			</li>
     98 			<li id="Advanced-OpenGL/Stencil-testing">
     99 				<a href="https://learnopengl.com/Advanced-OpenGL/Stencil-testing">Stencil testing </a>
    100 			</li>
    101 			<li id="Advanced-OpenGL/Blending">
    102 				<a href="https://learnopengl.com/Advanced-OpenGL/Blending">Blending </a>
    103 			</li>
    104 			<li id="Advanced-OpenGL/Face-culling">
    105 				<a href="https://learnopengl.cm/Advanced-OpenGL/Face-culling">Face culling </a>
    106 			</li>
    107 			<li id="Advanced-OpenGL/Framebuffers">
    108 				<a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers">Framebuffers </a>
    109 			</li>
    110 			<li id="Advanced-OpenGL/Cubemaps">
    111 				<a href="https://learnopengl.com/Advanced-OpenGL/Cubemaps">Cubemaps </a>
    112 			</li>
    113 			<li id="Advanced-OpenGL/Advanced-Data">
    114 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-Data">Advanced Data </a>
    115 			</li>
    116 			<li id="Advanced-OpenGL/Advanced-GLSL">
    117 				<a href="https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL">Advanced GLSL </a>
    118 			</li>
    119 			<li id="Advanced-OpenGL/Geometry-Shader">
    120 				<a href="https://learnopengl.com/Advanced-OpenGL/Geometry-Shader">Geometry Shader </a>
    121 			</li>
    122 			<li id="Advanced-OpenGL/Instancing">
    123 				<a href="https://learnopengl.com/Advanced-OpenGL/Instancing">Instancing </a>
    124 			</li>
    125 			<li id="Advanced-OpenGL/Anti-Aliasing">
    126 				<a href="https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing">Anti Aliasing </a>
    127 			</li>
    128 		</ol>
    129 	</li>
    130 	<li id="Advanced-Lighting">
    131 		<span class="closed">Advanced Lighting </span>
    132 		<ol>
    133 			<li id="Advanced-Lighting/Advanced-Lighting">
    134 				<a href="https://learnopengl.com/Advanced-Lighting/Advanced-Lighting">Advanced Lighting </a>
    135 			</li>
    136 			<li id="Advanced-Lighting/Gamma-Correction">
    137 				<a href="https://learnopengl.com/Advanced-Lighting/Gamma-Correction">Gamma Correction </a>
    138 			</li>
    139 			<li id="Advanced-Lighting/Shadows">
    140 				<span class="closed">Shadows </span>
    141 				<ol>
    142 					<li id="Advanced-Lighting/Shadows/Shadow-Mapping">
    143 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping">Shadow Mapping </a>
    144 					</li>
    145 					<li id="Advanced-Lighting/Shadows/Point-Shadows">
    146 						<a href="https://learnopengl.com/Advanced-Lighting/Shadows/Point-Shadows">Point Shadows </a>
    147 					</li>
    148 				</ol>
    149 			</li>
    150 			<li id="Advanced-Lighting/Normal-Mapping">
    151 				<a href="https://learnopengl.com/Advanced-Lighting/Normal-Mapping">Normal Mapping </a>
    152 			</li>
    153 			<li id="Advanced-Lighting/Parallax-Mapping">
    154 				<a href="https://learnopengl.com/Advanced-Lighting/Parallax-Mapping">Parallax Mapping </a>
    155 			</li>
    156 			<li id="Advanced-Lighting/HDR">
    157 				<a href="https://learnopengl.com/Advanced-Lighting/HDR">HDR </a>
    158 			</li>
    159 			<li id="Advanced-Lighting/Bloom">
    160 				<a href="https://learnopengl.com/Advanced-Lighting/Bloom">Bloom </a>
    161 			</li>
    162 			<li id="Advanced-Lighting/Deferred-Shading">
    163 				<a href="https://learnopengl.com/Advanced-Lighting/Deferred-Shading">Deferred Shading </a>
    164 			</li>
    165 			<li id="Advanced-Lighting/SSAO">
    166 				<a href="https://learnopengl.com/Advanced-Lighting/SSAO">SSAO </a>
    167 			</li>
    168 		</ol>
    169 	</li>
    170 	<li id="PBR">
    171 		<span class="closed">PBR </span>
    172 		<ol>
    173 			<li id="PBR/Theory">
    174 				<a href="https://learnopengl.com/PBR/Theory">Theory </a>
    175 			</li>
    176 			<li id="PBR/Lighting">
    177 				<a href="https://learnopengl.com/PBR/Lighting">Lighting </a>
    178 			</li>
    179 			<li id="PBR/IBL">
    180 				<span class="closed">IBL </span>
    181 				<ol>
    182 					<li id="PBR/IBL/Diffuse-irradiance">
    183 						<a href="https://learnopengl.com/PBR/IBL/Diffuse-irradiance">Diffuse irradiance </a>
    184 					</li>
    185 					<li id="PBR/IBL/Specular-IBL">
    186 						<a href="https://learnopengl.com/PBR/IBL/Specular-IBL">Specular IBL </a>
    187 					</li>
    188 				</ol>
    189 			</li>
    190 		</ol>
    191 	</li>
    192 	<li id="In-Practice">
    193 		<span class="closed">In Practice </span>
    194 		<ol>
    195 			<li id="In-Practice/Debugging">
    196 				<a href="https://learnopengl.com/In-Practice/Debugging">Debugging </a>
    197 			</li>
    198 			<li id="In-Practice/Text-Rendering">
    199 				<a href="https://learnopengl.com/In-Practice/Text-Rendering">Text Rendering </a>
    200 			</li>
    201 			<li id="In-Practice/2D-Game">
    202 				<span class="closed">2D Game </span>
    203 				<ol>
    204 					<li id="In-Practice/2D-Game/Breakout">
    205 						<a href="https://learnopengl.com/In-Practice/2D-Game/Breakout">Breakout </a>
    206 					</li>
    207 					<li id="In-Practice/2D-Game/Setting-up">
    208 						<a href="https://learnopengl.com/In-Practice/2D-Game/Setting-up">Setting up </a>
    209 					</li>
    210 					<li id="In-Practice/2D-Game/Rendering-Sprites">
    211 						<a href="https://learnopengl.com/In-Practice/2D-Game/Rendering-Sprites">Rendering Sprites </a>
    212 					</li>
    213 					<li id="In-Practice/2D-Game/Levels">
    214 						<a href="https://learnopengl.com/In-Practice/2D-Game/Levels">Levels </a>
    215 					</li>
    216 					<li id="In-Practice/2D-Game/Collisions">
    217 						<span class="closed">Collisions </span>
    218 						<ol>
    219 							<li id="In-Practice/2D-Game/Collisions/Ball">
    220 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Ball">Ball </a>
    221 							</li>
    222 							<li id="In-Practice/2D-Game/Collisions/Collision-detection">
    223 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection">Collision detection </a>
    224 							</li>
    225 							<li id="In-Practice/2D-Game/Collisions/Collision-resolution">
    226 								<a href="https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-resolution">Collision resolution </a>
    227 							</li>
    228 						</ol>
    229 					</li>
    230 					<li id="In-Practice/2D-Game/Particles">
    231 						<a href="https://learnopengl.com/In-Practice/2D-Game/Particles">Particles </a>
    232 					</li>
    233 					<li id="In-Practice/2D-Game/Postprocessing">
    234 						<a href="https://learnopengl.com/In-Practice/2D-Game/Postprocessing">Postprocessing </a>
    235 					</li>
    236 					<li id="In-Practice/2D-Game/Powerups">
    237 						<a href="https://learnopengl.com/In-Practice/2D-Game/Powerups">Powerups </a>
    238 					</li>
    239 					<li id="In-Practice/2D-Game/Audio">
    240 						<a href="https://learnopengl.com/In-Practice/2D-Game/Audio">Audio </a>
    241 					</li>
    242 					<li id="In-Practice/2D-Game/Render-text">
    243 						<a href="https://learnopengl.com/In-Practice/2D-Game/Render-text">Render text </a>
    244 					</li>
    245 					<li id="In-Practice/2D-Game/Final-thoughts">
    246 						<a href="https://learnopengl.com/In-Practice/2D-Game/Final-thoughts">Final thoughts </a>
    247 					</li>
    248 				</ol>
    249 			</li>
    250 		</ol>
    251 	</li>
    252 	<li id="Guest-Articles">
    253 		<span class="closed">Guest Articles </span>
    254 		<ol>
    255 			<li id="Guest-Articles/How-to-publish">
    256 				<a href="https://learnopengl.com/Guest-Articles/How-to-publish">How to publish </a>
    257 			</li>
    258 			<li id="Guest-Articles/2020">
    259 				<span class="closed">2020 </span>
    260 				<ol>
    261 					<li id="Guest-Articles/2020/OIT">
    262 						<span class="closed">OIT </span>
    263 						<ol>
    264 							<li id="Guest-Articles/2020/OIT/Introduction">
    265 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Introduction">Introduction </a>
    266 							</li>
    267 							<li id="Guest-Articles/2020/OIT/Weighted-Blended">
    268 								<a href="https://learnopengl.com/Guest-Articles/2020/OIT/Weighted-Blended">Weighted Blended </a>
    269 							</li>
    270 						</ol>
    271 					</li>
    272 					<li id="Guest-Articles/2020/Skeletal-Animation">
    273 						<a href="https://learnopengl.com/Guest-Articles/2020/Skeletal-Animation">Skeletal Animation </a>
    274 					</li>
    275 				</ol>
    276 			</li>
    277 			<li id="Guest-Articles/2021">
    278 				<span class="closed">2021 </span>
    279 				<ol>
    280 					<li id="Guest-Articles/2021/CSM">
    281 						<a href="https://learnopengl.com/Guest-Articles/2021/CSM">CSM </a>
    282 					</li>
    283 					<li id="Guest-Articles/2021/Scene">
    284 						<span class="closed">Scene </span>
    285 						<ol>
    286 							<li id="Guest-Articles/2021/Scene/Scene-Graph">
    287 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Scene-Graph">Scene Graph </a>
    288 							</li>
    289 							<li id="Guest-Articles/2021/Scene/Frustum-Culling">
    290 								<a href="https://learnopengl.com/Guest-Articles/2021/Scene/Frustum-Culling">Frustum Culling </a>
    291 							</li>
    292 						</ol>
    293 					</li>
    294 					<li id="Guest-Articles/2021/Tessellation">
    295 						<span class="closed">Tessellation </span>
    296 						<ol>
    297 							<li id="Guest-Articles/2021/Tessellation/Height-map">
    298 								<a href="https://learnopengl.com/Guest-Articles/2021/Tessellation/Height-map">Height map </a>
    299 							</li>
    300 						</ol>
    301 					</li>
    302 				</ol>
    303 			</li>
    304 		</ol>
    305 	</li>
    306 	<li id="Code-repository">
    307 		<a href="https://learnopengl.com/Code-repository">Code repository </a>
    308 	</li>
    309 	<li id="Translations">
    310 		<a href="https://learnopengl.com/Translations">Translations </a>
    311 	</li>
    312 	<li id="About">
    313 		<a href="https://learnopengl.com/About">About </a>
    314 	</li>
    315 </ol>
    316 	</nav>
    317 	<main>
    318     <h1 id="content-title">Basic Lighting</h1>
    319 <h1 id="content-url" style='display:none;'>Lighting/Basic-Lighting</h1>
    320 <p>
    321   Lighting in the real world is extremely complicated and depends on way too many factors, something we can't afford to calculate on the limited processing power we have. Lighting in OpenGL is therefore based on approximations of reality using simplified models that are much easier to process and look relatively similar. These lighting models are based on the physics of light as we understand it. One of those models is called the <def>Phong lighting model</def>. The major building blocks of the Phong lighting model consist of 3 components: ambient, diffuse and specular lighting. Below you can see what these lighting components look like on their own and combined:
    322 </p>
    323 
    324 <img src="/img/lighting/basic_lighting_phong.png"/>
    325 
    326 <p>  
    327   <ul>
    328     <li><def>Ambient lighting</def>: even when it is dark there is usually still some light somewhere in the world (the moon, a distant light) so objects are almost never completely dark. To simulate this we use an ambient lighting constant that always gives the object some color.</li>
    329     <li><def>Diffuse lighting</def>: simulates the directional impact a light object has on an object. This is the most visually significant component of the lighting model. The more a part of an object faces the light source, the brighter it becomes.</li>
    330     <li><def>Specular lighting</def>: simulates the bright spot of a light that appears on shiny objects. Specular highlights are more inclined to the color of the light than the color of the object.</li>
    331   </ul>
    332 </p>
    333 
    334 <p>
    335   To create visually interesting scenes we want to at least simulate these 3 lighting components. We'll start with the simplest one: <em>ambient lighting</em>.
    336 </p>
    337 
    338 <h1>Ambient lighting</h1>
    339 <p>
    340   Light usually does not come from a single light source, but from many light sources scattered all around us, even when they're not immediately visible. One of the properties of light is that it can scatter and bounce in many directions, reaching spots that aren't directly visible; light can thus <em>reflect</em> on other surfaces and have an indirect impact on the lighting of an object. Algorithms that take this into consideration are called <def>global illumination</def> algorithms, but these are complicated and expensive to calculate.
    341 </p>
    342 
    343 <p>
    344   Since we're not big fans of complicated and expensive algorithms we'll start by using a very simplistic model of global illumination, namely <def>ambient lighting</def>. As you've seen in the previous section we use a small constant (light) color that we add to the final resulting color of the object's fragments, thus making it look like there is always some scattered light even when there's not a direct light source.
    345 </p>
    346 
    347 <p>
    348   Adding ambient lighting to the scene is really easy. We take the light's color, multiply it with a small constant ambient factor, multiply this with the object's color, and use that as the fragment's color in the cube object's shader:
    349 </p>
    350 
    351 <pre><code>
    352 void main()
    353 {
    354     float ambientStrength = 0.1;
    355     vec3 ambient = ambientStrength * lightColor;
    356 
    357     vec3 result = ambient * objectColor;
    358     FragColor = vec4(result, 1.0);
    359 }  
    360 </code></pre>
    361 
    362 <p>
    363   If you'd now run the program, you'll notice that the first stage of lighting is now successfully applied to the object. The object is quite dark, but not completely since ambient lighting is applied (note that the light cube is unaffected because we use a different shader). It should look something like this:
    364 </p>
    365 
    366 <img src="/img/lighting/ambient_lighting.png" class="clean"/>
    367 
    368 <h1>Diffuse lighting</h1>
    369 <p>
    370 	Ambient lighting by itself doesn't produce the most interesting results, but diffuse lighting however will start to give a significant visual impact on the object. Diffuse lighting gives the object more brightness the closer its fragments are aligned to the light rays from a light source. To give you a better understanding of diffuse lighting take a look at the following image:
    371 </p>
    372 
    373 <img src="/img/lighting/diffuse_light.png" class="clean"/>
    374 
    375 <p>
    376   To the left we find a light source with a light ray targeted at a single fragment of our object. We  need to measure at what angle the light ray touches the fragment. If the light ray is perpendicular to the object's surface the light has the greatest impact. To measure the angle between the light ray and the fragment we use something called a <def>normal vector</def>, that is a vector  perpendicular to the fragment's surface (here depicted as a yellow arrow); we'll get to that later. The angle between the two vectors can then easily be calculated with the dot product.
    377 </p>
    378 
    379 <p>
    380   You may remember from the <a href="https://learnopengl.com/Getting-started/Transformations" target="_blank">transformations</a> chapter that, the lower the angle  between two unit vectors, the more the dot product is inclined towards a value of 1. When the angle between both vectors is 90 degrees, the dot product becomes 0. The same applies to \(\theta\): the larger \(\theta\) becomes, the less of an impact the light should have on the fragment's color.
    381 </p>
    382 
    383 <note>
    384   Note that to get (only) the cosine of the angle between both vectors we will work with <em>unit vectors</em> (vectors of length <code>1</code>) so we need to make sure all the vectors are normalized, otherwise the dot product returns more than just the cosine (see <a href="https://learnopengl.com/Getting-started/Transformations" target="_blank">Transformations</a>).
    385 </note>
    386 
    387 <p>
    388   The resulting dot product thus returns a scalar that we can use to calculate the light's impact on the fragment's color, resulting in differently lit fragments based on their orientation towards the light.
    389 </p>
    390 
    391 <p>
    392   So, what do we need to calculate diffuse lighting:
    393   <ul>
    394     <li>Normal vector: a vector that is perpendicular to the vertex' surface.</li>
    395     <li>The directed light ray: a direction vector that is the difference vector between the light's position and the fragment's position. To calculate this light ray we need the light's position vector and the fragment's position vector.</li>
    396   </ul>
    397 </p>
    398 
    399 <h2>Normal vectors</h2>
    400 <p>
    401   A normal vector is a (unit) vector that is perpendicular to the surface of a vertex. Since a vertex by itself has no surface (it's just a single point in space) we retrieve a normal vector by using its surrounding vertices to figure out the surface of the vertex. We can use a little trick to calculate the normal vectors for all the cube's vertices by using the cross product, but since a 3D cube is not a complicated shape we can simply manually add them to the vertex data. The updated vertex data array can be found <a href="/code_viewer.php?code=lighting/basic_lighting_vertex_data" target="_blank">here</a>. Try to visualize that the normals are indeed vectors perpendicular to each plane's surface (a cube consists of 6 planes).
    402 </p>
    403 
    404 <p>
    405   Since we added extra data to the vertex array we should update the cube's vertex shader:
    406 </p>
    407 
    408 <pre><code>
    409 #version 330 core
    410 layout (location = 0) in vec3 aPos;
    411 layout (location = 1) in vec3 aNormal;
    412 ...
    413 </code></pre>
    414 
    415 <p>
    416   Now that we added a normal vector to each of the vertices and updated the vertex shader we should update the vertex attribute pointers as well. Note that the light source's cube uses the same vertex array for its vertex data, but the lamp shader has no use of the newly added normal vectors. We don't have to update the lamp's shaders or attribute configurations, but we have to at least modify the vertex attribute pointers to reflect the new vertex array's size:
    417 </p>
    418 
    419 <pre><code>
    420 <function id='30'>glVertexAttribPointer</function>(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    421 <function id='29'><function id='60'>glEnable</function>VertexAttribArray</function>(0);
    422 </code></pre>
    423 
    424 <p>
    425   We only want to use the first <code>3</code> floats of each vertex and ignore the last <code>3</code> floats so we only need to update the <em>stride</em> parameter to <code>6</code> times the size of a <code>float</code> and we're done.
    426 </p>
    427 
    428 <note>
    429    It may look inefficient using vertex data that is not completely used by the lamp shader, but the vertex data is already stored in the GPU's memory from the container object so we don't have to store new data into the GPU's memory. This actually makes it more efficient compared to allocating a new VBO specifically for the lamp.
    430 </note>
    431 
    432 <p>
    433  All the lighting calculations are done in the fragment shader so we need to forward the normal vectors from the vertex shader to the fragment shader. Let's do that:
    434 </p>
    435 
    436 <pre><code>
    437 out vec3 Normal;
    438 
    439 void main()
    440 {
    441     gl_Position = projection * view * model * vec4(aPos, 1.0);
    442     Normal = aNormal;
    443 } 
    444 </code></pre>
    445 
    446 <p>
    447   What's left to do is declare the corresponding input variable in the fragment shader:
    448 </p>
    449 
    450 <pre><code>
    451 in vec3 Normal;  
    452 </code></pre>
    453 
    454 <h2>Calculating the diffuse color</h2>
    455 <p>
    456   We now have the normal vector for each vertex, but we still need the light's position vector and the fragment's position vector. Since the light's position is a single static variable we can declare it as a uniform in the fragment shader:
    457 </p>
    458 
    459 <pre><code>
    460 uniform vec3 lightPos;  
    461 </code></pre>
    462 
    463 <p>
    464   And then update the uniform in the render loop (or outside since it doesn't change per frame). We use the <var>lightPos</var> vector declared in the previous chapter as the location of the diffuse light source:
    465 </p>
    466 
    467 <pre><code>
    468 lightingShader.setVec3("lightPos", lightPos);  
    469 </code></pre>
    470 
    471 <p>
    472   Then the last thing we need is the actual fragment's position. We're going to do all the lighting calculations in world space so we want a vertex position that is in world space first. We can accomplish this by multiplying the vertex position attribute with the model matrix only (not the view and projection matrix) to transform it to world space coordinates. This can easily be accomplished in the vertex shader so let's declare an output variable and calculate its world space coordinates:
    473 </p>
    474 
    475 <pre><code>
    476 out vec3 FragPos;  
    477 out vec3 Normal;
    478   
    479 void main()
    480 {
    481     gl_Position = projection * view * model * vec4(aPos, 1.0);
    482     FragPos = vec3(model * vec4(aPos, 1.0));
    483     Normal = aNormal;
    484 }
    485 </code></pre>
    486 
    487 <p> 
    488   And lastly add the corresponding input variable to the fragment shader:
    489 </p>
    490 
    491 <pre><code>
    492 in vec3 FragPos;  
    493 </code></pre>
    494 
    495 <p>
    496   This <code>in</code> variable will be interpolated from the 3 world position vectors of the triangle to form the <var>FragPos</var> vector that is the per-fragment world position.   Now that all the required variables are set we can start the lighting calculations.
    497 </p>
    498 
    499 
    500 <p>
    501   The first thing we need to calculate is the direction vector between the light source and the fragment's position. From the previous section we know that the light's direction vector is the difference vector between the light's position vector and the fragment's position vector. As you may remember from the <a href="https://learnopengl.com/Getting-started/Transformations" target="_blank">transformations</a> chapter we can easily calculate this difference by subtracting both vectors from each other. We also want to make sure all the relevant vectors end up as unit vectors so we normalize both the normal and the resulting direction vector:
    502 </p>
    503 
    504 <pre><code>
    505 vec3 norm = normalize(Normal);
    506 vec3 lightDir = normalize(lightPos - FragPos);  
    507 </code></pre>
    508 
    509 <note>
    510   When calculating lighting we usually do not care about the magnitude of a vector or their position; we only care about their direction. Because we only care about their direction almost all the calculations are done with unit vectors since it simplifies most calculations (like the dot product). So when doing lighting calculations, make sure you always normalize the relevant vectors to ensure they're actual unit vectors. Forgetting to normalize a vector is a popular mistake.
    511 </note>
    512 
    513 <p>
    514   Next we need to calculate the diffuse impact of the light on the current fragment by taking the dot product between the <var>norm</var> and <var>lightDir</var> vectors. The resulting value is then multiplied with the light's color to get the diffuse component, resulting in a darker diffuse component the greater the angle between both vectors:
    515 </p>
    516 
    517 <pre><code>
    518 float diff = max(dot(norm, lightDir), 0.0);
    519 vec3 diffuse = diff * lightColor;
    520 </code></pre>
    521 
    522 <p>
    523   If the angle between both vectors is greater than <code>90</code> degrees then the result of the dot product will actually become negative and we end up with a negative diffuse component.
    524   For that reason we use the <fun>max</fun> function that returns the highest of both its parameters to make sure the diffuse component (and thus the colors) never become negative. Lighting for negative colors is not really defined so it's best to stay away from that, unless you're one of those eccentric artists. 
    525 </p>
    526 
    527 <p>
    528   Now that we have both an ambient and a diffuse component we add both colors to each other and then multiply the result with the color of the object to get the resulting fragment's output color:
    529 </p>
    530 
    531 <pre><code>
    532 vec3 result = (ambient + diffuse) * objectColor;
    533 FragColor = vec4(result, 1.0);
    534 </code></pre>
    535 
    536 <p>
    537   If your application (and shaders) compiled successfully you should see something like this:
    538 </p>
    539 
    540 <img src="/img/lighting/basic_lighting_diffuse.png" class="clean"/>
    541 
    542 <p>
    543   You can see that with diffuse lighting the cube starts to look like an actual cube again. Try visualizing the normal vectors in your head and move the camera around the cube to see that the larger the angle between the normal vector and the light's direction vector, the darker the fragment becomes.
    544 </p>
    545 
    546 <p>
    547   Feel free to compare your source code with the complete source code <a href="/code_viewer_gh.php?code=src/2.lighting/2.1.basic_lighting_diffuse/basic_lighting_diffuse.cpp" target="_blank">here</a> if you're stuck.
    548 </p>
    549 
    550 <h2>One last thing</h2>
    551 <p>
    552   in the previous section we passed the normal vector directly from the vertex shader to the fragment shader. However, the calculations in the fragment shader are all done in world space, so shouldn't we transform the normal vectors to world space coordinates as well? Basically yes, but it's not as simple as simply multiplying it with a model matrix. 
    553 </p>
    554 
    555 <p>
    556   First of all, normal vectors are only direction vectors and do not represent a specific position in space. Second, normal vectors do not have a homogeneous coordinate (the <code>w</code> component of a vertex position). This means that translations should not have any effect on the normal vectors. So if we want to multiply the normal vectors with a model matrix we want to remove the translation part of the matrix by taking the upper-left <code>3x3</code> matrix of the model matrix (note that we could also set the <code>w</code> component of a normal vector to <code>0</code> and multiply with the 4x4 matrix). 
    557 </p>
    558 
    559 <p>
    560  Second, if the model matrix would perform a non-uniform scale, the vertices would be changed in such a way that the normal vector is not perpendicular to the surface anymore. The following image shows the effect such a model matrix (with non-uniform scaling) has on a normal vector:
    561 </p>
    562 
    563 <img src="/img/lighting/basic_lighting_normal_transformation.png" class="clean"/>
    564 
    565 <p>
    566   Whenever we apply a non-uniform scale (note: a uniform scale only changes the normal's magnitude, not its direction, which is easily fixed by normalizing it) the normal vectors are not perpendicular to the corresponding surface anymore which distorts the lighting.
    567 </p>
    568 
    569 <p>
    570   The trick of fixing this behavior is to use a different model matrix specifically tailored for normal vectors. This matrix is called the <def>normal matrix</def> and uses a few linear algebraic operations to remove the effect of wrongly scaling the normal vectors. If you want to know how this matrix is calculated I suggest the following <a href="http://www.lighthouse3d.com/tutorials/glsl-tutorial/the-normal-matrix/" target="_blank">article</a>. 
    571 </p>
    572 
    573 <p>
    574   The normal matrix is defined as 'the transpose of the inverse of the upper-left 3x3 part of the model matrix'. Phew, that's a mouthful and if you don't really understand what that means, don't worry; we haven't discussed inverse and transpose matrices yet. Note that most resources define the normal matrix as derived from the model-view matrix, but since we're working in world space (and not in view space) we will derive it from the model matrix.
    575 </p>
    576 
    577 <p>
    578   In the vertex shader we can generate the normal matrix by using the <fun>inverse</fun> and <fun>transpose</fun> functions in the vertex shader that work on any matrix type. Note that we cast the matrix to a 3x3 matrix to ensure it loses its translation properties and that it can multiply with the <code>vec3</code> normal vector:
    579 </p>
    580 
    581 <pre><code>
    582 Normal = mat3(transpose(inverse(model))) * aNormal;  
    583 </code></pre>
    584 
    585 <warning>
    586   Inversing matrices is a costly operation for shaders, so wherever possible try to avoid doing inverse operations since they have to be done on each vertex of your scene. For learning purposes this is fine, but for an efficient application you'll likely want to calculate the normal matrix on the CPU and send it to the shaders via a uniform before drawing (just like the model matrix).
    587 </warning>
    588 
    589 <p>
    590   In the diffuse lighting section the lighting was fine because we didn't do any scaling on the object, so there was not really a need to use a normal matrix and we could've just multiplied the normals with the model matrix. If you are doing a non-uniform scale however, it is essential that you multiply your normal vectors with the normal matrix.
    591 </p>
    592 
    593 
    594 <h1>Specular Lighting</h1>
    595 <p>
    596   If you're not exhausted already by all the lighting talk we can start finishing the Phong lighting model by adding specular highlights.
    597 </p>
    598 
    599 <p>
    600   Similar to diffuse lighting, specular lighting is based on the light's direction vector and the object's normal vectors, but this time it is also based on the view direction e.g. from what direction the player is looking at the fragment. Specular lighting is based on the reflective properties of surfaces. If we think of the object's surface as a mirror, the specular lighting is the strongest wherever we would see the light reflected on the surface. You can see this effect in the following image:  
    601 </p>
    602 
    603 <img src="/img/lighting/basic_lighting_specular_theory.png" class="clean"/>
    604 
    605 <p>
    606   We calculate a reflection vector by reflecting the light direction around the normal vector. Then we calculate the angular distance between this reflection vector and the view direction. The closer the angle between them, the greater the impact of the specular light. The resulting effect is that we see a bit of a highlight when we're looking at the light's direction reflected via the surface. 
    607 </p>
    608 
    609 <p>
    610   The view vector is the one extra variable we need for specular lighting which we can calculate using the viewer's world space position and the fragment's position. Then we calculate the specular's intensity, multiply this with the light color and add this to the ambient and diffuse components.
    611 </p>
    612 
    613 <note>
    614   We chose to do the lighting calculations in world space, but most people tend to prefer doing lighting in view space. An advantage of view space is that the viewer's position is always at <code>(0,0,0)</code> so you already got the position of the viewer for free. However, I find calculating lighting in world space more intuitive for learning purposes. If you still want to calculate lighting in view space you want to transform all the relevant vectors with the view matrix as well (don't forget to change the normal matrix too).
    615 </note>
    616 
    617 <p>
    618   To get the world space coordinates of the viewer we simply take the position vector of the camera object (which is the viewer of course). So let's add another uniform to the fragment shader and pass the camera position vector to the shader:
    619 </p>
    620 
    621 <pre><code>
    622 uniform vec3 viewPos;
    623 </code></pre>
    624 
    625 <pre><code>
    626 lightingShader.setVec3("viewPos", camera.Position); 
    627 </code></pre>
    628 
    629 <p>
    630   Now that we have all the required variables we can calculate the specular intensity. First we define a specular intensity value to give the specular highlight a medium-bright color so that it doesn't have too much of an impact:
    631 </p>
    632 
    633 <pre><code>
    634 float specularStrength = 0.5;
    635 </code></pre>
    636 
    637 <p>
    638   If we would set this to <code>1.0f</code> we'd get a really bright specular component which is a bit too much for a coral cube. In the <a href="https://learnopengl.com/Lighting/Materials" target="_blank">next</a> chapter we'll talk about properly setting all these lighting intensities and how they affect the objects. Next we calculate the view direction vector and the corresponding reflect vector along the normal axis:
    639 </p>
    640 
    641 <pre><code>
    642 vec3 viewDir = normalize(viewPos - FragPos);
    643 vec3 reflectDir = reflect(-lightDir, norm);  
    644 </code></pre>
    645 
    646 <p>
    647   Note that we negate the <code>lightDir</code> vector. The <code>reflect</code> function expects the first vector to point <strong>from</strong> the light source towards the fragment's position, but the <code>lightDir</code> vector is currently pointing the other way around: from the fragment  <strong>towards</strong> the light source (this depends on the order of subtraction earlier on when we calculated the <code>lightDir</code> vector). To make sure we get the correct <code>reflect</code> vector we reverse its direction by negating the <code>lightDir</code> vector first. The second argument expects a normal vector so we supply the normalized <code>norm</code> vector.
    648 </p>
    649 
    650 <p>
    651   Then what's left to do is to actually calculate the specular component. This is accomplished with the following formula:
    652 
    653 <pre><code>
    654 float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    655 vec3 specular = specularStrength * spec * lightColor;  
    656 </code></pre>
    657 
    658 <p>
    659   We first calculate the dot product between the view direction and the reflect direction (and make sure it's not negative) and then raise it to the power of <code>32</code>. This <code>32</code> value is the <def>shininess</def> value of the highlight. The higher the shininess value of an object, the more it properly reflects the light instead of scattering it all around and thus the smaller the highlight becomes. Below you can see an image that shows the visual impact of different shininess values:
    660 </p>
    661 
    662 <img src="/img/lighting/basic_lighting_specular_shininess.png"/>
    663 
    664 <p>
    665   We don't want the specular component to be too distracting so we keep the exponent at <code>32</code>. The only thing left to do is to add it to the ambient and diffuse components and multiply the combined result with the object's color:
    666 </p>
    667 
    668 <pre><code>
    669 vec3 result = (ambient + diffuse + specular) * objectColor;
    670 FragColor = vec4(result, 1.0);
    671 </code></pre>
    672 
    673 <p>
    674 	We now calculated all the lighting components of the Phong lighting model. Based on your point of view you should see something like this:
    675 </p>
    676 
    677 <img src="/img/lighting/basic_lighting_specular.png" class="clean"/>
    678 
    679 <p>
    680   You can find the complete source code of the application <a href="/code_viewer_gh.php?code=src/2.lighting/2.2.basic_lighting_specular/basic_lighting_specular.cpp" target="_blank">here</a>. 
    681 </p>
    682 
    683 <note>
    684   <p>
    685   In the earlier days of lighting shaders, developers used to implement the Phong lighting model in the vertex shader. The advantage of doing lighting in the vertex shader is that it is a lot more efficient since there are generally a lot less vertices compared to fragments, so the (expensive) lighting calculations are done less frequently. However, the resulting color value in the vertex shader is the resulting lighting color of that vertex only and the color values of the surrounding fragments are then the result of interpolated lighting colors. The result was that the lighting was not very realistic unless large amounts of vertices were used:
    686   </p>
    687   
    688   <img src="/img/lighting/basic_lighting_gouruad.png"/>
    689   
    690   <p>
    691   When the Phong lighting model is implemented in the vertex shader it is called <def>Gouraud shading</def> instead of <def>Phong shading</def>. Note that due to the interpolation the lighting  looks somewhat off. The Phong shading gives much smoother lighting results.
    692   </p>
    693 </note>
    694 
    695 <p>
    696   By now you should be starting to see just how powerful shaders are. With little information shaders are able to calculate how lighting affects the fragment's colors for all our objects. In the <a href="https://learnopengl.com/Lighting/Materials" target="_blank">next</a> chapters we'll be delving much deeper into what we can do with the lighting model.
    697 </p>
    698 
    699 <h2>Exercises</h2>
    700 <ul>
    701   <li>Right now the light source is a boring static light source that doesn't move. Try to move the light source around the scene over time using either <fun>sin</fun> or <fun>cos</fun>. Watching the lighting change over time gives you a good understanding of Phong's lighting model: <a href="/code_viewer_gh.php?code=src/2.lighting/2.3.basic_lighting_exercise1/basic_lighting_exercise1.cpp" target="_blank">solution</a>. </li>
    702   <li>Play around with different ambient, diffuse and specular strengths and see how they impact the result. Also experiment with the shininess factor. Try to comprehend why certain values have a certain visual output.</li>
    703   <li>Do Phong shading in view space instead of world space: <a href="/code_viewer_gh.php?code=src/2.lighting/2.4.basic_lighting_exercise2/basic_lighting_exercise2.cpp" target="_blank">solution</a>. </li>
    704   <li>Implement Gouraud shading instead of Phong shading. If you did things right the lighting should <a href="/img/lighting/basic_lighting_exercise3.png" target="_blank">look a bit  off</a> (especially the specular highlights) with the cube object. Try to reason why it looks so weird: <a href="/code_viewer_gh.php?code=src/2.lighting/2.5.basic_lighting_exercise3/basic_lighting_exercise3.cpp" target="_blank">solution</a>.</li>
    705 </ul>
    706        
    707 
    708     </div>
    709     
    710 	</main>
    711 </body>
    712 </html>