LearnOpenGL

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

Point-Shadows.html (40774B)


      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">Point Shadows</h1>
    319 <h1 id="content-url" style='display:none;'>Advanced-Lighting/Shadows/Point-Shadows</h1>
    320 <p>
    321   In the last chapter we learned to create dynamic shadows with shadow mapping. It works great, but it's mostly suited for directional (or spot) lights as the shadows are generated only in the direction of the light source. It is therefore also known as <def>directional shadow mapping</def> as the depth (or shadow) map is generated from only the direction the light is looking at.   
    322 </p>
    323 
    324 <p>
    325   What this chapter will focus on is the generation of dynamic shadows in all surrounding directions. The technique we're using is perfect for point lights as a real point light would cast shadows in all directions. This technique is known as point (light) shadows or more formerly as <def>omnidirectional shadow maps</def>.
    326 </p>
    327 
    328 <note>
    329   This chapter builds upon the previous <a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping" target="_blank">shadow mapping</a> chapter so unless you're familiar with traditional shadow mapping it is advised to read the shadow mapping chapter first.
    330 </note>
    331 
    332 <p>
    333   The technique is mostly similar to directional shadow mapping: we generate a depth map from the light's perspective(s), sample the depth map based on the current fragment position, and compare each fragment with the stored depth value to see whether it is in shadow. The main difference between directional shadow mapping and omnidirectional shadow mapping is the depth map we use.
    334 </p>
    335 
    336 <p>
    337   The depth map we need requires rendering a scene from all surrounding directions of a point light and as such a normal 2D depth map won't work; what if we were to use a <a href="https://learnopengl.com/Advanced-OpenGL/Cubemaps" target="_blank">cubemap</a> instead? Because a cubemap can store full environment data with only 6 faces, it is possible to render the entire scene to each of the faces of a cubemap and sample these as the point light's surrounding depth values.
    338 </p>
    339 
    340 <img src="/img/advanced-lighting/point_shadows_diagram.png" class="clean" alt="Image of how omnidrectional shadow mapping or point shadows work"/>
    341 
    342 <p>
    343   The generated depth cubemap is then passed to the lighting fragment shader that samples the cubemap with a direction vector to obtain the closest depth (from the light's perspective) at that fragment. Most of the complicated stuff we've already discussed in the shadow mapping chapter. What makes this technique a bit more difficult is the depth cubemap generation.
    344 </p>
    345   
    346 <h2>Generating the depth cubemap</h2>
    347 <p>
    348   To create a cubemap of a light's surrounding depth values we have to render the scene 6 times: once for each face. One (quite obvious) way to do this, is render the scene 6 times with 6 different view matrices, each time attaching a different cubemap face to the framebuffer object. This would look something like this:
    349   </p>
    350   
    351 <pre><code>
    352 for(unsigned int i = 0; i &lt; 6; i++)
    353 {
    354     GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
    355     <function id='81'>glFramebufferTexture2D</function>(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, face, depthCubemap, 0);
    356     BindViewMatrix(lightViewMatrices[i]);
    357     RenderScene();  
    358 }
    359 </code></pre>
    360   
    361 <p>
    362   This can be quite expensive though as a lot of render calls are necessary for this single depth map. In this chapter we're going to use an alternative (more organized) approach using a little trick in the geometry shader that allows us to build the depth cubemap with just a single render pass. 
    363 </p>
    364   
    365 <p>
    366   First, we'll need to create a cubemap:
    367 </p>
    368   
    369 <pre><code>
    370 unsigned int depthCubemap;
    371 <function id='50'>glGenTextures</function>(1, &depthCubemap);
    372 </code></pre>
    373   
    374 <p>
    375   And assign each of the single cubemap faces a 2D depth-valued texture image:
    376 </p>
    377   
    378 <pre><code>
    379 const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
    380 <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, depthCubemap);
    381 for (unsigned int i = 0; i &lt; 6; ++i)
    382         <function id='52'>glTexImage2D</function>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, 
    383                      SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);  
    384 </code></pre>
    385   
    386 <p>
    387   And don't forget to set the texture parameters:
    388 </p>
    389   
    390 <pre><code>
    391 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    392 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    393 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    394 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    395 <function id='15'>glTexParameter</function>i(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);  
    396 </code></pre>
    397 
    398 <p>
    399   Normally we'd attach a single face of a cubemap texture to the framebuffer object and render the scene 6 times, each time switching the depth buffer target of the framebuffer to a different cubemap face. Since we're going to use a geometry shader, that allows us to render to all faces in a single pass, we can directly attach the cubemap as a framebuffer's depth attachment with <fun>glFramebufferTexture</fun>:
    400 </p>
    401   
    402 <pre class="cpp"><code>
    403 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, depthMapFBO);
    404 glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0);
    405 glDrawBuffer(GL_NONE);
    406 glReadBuffer(GL_NONE);
    407 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, 0);  
    408 </code></pre>
    409   
    410 <p>
    411   Again, note the call to <fun>glDrawBuffer</fun> and <fun>glReadBuffer</fun>: we only care about depth values when generating a depth cubemap so we have to explicitly tell OpenGL this framebuffer object does not render to a color buffer. 
    412 </p>
    413   
    414 <p>
    415   With omnidirectional shadow maps we have two render passes: first, we generate the depth cubemap and second, we use the depth cubemap in the normal render pass to add shadows to the scene. This process looks a bit like this:
    416 </p>
    417   
    418 <pre><code>
    419 // 1. first render to depth cubemap
    420 <function id='22'>glViewport</function>(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
    421 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, depthMapFBO);
    422     <function id='10'>glClear</function>(GL_DEPTH_BUFFER_BIT);
    423     ConfigureShaderAndMatrices();
    424     RenderScene();
    425 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, 0);
    426 // 2. then render scene as normal with shadow mapping (using depth cubemap)
    427 <function id='22'>glViewport</function>(0, 0, SCR_WIDTH, SCR_HEIGHT);
    428 <function id='10'>glClear</function>(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    429 ConfigureShaderAndMatrices();
    430 <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, depthCubemap);
    431 RenderScene();
    432 </code></pre>
    433   
    434 <p>
    435   The process is exactly the same as with default shadow mapping, although this time we render to and use a cubemap depth texture compared to a 2D depth texture. 
    436 </p>
    437   
    438 <h3>Light space transform</h3>
    439 <p>
    440   With the framebuffer and cubemap set, we need some way to transform all the scene's geometry to the relevant light spaces in all 6 directions of the light. Just like the <a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping" target="_blank">shadow mapping</a> chapter we're going to need a light space transformation matrix \(T\), but this time one for each face.
    441 </p>
    442   
    443 <p>
    444   Each light space transformation matrix contains both a projection and a view matrix. For the projection matrix we're going to use a perspective projection matrix; the light source represents a point in space so perspective projection makes most sense. Each light space transformation matrix uses the same projection matrix:
    445 </p>
    446   
    447 <pre><code>
    448 float aspect = (float)SHADOW_WIDTH/(float)SHADOW_HEIGHT;
    449 float near = 1.0f;
    450 float far = 25.0f;
    451 glm::mat4 shadowProj = <function id='58'>glm::perspective</function>(<function id='63'>glm::radians</function>(90.0f), aspect, near, far); 
    452 </code></pre>
    453   
    454 <p>
    455   Important to note here is the field of view parameter of <fun><function id='58'>glm::perspective</function></fun> that we set to 90 degrees. By setting this to 90 degrees we make sure the viewing field is exactly large enough to fill a single face of the cubemap such that all faces align correctly to each other at the edges.
    456 </p>
    457   
    458 <p>
    459   As the projection matrix does not change per direction we can re-use it for each of the 6 transformation matrices. We do need a different view matrix per direction. With <fun><function id='62'>glm::lookAt</function></fun> we create 6 view directions, each looking at one face direction of the cubemap in the order: right, left, top, bottom, near and far.
    460 </p>
    461   
    462 <pre><code>
    463 std::vector&lt;glm::mat4&gt; shadowTransforms;
    464 shadowTransforms.push_back(shadowProj * 
    465                  <function id='62'>glm::lookAt</function>(lightPos, lightPos + glm::vec3( 1.0, 0.0, 0.0), glm::vec3(0.0,-1.0, 0.0));
    466 shadowTransforms.push_back(shadowProj * 
    467                  <function id='62'>glm::lookAt</function>(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0,-1.0, 0.0));
    468 shadowTransforms.push_back(shadowProj * 
    469                  <function id='62'>glm::lookAt</function>(lightPos, lightPos + glm::vec3( 0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, 1.0));
    470 shadowTransforms.push_back(shadowProj * 
    471                  <function id='62'>glm::lookAt</function>(lightPos, lightPos + glm::vec3( 0.0,-1.0, 0.0), glm::vec3(0.0, 0.0,-1.0));
    472 shadowTransforms.push_back(shadowProj * 
    473                  <function id='62'>glm::lookAt</function>(lightPos, lightPos + glm::vec3( 0.0, 0.0, 1.0), glm::vec3(0.0,-1.0, 0.0));
    474 shadowTransforms.push_back(shadowProj * 
    475                  <function id='62'>glm::lookAt</function>(lightPos, lightPos + glm::vec3( 0.0, 0.0,-1.0), glm::vec3(0.0,-1.0, 0.0));
    476 </code></pre>
    477   
    478 <p>
    479 	Here we create 6 view matrices and multiply them with the projection matrix to get a total of 6 different light space transformation matrices. The <code>target</code> parameter of <fun><function id='62'>glm::lookAt</function></fun> each looks into the direction of a single cubemap face.
    480 </p>
    481   
    482 <p>
    483   These transformation matrices are sent to the shaders that render the depth into the cubemap.
    484 </p>
    485   
    486 <h3>Depth shaders</h3>
    487 <p>
    488   To render depth values to a depth cubemap we're going to need a total of three shaders: a vertex and fragment shader, and a <a href="https://learnopengl.com/Advanced-OpenGL/Geometry-Shader" target="_blank">geometry shader</a> in between.
    489 </p>
    490   
    491 <p>
    492   The geometry shader will be the shader responsible for transforming all world-space vertices to the 6 different light spaces. Therefore, the vertex shader simply transforms vertices to world-space and directs them to the geometry shader:
    493 </p>
    494   
    495 <pre><code>
    496 #version 330 core
    497 layout (location = 0) in vec3 aPos;
    498 
    499 uniform mat4 model;
    500 
    501 void main()
    502 {
    503     gl_Position = model * vec4(aPos, 1.0);
    504 }  
    505 </code></pre>
    506   
    507 <p>
    508   The geometry shader will take as input 3 triangle vertices and a uniform array of light space transformation matrices. The geometry shader is responsible for transforming the vertices to the light spaces; this is also where it gets interesting. 
    509   </p>
    510   
    511   <p>
    512     The geometry shader has a built-in variable called <var>gl_Layer</var> that specifies which cubemap face to emit a primitive to. When left alone, the geometry shader just sends its primitives further down the pipeline as usual, but when we update this variable we can control to which cubemap face we render to for each primitive. This of course only works when we have a cubemap texture attached to the active framebuffer.
    513 </p>
    514   
    515 <pre><code>
    516 #version 330 core
    517 layout (triangles) in;
    518 layout (triangle_strip, max_vertices=18) out;
    519 
    520 uniform mat4 shadowMatrices[6];
    521 
    522 out vec4 FragPos; // FragPos from GS (output per emitvertex)
    523 
    524 void main()
    525 {
    526     for(int face = 0; face &lt; 6; ++face)
    527     {
    528         gl_Layer = face; // built-in variable that specifies to which face we render.
    529         for(int i = 0; i &lt; 3; ++i) // for each triangle vertex
    530         {
    531             FragPos = gl_in[i].gl_Position;
    532             gl_Position = shadowMatrices[face] * FragPos;
    533             EmitVertex();
    534         }    
    535         EndPrimitive();
    536     }
    537 }  
    538 </code></pre>
    539   
    540 <p>
    541   This geometry shader is relatively straightforward. We take as input a triangle, and output a total of 6 triangles (6 * 3 equals 18 vertices). In the <fun>main</fun> function we iterate over 6 cubemap faces where we specify each face as the output face by storing the face integer into <var>gl_Layer</var>. We then generate the output triangles by transforming each world-space input vertex to the relevant light space by multiplying <var>FragPos</var> with the face's light-space transformation matrix. Note that we also sent the resulting <var>FragPos</var> variable to the fragment shader that we'll need to calculate a depth value.
    542 </p>
    543   
    544 <p>
    545   In the last chapter we used an empty fragment shader and let OpenGL figure out the depth values of the depth map. This time we're going to calculate our own (linear) depth as the linear distance between each closest fragment position and the light source's position. Calculating our own depth values makes the later shadow calculations a bit more intuitive.
    546 </p>
    547   
    548 <pre><code>
    549 #version 330 core
    550 in vec4 FragPos;
    551 
    552 uniform vec3 lightPos;
    553 uniform float far_plane;
    554 
    555 void main()
    556 {
    557     // get distance between fragment and light source
    558     float lightDistance = length(FragPos.xyz - lightPos);
    559     
    560     // map to [0;1] range by dividing by far_plane
    561     lightDistance = lightDistance / far_plane;
    562     
    563     // write this as modified depth
    564     gl_FragDepth = lightDistance;
    565 }  
    566 </code></pre>
    567 
    568 <p>
    569   The fragment shader takes as input the <var>FragPos</var> from the geometry shader, the light's position vector, and the frustum's far plane value. Here we take the distance between the fragment and the light source, map it to the [<code>0</code>,<code>1</code>] range and write it as the fragment's depth value. 
    570 </p>
    571   
    572 <p>
    573   Rendering the scene with these shaders and the cubemap-attached framebuffer object active should give you a completely filled depth cubemap for the second pass's shadow calculations.
    574 </p>
    575   
    576 <h2>Omnidirectional shadow maps</h2>
    577 <p>
    578   With everything set up it is time to render the actual omnidirectional shadows. The procedure is similar to the directional shadow mapping chapter, although this time we bind a cubemap texture instead of a 2D texture and also pass the light projection's far plane variable to the shaders.
    579 </p>
    580   
    581 <pre><code>
    582 <function id='22'>glViewport</function>(0, 0, SCR_WIDTH, SCR_HEIGHT);
    583 <function id='10'>glClear</function>(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    584 shader.use();  
    585 // ... send uniforms to shader (including light's far_plane value)
    586 <function id='49'>glActiveTexture</function>(GL_TEXTURE0);
    587 <function id='48'>glBindTexture</function>(GL_TEXTURE_CUBE_MAP, depthCubemap);
    588 // ... bind other textures
    589 RenderScene();
    590 </code></pre>
    591   
    592 <p>
    593   Here the <fun>renderScene</fun> function renders a few cubes in a large cube room scattered around a light source at the center of the scene.
    594 </p>
    595   
    596 <p>
    597   The vertex and fragment shader are mostly similar to the original shadow mapping shaders: the difference being that the fragment shader no longer requires a fragment position in light space as we can now sample the depth values with a direction vector. 
    598 </p>
    599   
    600 <p>
    601   Because of this, the vertex shader doesn't needs to transform its position vectors to light space so we can remove the <var>FragPosLightSpace</var> variable:
    602 </p>
    603 
    604 <pre><code>
    605 #version 330 core
    606 layout (location = 0) in vec3 aPos;
    607 layout (location = 1) in vec3 aNormal;
    608 layout (location = 2) in vec2 aTexCoords;
    609 
    610 out vec2 TexCoords;
    611 
    612 out VS_OUT {
    613     vec3 FragPos;
    614     vec3 Normal;
    615     vec2 TexCoords;
    616 } vs_out;
    617 
    618 uniform mat4 projection;
    619 uniform mat4 view;
    620 uniform mat4 model;
    621 
    622 void main()
    623 {
    624     vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
    625     vs_out.Normal = transpose(inverse(mat3(model))) * aNormal;
    626     vs_out.TexCoords = aTexCoords;
    627     gl_Position = projection * view * model * vec4(aPos, 1.0);
    628 }  
    629 </code></pre>
    630   
    631 <p>
    632   The fragment shader's Blinn-Phong lighting code is exactly the same as we had before with a shadow multiplication at the end:
    633 </p>
    634   
    635 <pre><code>
    636 #version 330 core
    637 out vec4 FragColor;
    638 
    639 in VS_OUT {
    640     vec3 FragPos;
    641     vec3 Normal;
    642     vec2 TexCoords;
    643 } fs_in;
    644 
    645 uniform sampler2D diffuseTexture;
    646 uniform samplerCube depthMap;
    647 
    648 uniform vec3 lightPos;
    649 uniform vec3 viewPos;
    650 
    651 uniform float far_plane;
    652 
    653 float ShadowCalculation(vec3 fragPos)
    654 {
    655     [...]
    656 }
    657 
    658 void main()
    659 {           
    660     vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
    661     vec3 normal = normalize(fs_in.Normal);
    662     vec3 lightColor = vec3(0.3);
    663     // ambient
    664     vec3 ambient = 0.3 * color;
    665     // diffuse
    666     vec3 lightDir = normalize(lightPos - fs_in.FragPos);
    667     float diff = max(dot(lightDir, normal), 0.0);
    668     vec3 diffuse = diff * lightColor;
    669     // specular
    670     vec3 viewDir = normalize(viewPos - fs_in.FragPos);
    671     vec3 reflectDir = reflect(-lightDir, normal);
    672     float spec = 0.0;
    673     vec3 halfwayDir = normalize(lightDir + viewDir);  
    674     spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
    675     vec3 specular = spec * lightColor;    
    676     // calculate shadow
    677     float shadow = ShadowCalculation(fs_in.FragPos);                      
    678     vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;    
    679     
    680     FragColor = vec4(lighting, 1.0);
    681 }  
    682 </code></pre>
    683   
    684 <p>
    685   There are a few subtle differences: the lighting code is the same, but we now have a <code>samplerCube</code> uniform and the <fun>ShadowCalculation</fun> function takes the current fragment's position as its argument instead of the fragment position in light space. We now also include the light frustum's <var>far_plane</var> value that we'll later need.
    686 </p>
    687   
    688 <p>
    689   The biggest difference is in the content of the <fun>ShadowCalculation</fun> function that now samples depth values from a cubemap instead of a 2D texture. Let's discuss its content step by step.
    690 </p>
    691   
    692 <p>
    693   The first thing we have to do is retrieve the depth of the cubemap. You may remember from the cubemap section of this chapter that we stored the depth as the linear distance between the fragment and the light position; we're taking a similar approach here:
    694 </p>
    695   
    696 <pre><code>
    697 float ShadowCalculation(vec3 fragPos)
    698 {
    699     vec3 fragToLight = fragPos - lightPos; 
    700     float closestDepth = texture(depthMap, fragToLight).r;
    701 }  
    702 </code></pre>
    703   
    704 <p>
    705   Here we take the difference vector between the fragment's position and the light's position and use that vector as a direction vector to sample the cubemap. The direction vector doesn't need to be a unit vector to sample from a cubemap so there's no need to normalize it. The resulting <var>closestDepth</var> value is the normalized depth value between the light source and its closest visible fragment.
    706 </p>
    707   
    708 <p>
    709   The <var>closestDepth</var> value is currently in the range [<code>0</code>,<code>1</code>] so we first transform it back to [<code>0</code>,<code>far_plane</code>] by multiplying it with <var>far_plane</var>.
    710 </p>
    711   
    712 <pre><code>
    713 closestDepth *= far_plane;  
    714 </code></pre>
    715   
    716 <p>
    717   Next we retrieve the depth value between the current fragment and the light source, which we can easily obtain by taking the length of <var>fragToLight</var> due to how we calculated depth values in the cubemap:
    718 </p>
    719   
    720 <pre><code>
    721 float currentDepth = length(fragToLight);  
    722 </code></pre>
    723   
    724 <p>
    725   This returns a depth value in the same (or larger) range as <var>closestDepth</var>. 
    726 </p>
    727   
    728 <p>
    729   Now we can compare both depth values to see which is closer than the other and determine whether the current fragment is in shadow. We also include a shadow bias so we don't get shadow acne as discussed in the <a href="https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping" target="_blank">previous</a> chapter.
    730 </p>
    731   
    732 <pre><code>
    733 float bias = 0.05; 
    734 float shadow = currentDepth -  bias > closestDepth ? 1.0 : 0.0; 
    735 </code></pre>
    736   
    737 <p>
    738   The complete <fun>ShadowCalculation</fun> then becomes:
    739 </p>
    740   
    741 <pre><code>
    742 float ShadowCalculation(vec3 fragPos)
    743 {
    744     // get vector between fragment position and light position
    745     vec3 fragToLight = fragPos - lightPos;
    746     // use the light to fragment vector to sample from the depth map    
    747     float closestDepth = texture(depthMap, fragToLight).r;
    748     // it is currently in linear range between [0,1]. Re-transform back to original value
    749     closestDepth *= far_plane;
    750     // now get current linear depth as the length between the fragment and light position
    751     float currentDepth = length(fragToLight);
    752     // now test for shadows
    753     float bias = 0.05; 
    754     float shadow = currentDepth -  bias > closestDepth ? 1.0 : 0.0;
    755 
    756     return shadow;
    757 }  
    758 </code></pre>
    759   
    760 <p>
    761   With these shaders we already get pretty good shadows and this time in all surrounding directions from a point light. With a point light positioned at the center of a simple scene it'll look a bit like this:
    762 </p>
    763   
    764   <img src="/img/advanced-lighting/point_shadows.png" class="clean" alt="Omnidirectional point shadow maps in OpenGL"/>
    765     
    766 <p>
    767   You can find the source code of this demo <a href="/code_viewer_gh.php?code=src/5.advanced_lighting/3.2.1.point_shadows/point_shadows.cpp" target="_blank">here</a>.
    768 </p>
    769     
    770 <h3>Visualizing cubemap depth buffer</h3>
    771 <p>
    772   If you're somewhat like me you probably didn't get this right on the first try so it makes sense to do some debugging, with one of the obvious checks being validating whether the depth map was built correctly. A simple trick to visualize the depth buffer is to take the <var>closestDepth</var> variable in the <fun>ShadowCalculation</fun> function and display that variable as:
    773 </p>
    774     
    775 <pre><code>
    776 FragColor = vec4(vec3(closestDepth / far_plane), 1.0);  
    777 </code></pre>
    778     
    779 <p>
    780   The result is a grayed out scene where each color represents the linear depth values of the scene:
    781 </p>
    782     
    783     <img src="/img/advanced-lighting/point_shadows_depth_cubemap.png" class="clean" alt="Visualized depth cube map of omnidrectional shadow maps"/>
    784       
    785 <p>
    786   You can also see the to-be shadowed regions on the outside wall. If it looks somewhat similar, you know the depth cubemap was properly generated. 
    787 </p>
    788       
    789 <h2>PCF</h2>
    790 <p>
    791    Since omnidirectional shadow maps are based on the same principles of traditional shadow mapping it also has the same resolution dependent artifacts. If you zoom in close enough you can again see jagged edges. <def>Percentage-closer filtering</def> or PCF allows us to smooth out these jagged edges by filtering multiple samples around the fragment position and average the results. 
    792 </p>
    793       
    794 <p>
    795    If we take the same simple PCF filter of the previous chapter and add a third dimension we get:
    796 </p>
    797       
    798 <pre><code>
    799 float shadow  = 0.0;
    800 float bias    = 0.05; 
    801 float samples = 4.0;
    802 float offset  = 0.1;
    803 for(float x = -offset; x &lt; offset; x += offset / (samples * 0.5))
    804 {
    805     for(float y = -offset; y &lt; offset; y += offset / (samples * 0.5))
    806     {
    807         for(float z = -offset; z &lt; offset; z += offset / (samples * 0.5))
    808         {
    809             float closestDepth = texture(depthMap, fragToLight + vec3(x, y, z)).r; 
    810             closestDepth *= far_plane;   // undo mapping [0;1]
    811             if(currentDepth - bias &gt; closestDepth)
    812                 shadow += 1.0;
    813         }
    814     }
    815 }
    816 shadow /= (samples * samples * samples);
    817 </code></pre>
    818       
    819 <p>
    820  The code isn't that different from the traditional shadow mapping code. We calculate and add texture offsets dynamically for each axis based on a fixed number of samples. For each sample we repeat the original shadow process on the offsetted sample direction and average the results at the end.
    821 </p>
    822       
    823 <p>
    824     The shadows now look more soft and smooth and give more plausible results.
    825 </p>
    826       
    827       <img src="/img/advanced-lighting/point_shadows_soft.png" class="clean" alt="Soft shades with omnidirectional shadow mapping in OpenGL using PCF"/>
    828         
    829 <p>
    830   However, with <var>samples</var> set to <code>4.0</code> we take a total of <code>64</code> samples each fragment which is a lot!
    831 </p>
    832         
    833 <p>
    834   As most of these samples are redundant in that they sample close to the original direction vector it may make more sense to only sample in perpendicular directions of the sample direction vector. However as there is no (easy) way to figure out which sub-directions are redundant this becomes difficult. One trick we can use is to take an array of offset directions that are all roughly separable e.g. each of them points in completely different directions. This will significantly reduce the number of sub-directions that are close together. Below we have such an array of a maximum of <code>20</code> offset directions:
    835 </p>
    836         
    837 <pre><code>
    838 vec3 sampleOffsetDirections[20] = vec3[]
    839 (
    840    vec3( 1,  1,  1), vec3( 1, -1,  1), vec3(-1, -1,  1), vec3(-1,  1,  1), 
    841    vec3( 1,  1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1,  1, -1),
    842    vec3( 1,  1,  0), vec3( 1, -1,  0), vec3(-1, -1,  0), vec3(-1,  1,  0),
    843    vec3( 1,  0,  1), vec3(-1,  0,  1), vec3( 1,  0, -1), vec3(-1,  0, -1),
    844    vec3( 0,  1,  1), vec3( 0, -1,  1), vec3( 0, -1, -1), vec3( 0,  1, -1)
    845 );   
    846 </code></pre>
    847         
    848 <p>
    849   From this we can adapt the PCF algorithm to take a fixed amount of samples from <var>sampleOffsetDirections</var> and use these to sample the cubemap. The advantage here is that we need a lot less samples to get visually similar results.
    850 </p>
    851         
    852 <pre><code>
    853 float shadow = 0.0;
    854 float bias   = 0.15;
    855 int samples  = 20;
    856 float viewDistance = length(viewPos - fragPos);
    857 float diskRadius = 0.05;
    858 for(int i = 0; i &lt; samples; ++i)
    859 {
    860     float closestDepth = texture(depthMap, fragToLight + sampleOffsetDirections[i] * diskRadius).r;
    861     closestDepth *= far_plane;   // undo mapping [0;1]
    862     if(currentDepth - bias > closestDepth)
    863         shadow += 1.0;
    864 }
    865 shadow /= float(samples);  
    866 </code></pre>
    867         
    868 <p>
    869   Here we add multiple offsets, scaled by some <var>diskRadius</var>, around the original <var>fragToLight</var> direction vector to sample from the cubemap. 
    870 </p>
    871         
    872 <p>
    873   Another interesting trick we can apply here is that we can change <var>diskRadius</var> based on the distance of the viewer to the fragment, making the shadows softer when far away and sharper when close by.
    874 </p>
    875         
    876 <pre><code>
    877 float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;  
    878 </code></pre>
    879         
    880 <p>
    881   The results of the updated PCF algorithm gives just as good, if not better, results of soft shadows:
    882 </p>
    883         
    884 <img src="/img/advanced-lighting/point_shadows_soft_better.png" class="clean" alt="Soft shades with omnidirectional shadow mapping in OpenGL using PCF, more efficient"/>
    885   
    886 <p>
    887   Of course, the <var>bias</var> we add to each sample is highly based on context and will always require tweaking based on the scene you're working with. Play around with all the values and see how they affect the scene.
    888 </p>
    889   
    890 <p>
    891   You can find the final code here: <a href="/code_viewer_gh.php?code=src/5.advanced_lighting/3.2.2.point_shadows_soft/point_shadows_soft.cpp" target="_blank">here</a>.
    892 </p>   
    893   
    894 <p>
    895   I should mention that using geometry shaders to generate a depth map isn't necessarily faster than rendering the scene 6 times for each face. Using a geometry shader like this has its own performance penalties that may outweigh the performance gain of using one in the first place. This of course depends on the type of environment, the specific video card drivers, and plenty of other factors. So if you really care about pushing the most out of your system, make sure to profile both methods and select the more efficient one for your scene.
    896 </p>
    897   
    898 <h2>Additional resources</h2>
    899   <ul>
    900   <li><a href="http://www.sunandblackcat.com/tipFullView.php?l=eng&topicid=36" target="_blank">Shadow Mapping for point light sources in OpenGL</a>: omnidirectional shadow mapping tutorial by sunandblackcat.</li>
    901     <li><a href="http://ogldev.atspace.co.uk/www/tutorial43/tutorial43.html" target="_blank">Multipass Shadow Mapping With Point Lights</a>: omnidirectional shadow mapping tutorial by ogldev.</li>
    902     <li><a href="http://www.cg.tuwien.ac.at/~husky/RTR/OmnidirShadows-whyCaps.pdf" target="_blank">Omni-directional Shadows</a>: a nice set of slides about omnidirectional shadow mapping by Peter Houska.</li>
    903 </ul>       
    904 
    905     </div>
    906     
    907     <div id="hover">
    908         HI
    909     </div>
    910    <!-- 728x90/320x50 sticky footer -->
    911 <div id="waldo-tag-6196"></div>
    912 
    913    <div id="disqus_thread"></div>
    914 
    915     
    916 
    917 
    918 </div> <!-- container div -->
    919 
    920 
    921 </div> <!-- super container div -->
    922 </body>
    923 </html>
    924 	</main>
    925 </body>
    926 </html>