LearnOpenGL

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

Light-casters.html (41507B)


      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">Light casters</h1>
    319 <h1 id="content-url" style='display:none;'>Lighting/Light-casters</h1>
    320 <p>
    321 	All the lighting we've used so far came from a single source that is a single point in space. It gives good results, but in the real world we have several types of light that each act different. A light source that <em>casts</em> light upon objects is called a <def>light caster</def>. In this chapter we'll discuss several different types of light casters. Learning to simulate different light sources is yet another tool in your toolbox to further enrich your environments.	            
    322 </p>
    323 
    324 <p>
    325   We'll first discuss a directional light, then a point light which is an extension of what we had before, and lastly we'll discuss spotlights. In the <a href="https://learnopengl.com/Lighting/Multiple-lights" target="_blank">next</a> chapter we'll combine several of these different light types into one scene.
    326 </p>
    327     
    328 <h1>Directional Light</h1>
    329 <p>
    330   When a light source is far away the light rays coming from the light source are close to parallel to each other. It looks like all the light rays are coming from the same direction, regardless of where the object and/or the viewer is. When a light source is modeled to be <em>infinitely</em> far away it is called a <def>directional light</def> since all its light rays have the same direction; it is independent of the location of the light source. 
    331 </p>
    332   
    333 <p>
    334 	A fine example of a directional light source is the sun as we know it. The sun is not infinitely far away from us, but it is so far away that we can perceive it as being infinitely far away  in the lighting calculations. All the light rays from the sun are then modeled as parallel light rays as we can see in the following image:
    335 </p>
    336   
    337   <img src="/img/lighting/light_casters_directional.png" class="clean"/>
    338   
    339 <p>
    340   Because all the light rays are parallel it does not matter how each object relates to the light source's position since the light direction remains the same for each object in the scene. Because the light's direction vector stays the same, the lighting calculations will be similar for each object in the scene.
    341   </p>
    342   
    343 <p>
    344   We can model such a directional light by defining a light direction vector instead of a position vector. The shader calculations remain mostly the same except this time we directly use the light's <var>direction</var> vector instead of calculating the <var>lightDir</var> vector using the light's <var>position</var> vector:
    345 </p>
    346   
    347 <pre><code>
    348 struct Light {
    349     // vec3 position; // no longer necessary when using directional lights.
    350     vec3 direction;
    351   
    352     vec3 ambient;
    353     vec3 diffuse;
    354     vec3 specular;
    355 };
    356 [...]
    357 void main()
    358 {
    359   vec3 lightDir = normalize(-light.direction);
    360   [...]
    361 }
    362 </code></pre>
    363   
    364   <p>
    365     Note that we first negate the <var>light.direction</var> vector. The lighting calculations we used so far expect the light direction to be a direction from the fragment <strong>towards</strong> the light source, but people generally prefer to specify a directional light as a global direction pointing <strong>from</strong> the light source. Therefore we have to negate the global light direction vector to switch its direction; it's now a direction vector pointing towards the light source. Also, be sure to normalize the vector since it is unwise to assume the input vector to be a unit vector.
    366   </p>
    367   
    368 <p>
    369     The resulting <var>lightDir</var> vector is then used as before in the diffuse and specular computations.
    370 </p>
    371     
    372 <p>
    373     To clearly demonstrate that a directional light has the same effect on multiple objects we revisit the container party scene from the end of the <a href="https://learnopengl.com/Getting-started/Coordinate-Systems" target="_blank">Coordinate systems</a> chapter. In case you missed the party we defined 10 different <a href="/code_viewer.php?code=lighting/light_casters_container_positions" target="_blank">container positions</a> and generated a different model matrix per container where each model matrix contained the appropriate local-to-world transformations: 
    374 </p>
    375   
    376 <pre><code>
    377 for(unsigned int i = 0; i &lt; 10; i++)
    378 {
    379     glm::mat4 model = glm::mat4(1.0f);
    380     model = <function id='55'>glm::translate</function>(model, cubePositions[i]);
    381     float angle = 20.0f * i;
    382     model = <function id='57'>glm::rotate</function>(model, <function id='63'>glm::radians</function>(angle), glm::vec3(1.0f, 0.3f, 0.5f));
    383     lightingShader.setMat4("model", model);
    384 
    385     <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 36);
    386 }
    387 </code></pre>
    388   
    389 <p>
    390     Also, don't forget to actually specify the direction of the light source (note that we define the  direction as a direction <strong>from</strong> the light source; you can quickly see the light's direction is pointing downwards):
    391 </p>
    392   
    393 <pre><code>
    394 lightingShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f); 	    
    395 </code></pre>
    396   
    397 <note>
    398   <p>
    399   We've been passing the light's position and direction vectors as <code>vec3</code>s for a while now, but some people tend to prefer to keep all the vectors defined as <code>vec4</code>. When defining position vectors as a <code>vec4</code> it is important to set the <code>w</code> component to <code>1.0</code> so translation and projections are properly applied. However, when defining a direction vector as a <code>vec4</code> we don't want translations to have an effect (since they just represent directions, nothing more) so then we define the <code>w</code> component to be <code>0.0</code>.    
    400   </p>
    401   
    402   <p>
    403     Direction vectors can then be represented as: <code>vec4(-0.2f, -1.0f, -0.3f, 0.0f)</code>. This can also function as an easy check for light types: you could check if the <code>w</code> component is equal to <code>1.0</code> to see that we now have a light's position vector and if <code>w</code> is equal to <code>0.0</code> we have a light's direction vector; so adjust the calculations based on that:
    404   </p>
    405   
    406 <pre><code>
    407 if(lightVector.w == 0.0) // note: be careful for floating point errors
    408   // do directional light calculations
    409 else if(lightVector.w == 1.0)
    410   // do light calculations using the light's position (as in previous chapters)  
    411 </code></pre>
    412   
    413   <p>
    414     Fun fact: this is actually how the old OpenGL (fixed-functionality) determined if a light source was a directional light or a positional light source and adjusted its lighting based on that.
    415   </p>
    416 </note>
    417   
    418 <p>
    419     If you'd now compile the application and fly through the scene it looks like there is a sun-like light source casting light on all the objects. Can you see that the diffuse and specular components all react as if there was a light source somewhere in the sky? It'll look something like this:
    420 </p>
    421   
    422   <img src="/img/lighting/light_casters_directional_light.png" class="clean"/>
    423   
    424 <p>
    425   You can find the full source code of the application <a href="/code_viewer_gh.php?code=src/2.lighting/5.1.light_casters_directional/light_casters_directional.cpp" target="_blank">here</a>.  
    426 </p>
    427   
    428 <h1>Point lights</h1>
    429 <p>
    430 	Directional lights are great for global lights that illuminate the entire scene, but we usually also want several <def>point lights</def> scattered throughout the scene. A point light is a light source with a given position somewhere in a world that illuminates in all directions, where the light rays fade out over distance. Think of light bulbs and torches as light casters that act as a point light.  
    431 </p>
    432   
    433   <img src="/img/lighting/light_casters_point.png" class="clean"/>
    434   
    435   <p>
    436     In the earlier chapters we've been working with a simplistic point light. We had a light source at a given position that scatters light in all directions from that given light position. However, the light source we defined simulated light rays that never fade out thus making it look like the light source is extremely strong. In most 3D applications we'd like to simulate a light source that only illuminates an area close to the light source and not the entire scene. 
    437 </p>
    438   
    439   <p>
    440     If you'd add the 10 containers to the lighting scene from the previous chapters, you'd notice that the container all the way in the back is lit with the same intensity as the container in front of the light; there is no logic yet that diminishes light over distance. We want the container in the back to only be slightly lit in comparison to the containers close to the light source.
    441   </p>
    442   
    443 <h2>Attenuation</h2>
    444 <p>
    445   To reduce the intensity of light over the distance a light ray travels is generally called <def>attenuation</def>. One way to reduce the light intensity over distance is to simply use a linear equation. Such an equation would linearly reduce the light intensity over the distance thus making sure that objects at a distance are less bright. However, such a linear function tends to look a bit fake. In the real world, lights are generally quite bright standing close by, but the brightness of a light source diminishes quickly at a distance; the remaining light intensity  then slowly diminishes over distance. We are thus in need of a different equation for reducing the light's intensity.
    446 </p>
    447   
    448   <p>
    449     Luckily some smart people already figured this out for us. The following formula calculates an attenuation value based on a fragment's distance to the light source which we later multiply with the light's intensity vector:
    450   </p>
    451   
    452   \begin{equation} F_{att} = \frac{1.0}{K_c + K_l * d + K_q * d^2} \end{equation}
    453   
    454   <p>
    455     Here \(d\) represents the distance from the fragment to the light source. Then to calculate the attenuation value we define 3 (configurable) terms: a <def>constant</def> term \(K_c\), a <def>linear</def> term \(K_l\) and a <def>quadratic</def> term \(K_q\). 
    456     <ul>
    457       <li>The constant term is usually kept at <code>1.0</code> which is mainly there to make sure the denominator never gets smaller than <code>1</code> since it would otherwise boost the intensity with certain distances, which is not the effect we're looking for.</li>
    458       <li>The linear term is multiplied with the distance value that reduces the intensity in a linear fashion.</li>
    459       <li>The quadratic term is multiplied with the quadrant of the distance and sets a quadratic decrease of intensity for the light source. The quadratic term will be less significant compared to the linear term when the distance is small, but gets much larger as the distance grows. </li>
    460     </ul>
    461     Due to the quadratic term the light will diminish mostly at a linear fashion until the distance becomes large enough for the quadratic term to surpass the linear term and then the light intensity will decrease a lot faster. The resulting effect is that the light is quite intense when at a close range, but quickly loses its brightness over distance until it eventually loses its brightness at a more slower pace. The following graph shows the effect such an attenuation has over a distance of <code>100</code>:
    462   </p>
    463   
    464   <img src="/img/lighting/attenuation.png" class="clean"/>
    465   
    466   <p>
    467     You can see that the light has the highest intensity when the distance is small, but as soon as the distance grows its intensity is significantly reduced and slowly reaches <code>0</code> intensity at around a distance of <code>100</code>. This is exactly what we want.
    468   </p>
    469   
    470   <h3>Choosing the right values</h3>
    471   <p>
    472     But at what values do we set those 3 terms? Setting the right values depend on many factors: the environment, the distance you want a light to cover, the type of light etc. In most cases, it simply is a question of experience and a moderate amount of tweaking. The following table shows some of the values these terms could take to simulate a realistic (sort of) light source that covers a specific radius (distance). The first column specifies the distance a light will cover with the given terms. These values are good starting points for most lights, with courtesy of <a href="http://www.ogre3d.org/tikiwiki/tiki-index.php?page=-Point+Light+Attenuation" target="_blank">Ogre3D's wiki</a>:
    473   </p>
    474   
    475 <table>
    476   <tr>
    477   	<th>Distance</th>
    478   	<th>Constant</th>
    479   	<th>Linear</th>
    480   	<th>Quadratic</th>
    481   </tr>  
    482   <tr>
    483     <td><code>7</code></td>
    484  	<td><code>1.0</code></td>
    485   	<td><code>0.7</code></td>
    486  	<td><code>1.8</code></td> 
    487   </tr>
    488   <tr>
    489     <td><code>13</code></td>
    490  	<td><code>1.0</code></td>
    491   	<td><code>0.35</code></td>
    492  	<td><code>0.44</code></td> 
    493   </tr>
    494   <tr>
    495     <td><code>20</code></td>
    496  	<td><code>1.0</code></td>
    497   	<td><code>0.22</code></td>
    498  	<td><code>0.20</code></td> 
    499   </tr>
    500   <tr>
    501     <td><code>32</code></td>
    502  	<td><code>1.0</code></td>
    503   	<td><code>0.14</code></td>
    504  	<td><code>0.07</code></td> 
    505   </tr><tr>
    506     <td><code>50</code></td>
    507  	<td><code>1.0</code></td>
    508   	<td><code>0.09</code></td>
    509  	<td><code>0.032</code></td> 
    510   </tr>
    511   <tr>
    512     <td><code>65</code></td>
    513  	<td><code>1.0</code></td>
    514   	<td><code>0.07</code></td>
    515  	<td><code>0.017</code></td> 
    516   </tr><tr>
    517     <td><code>100</code></td>
    518  	<td><code>1.0</code></td>
    519   	<td><code>0.045</code></td>
    520  	<td><code>0.0075</code></td> 
    521   </tr><tr>
    522     <td><code>160</code></td>
    523  	<td><code>1.0</code></td>
    524   	<td><code>0.027</code></td>
    525  	<td><code>0.0028</code></td> 
    526   </tr>
    527   <tr>
    528     <td><code>200</code></td>
    529  	<td><code>1.0</code></td>
    530   	<td><code>0.022</code></td>
    531  	<td><code>0.0019</code></td> 
    532   </tr><tr>
    533     <td><code>325</code></td>
    534  	<td><code>1.0</code></td>
    535   	<td><code>0.014</code></td>
    536  	<td><code>0.0007</code></td> 
    537   </tr>
    538   <tr>
    539     <td><code>600</code></td>
    540  	<td><code>1.0</code></td>
    541   	<td><code>0.007</code></td>
    542  	<td><code>0.0002</code></td> 
    543   </tr>
    544   <tr>
    545     <td><code>3250</code></td>
    546  	<td><code>1.0</code></td>
    547   	<td><code>0.0014</code></td>
    548  	<td><code>0.000007</code></td> 
    549   </tr>
    550 </table>
    551   
    552 <p>
    553   As you can see, the constant term \(K_c\) is kept at <code>1.0</code> in all cases. The linear term \(K_l\) is usually quite small to cover larger distances and the quadratic term \(K_q\) is even smaller. Try to experiment a bit with these values to see their effect in your implementation. In our environment a distance of <code>32</code> to <code>100</code> is generally enough for most lights.
    554 </p>
    555   
    556 <h3>Implementing attenuation</h3>
    557 <p>
    558     To implement attenuation we'll be needing 3 extra values in the fragment shader: namely the constant, linear and quadratic terms of the equation. These are best stored in the <fun>Light</fun> struct we defined earlier. Note that we need to calculate <var>lightDir</var> again using <var>position</var> as this is a point light (as we did in the previous chapter) and not a directional light.
    559 </p>
    560 
    561 <pre><code>
    562 struct Light {
    563     vec3 position;  
    564   
    565     vec3 ambient;
    566     vec3 diffuse;
    567     vec3 specular;
    568 	
    569     float constant;
    570     float linear;
    571     float quadratic;
    572 }; 
    573 </code></pre>
    574   
    575 <p>
    576   Then we set the terms in our application: we want the light to cover a distance of <code>50</code> so we'll use the appropriate constant, linear and quadratic terms from the table:
    577 </p>
    578   
    579 <pre><code>		
    580 lightingShader.setFloat("light.constant",  1.0f);
    581 lightingShader.setFloat("light.linear",    0.09f);
    582 lightingShader.setFloat("light.quadratic", 0.032f);	    
    583 </code></pre>
    584     
    585   <p>
    586     Implementing attenuation in the fragment shader is relatively straightforward: we simply calculate an attenuation value based on the equation and multiply this with the ambient, diffuse and specular components. 
    587   </p>
    588   
    589 <p>
    590   We do need the distance to the light source for the equation to work though. Remember how we can calculate the length of a vector? We can retrieve the distance term by calculating the difference vector between the fragment and the light source and take that resulting vector's length. We can use GLSL's built-in <fun>length</fun> function for that purpose:
    591   </p>
    592   
    593 <pre><code>
    594 float distance    = length(light.position - FragPos);
    595 float attenuation = 1.0 / (light.constant + light.linear * distance + 
    596     		    light.quadratic * (distance * distance));    
    597 </code></pre>
    598   
    599 <p>
    600   Then we include this attenuation value in the lighting calculations by multiplying the attenuation value with the ambient, diffuse and specular colors.
    601   </p>
    602   
    603   <note>
    604     We could leave the ambient component alone so ambient lighting is not decreased over distance, but if we were to use more than 1 light source all the ambient components will start to stack up. In that case we want to attenuate ambient lighting as well. Simply play around with what's best for your environment.
    605   </note>
    606   
    607 <pre><code>
    608 ambient  *= attenuation; 
    609 diffuse  *= attenuation;
    610 specular *= attenuation;   
    611 </code></pre>
    612   
    613 <p>
    614     If you'd run the application you'd get something like this:
    615 </p>
    616   
    617   <img src="/img/lighting/light_casters_point_light.png" class="clean"/>
    618   
    619   <p>
    620     You can see that right now only the front containers are lit with the closest container being the brightest. The containers in the back are not lit at all since they're too far from the light source. You can find the source code of the application <a href="/code_viewer_gh.php?code=src/2.lighting/5.2.light_casters_point/light_casters_point.cpp" target="_blank">here</a>.
    621   </p>
    622   
    623   <p>
    624     A point light is thus a light source with a configurable location and attenuation applied to its lighting calculations. Yet another type of light for our lighting arsenal.
    625   </p>
    626 
    627 <h1>Spotlight</h1>
    628 <p>
    629   The last type of light we're going to discuss is a <def>spotlight</def>. A spotlight is a light source that is located somewhere in the environment that, instead of shooting light rays in all directions, only shoots them in a specific direction. The result is that only the objects within a certain radius of the spotlight's direction are lit and everything else stays dark. A good example of a spotlight would be a street lamp or a flashlight.
    630 </p>
    631   
    632 <p>
    633   A spotlight in OpenGL is represented by a world-space position, a direction and a <def>cutoff</def> angle that specifies the radius of the spotlight. For each fragment we calculate if the fragment is between the spotlight's cutoff directions (thus in its cone) and if so, we lit the fragment accordingly. The following image gives you an idea of how a spotlight works:   
    634 </p>
    635   
    636   <img src="/img/lighting/light_casters_spotlight_angles.png" class="clean"/>
    637   
    638 <p>
    639   <ul>
    640     <li><code>LightDir</code>: the vector pointing from the fragment to the light source.</li>
    641     <li><code>SpotDir</code>: the direction the spotlight is aiming at.</li>
    642     <li><code>Phi</code> \(\phi\): the cutoff angle that specifies the spotlight's radius. Everything outside this angle is not lit by the spotlight.</li>
    643     <li><code>Theta</code> \(\theta\): the angle between the <var>LightDir</var> vector and the <var>SpotDir</var> vector. The \(\theta\) value should be smaller than \(\Phi\) to be inside the spotlight. </li>
    644   </ul>  
    645 </p>
    646   
    647 <p>
    648    So what we basically need to do, is calculate the dot product (returns the cosine of the angle between two unit vectors) between the <var>LightDir</var> vector and the <var>SpotDir</var> vector and compare this with the cutoff angle \(\phi\). Now that you (sort of) understand what a spotlight is all about we're going to create one in the form of a flashlight.
    649 </p>
    650   
    651 <h2>Flashlight</h2>
    652 <p>
    653    A flashlight is a spotlight located at the viewer's position and usually aimed straight ahead from the player's perspective. A flashlight is basically a normal spotlight, but with its position and direction continually updated based on the player's position and orientation. 
    654 </p>
    655   
    656 <p>
    657     So, the values we're going to need for the fragment shader are the spotlight's position vector (to calculate the fragment-to-light's direction vector), the spotlight's direction vector and the cutoff angle. We can store these values in the <fun>Light</fun> struct:
    658 </p>
    659   
    660 <pre><code>
    661 struct Light {
    662     vec3  position;
    663     vec3  direction;
    664     float cutOff;
    665     ...
    666 };    
    667 </code></pre>
    668   
    669 <p>
    670   Next we pass the appropriate values to the shader:
    671 </p>
    672   
    673 <pre><code>
    674 lightingShader.setVec3("light.position",  camera.Position);
    675 lightingShader.setVec3("light.direction", camera.Front);
    676 lightingShader.setFloat("light.cutOff",   glm::cos(<function id='63'>glm::radians</function>(12.5f)));
    677 </code></pre>
    678   
    679 <p>
    680   As you can see we're not setting an angle for the cutoff value but calculate the cosine value based on an angle and pass the cosine result to the fragment shader. The reason for this is that in the fragment shader we're calculating the dot product between the <code>LightDir</code> and the <code>SpotDir</code> vector and the dot product returns a cosine value and not an angle; and we can't directly compare an angle with a cosine value. To get the angle in the shader we then have to calculate the inverse cosine of the dot product's result which is an expensive operation. So to save some performance we calculate the cosine value of a given cutoff angle beforehand and pass this result to the fragment shader. Since both angles are now represented as cosines, we can directly compare between them without expensive operations.
    681 </p>
    682   
    683 <p>
    684   Now what's left to do is calculate the theta \(\theta\) value and compare this with the cutoff \(\phi\) value to determine if we're in or outside the spotlight:
    685 </p>
    686   
    687 <pre><code>
    688 float theta = dot(lightDir, normalize(-light.direction));
    689     
    690 if(theta > light.cutOff) 
    691 {       
    692   // do lighting calculations
    693 }
    694 else  // else, use ambient light so scene isn't completely dark outside the spotlight.
    695   color = vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0);
    696 </code></pre>
    697   
    698 <p>
    699   We first calculate the dot product between the <var>lightDir</var> vector and the negated <var>direction</var> vector (negated, because we want the vectors to point towards the light source, instead of from). Be sure to normalize all the relevant vectors.
    700 </p>
    701   
    702 <note>
    703   <p>
    704   You may be wondering why there is a <code>&gt;</code> sign instead of a <code>&lt;</code> sign in the <code>if</code> guard. Shouldn't <var>theta</var> be smaller than the light's cutoff value to be inside the spotlight? That is right, but don't forget angle values are represented as cosine values and an angle of <code>0</code> degrees is represented as the cosine value of <code>1.0</code> while an angle of <code>90</code> degrees is represented as the cosine value of <code>0.0</code> as you can see here:
    705   </p>
    706   
    707   <img src="/img/lighting/light_casters_cos.png"/>
    708   
    709   <p>
    710   You can now see that the closer the cosine value is to <code>1.0</code> the smaller its angle. Now it makes sense why <var>theta</var> needs to be larger than the cutoff value. The cutoff value is currently set at the cosine of <code>12.5</code> which is equal to <code>0.976</code> so a cosine <var>theta</var> value between <code>0.976</code> and <code>1.0</code> would result in the fragment being lit as if inside the spotlight.
    711   </p>
    712 </note>
    713   
    714   <p>
    715     Running the application results in a spotlight that only lights the fragments that are directly inside the cone of the spotlight. It'll look something like this:    
    716   </p>
    717   
    718   <img src="/img/lighting/light_casters_spotlight_hard.png" class="clean"/>
    719   
    720   <p>
    721     You can find the full source code <a href="/code_viewer_gh.php?code=src/2.lighting/5.3.light_casters_spot/light_casters_spot.cpp" target="_blank">here</a>.
    722   </p>
    723   
    724   <p>
    725     It still looks a bit fake though, mostly because the spotlight has hard edges. Wherever a fragment reaches the edge of the spotlight's cone it is shut down completely instead of with a nice smooth fade. A realistic spotlight would reduce the light gradually around its edges. 
    726   </p>
    727 
    728 <h2>Smooth/Soft edges</h2>
    729 <p>
    730   To create the effect of a smoothly-edged spotlight we want to simulate a spotlight having an <def>inner</def> and an <def>outer</def> cone. We can set the inner cone as the cone defined in the previous section, but we also want an outer cone that gradually dims the light from the inner to the edges of the outer cone. 
    731 </p>
    732   
    733 <p>
    734     To create an outer cone we simply define another cosine value that represents the angle between the spotlight's direction vector and the outer cone's vector (equal to its radius). Then, if a fragment is between the inner and the outer cone it should calculate an intensity value between <code>0.0</code> and <code>1.0</code>. If the fragment is inside the inner cone its intensity is equal to <code>1.0</code> and <code>0.0</code> if the fragment is outside the outer cone.
    735 </p>
    736   
    737 <p>
    738    We can calculate such a value using the following equation:
    739   
    740   \begin{equation} I = \frac{\theta - \gamma}{\epsilon} \end{equation}
    741   
    742   Here \(\epsilon\) (epsilon) is the cosine difference between the inner (\(\phi\)) and the outer cone (\(\gamma\)) (\(\epsilon =  \phi - \gamma\)). The resulting \(I\) value is then the  intensity of the spotlight at the current fragment. 
    743   </p>
    744   
    745   <p>
    746     It is a bit hard to visualize how this formula actually works so let's try it out with a few sample values:
    747 </p>
    748   
    749 
    750 <table>
    751   <tr>
    752   	<th>\(\theta\)</th>
    753     <th>\(\theta\) in degrees</th>
    754   	<th>\(\phi\) (inner cutoff)</th>
    755     <th>\(\phi\) in degrees</th>
    756   	<th>\(\gamma\) (outer cutoff)</th>
    757     <th>\(\gamma\) in degrees</th>
    758   	<th>\(\epsilon\)</th>
    759     <th>\(I\)</th>
    760   </tr>  
    761   <tr>
    762     <td><code>0.87</code></td>
    763     <td><code>30</code></td>
    764  	<td><code>0.91</code></td>
    765   	<td><code>25</code></td>
    766  	<td><code>0.82</code></td> 
    767     <td><code>35</code></td> 
    768     <td><code>0.91 - 0.82 = 0.09</code></td> 
    769     <td><code>0.87 - 0.82 / 0.09 = 0.56</code></td> 
    770   </tr>
    771   <tr>
    772     <td><code>0.9</code></td>
    773     <td><code>26</code></td>
    774  	<td><code>0.91</code></td>
    775   	<td><code>25</code></td>
    776  	<td><code>0.82</code></td> 
    777     <td><code>35</code></td> 
    778     <td><code>0.91 - 0.82 = 0.09</code></td> 
    779     <td><code>0.9 - 0.82 / 0.09 = 0.89</code></td> 
    780   </tr>
    781   <tr>
    782     <td><code>0.97</code></td>
    783     <td><code>14</code></td>
    784  	<td><code>0.91</code></td>
    785   	<td><code>25</code></td>
    786  	<td><code>0.82</code></td> 
    787     <td><code>35</code></td> 
    788     <td><code>0.91 - 0.82 = 0.09</code></td> 
    789     <td><code>0.97 - 0.82 / 0.09 = 1.67</code></td> 
    790   </tr>
    791   <tr>
    792     <td><code>0.83</code></td>
    793     <td><code>34</code></td>
    794  	<td><code>0.91</code></td>
    795   	<td><code>25</code></td>
    796  	<td><code>0.82</code></td> 
    797     <td><code>35</code></td> 
    798     <td><code>0.91 - 0.82 = 0.09</code></td> 
    799     <td><code>0.83 - 0.82 / 0.09 = 0.11</code></td> 
    800   </tr>
    801   <tr>
    802     <td><code>0.64</code></td>
    803     <td><code>50</code></td>
    804  	<td><code>0.91</code></td>
    805   	<td><code>25</code></td>
    806  	<td><code>0.82</code></td> 
    807     <td><code>35</code></td> 
    808     <td><code>0.91 - 0.82 = 0.09</code></td> 
    809     <td><code>0.64 - 0.82 / 0.09 = -2.0</code></td> 
    810   </tr>
    811   <tr>
    812     <td><code>0.966</code></td>
    813     <td><code>15</code></td>
    814  	<td><code>0.9978</code></td>
    815   	<td><code>12.5</code></td>
    816  	<td><code>0.953</code></td> 
    817     <td><code>17.5</code></td> 
    818     <td><code>0.9978 - 0.953 = 0.0448</code></td> 
    819     <td><code>0.966 - 0.953 / 0.0448 = 0.29</code></td> 
    820   </tr>
    821 </table>
    822  
    823 <p>
    824   As you can see we're basically interpolating between the outer cosine and the inner cosine based on the \(\theta\) value. If you still don't really see what's going on, don't worry, you can simply take the formula for granted and return here when you're much older and wiser.
    825 </p>
    826   
    827 <p>
    828   We now have an intensity value that is either negative when outside the spotlight, higher than <code>1.0</code> when inside the inner cone, and somewhere in between around the edges. If we properly clamp the values we don't need an <code>if-else</code> in the fragment shader anymore and we can simply multiply the light components with the calculated intensity value:
    829 </p>
    830   
    831 <pre><code>
    832 float theta     = dot(lightDir, normalize(-light.direction));
    833 float epsilon   = light.cutOff - light.outerCutOff;
    834 float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);    
    835 ...
    836 // we'll leave ambient unaffected so we always have a little light.
    837 diffuse  *= intensity;
    838 specular *= intensity;
    839 ...
    840 </code></pre>
    841   
    842 <p>
    843   Note that we use the <fun>clamp</fun> function that <def>clamps</def> its first argument between the values <code>0.0</code> and <code>1.0</code>. This makes sure the intensity values won't end up outside the [<code>0</code>, <code>1</code>] range.
    844 </p>
    845   
    846 <p>
    847   Make sure you add the <var>outerCutOff</var> value to the <fun>Light</fun> struct and set its uniform value in the application. For the following image an inner cutoff angle of <code>12.5</code> and an outer cutoff angle of <code>17.5</code> was used:
    848 </p>
    849   
    850   <img src="/img/lighting/light_casters_spotlight.png" class="clean"/>
    851  
    852  <p>
    853    Ahhh, that's much better. Play around with the inner and outer cutoff angles and try to create a spotlight that better suits your needs. You can find the source code of the application <a href="/code_viewer_gh.php?code=src/2.lighting/5.4.light_casters_spot_soft/light_casters_spot_soft.cpp" target="_blank">here</a>.
    854   </p>
    855   
    856 <p>
    857   Such a flashlight/spotlight type of lamp is perfect for horror games and combined with directional and point lights the environment will really start to light up. 
    858 </p>
    859   
    860 <h2>Exercises</h2>
    861   <ul>
    862   <li>Try experimenting with all the different light types and their fragment shaders. Try inverting some vectors and/or use &lt; instead of &gt;. Try to explain the different visual outcomes.</li>
    863   </ul>       
    864 
    865     </div>
    866     
    867 	</main>
    868 </body>
    869 </html>