LearnOpenGL

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

HDR.html (29217B)


      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">HDR</h1>
    319 <h1 id="content-url" style='display:none;'>Advanced-Lighting/HDR</h1>
    320 <p>
    321   Brightness and color values, by default, are clamped between <code>0.0</code> and <code>1.0</code> when stored into a framebuffer. This, at first seemingly innocent, statement caused us to always specify light and color values somewhere in this range, trying to make them fit into the scene. This  works oké and gives decent results, but what happens if we walk in a really bright area with multiple bright light sources that as a total sum exceed <code>1.0</code>? The answer is that all fragments that have a brightness or color sum over <code>1.0</code> get clamped to <code>1.0</code>, which isn't pretty to look at:
    322 </p>
    323 
    324 <img src="/img/advanced-lighting/hdr_clamped.png" class="clean" alt="Color values clamped in bright areas"/>
    325   
    326 <p>
    327   Due to a large number of fragments' color values getting clamped to <code>1.0</code>, each of the bright fragments have the exact same white color value in large regions, losing a significant amount of detail and giving it a fake look.
    328 </p>
    329   
    330 <p>
    331   A solution to this problem would be to reduce the strength of the light sources and ensure no area of fragments in your scene ends up brighter than <code>1.0</code>; this is not a good solution as this forces you to use unrealistic lighting parameters. A better approach is to allow color values to temporarily exceed <code>1.0</code> and transform them back to the original range of <code>0.0</code> and <code>1.0</code> as a final step, but without losing detail.
    332 </p>
    333   
    334 <p>
    335   Monitors (non-HDR) are limited to display colors in the range of <code>0.0</code> and <code>1.0</code>, but there is no such limitation in lighting equations. By allowing fragment colors to exceed <code>1.0</code> we have a much higher range of color values available to work in known as <def>high dynamic range</def> (HDR). With high dynamic range, bright things can be really bright, dark things can be really dark, and details can be seen in both.
    336 </p>
    337   
    338 <p>
    339   High dynamic range was originally only used for photography where a photographer takes multiple pictures of the same scene with varying exposure levels, capturing a large range of color values. Combining these forms a HDR image where a large range of details are visible based on the combined exposure levels, or a specific exposure it is viewed with. For instance, the following image (credits to Colin Smith) shows a lot of detail at brightly lit regions with a low exposure (look at the window), but these details are gone with a high exposure. However, a high exposure now reveals a great amount of detail at darker regions that weren't previously visible.
    340 </p>
    341   
    342   <img src="/img/advanced-lighting/hdr_image.png" alt="HDR image showing multiple exposure levels and their respective details"/>
    343     
    344 <p>
    345   This is also very similar to how the human eye works and the basis of high dynamic range rendering. When there is little light, the human eye adapts itself so the darker parts become more visible and similarly for bright areas. It's like the human eye has an automatic exposure slider based on the scene's brightness.
    346 </p>
    347     
    348 <p>
    349   High dynamic range rendering works a bit like that. We allow for a much larger range of color values to render to, collecting a large range of dark and bright details of a scene, and at the end we transform all the HDR values back to the <def>low dynamic range</def> (LDR) of [<code>0.0</code>, <code>1.0</code>]. This process of converting HDR values to LDR values is called <def>tone mapping</def> and a large collection of tone mapping algorithms exist that aim to preserve most HDR details during the conversion process. These tone mapping algorithms often involve an exposure parameter that selectively favors dark or bright regions.
    350 </p>
    351     
    352 <p>
    353   When it comes to real-time rendering, high dynamic range allows us to not only exceed the LDR range of [<code>0.0</code>, <code>1.0</code>] and preserve more detail, but also gives us the ability to specify a light source's intensity by their <em>real</em> intensities. For instance, the sun has a much higher intensity than something like a flashlight so why not configure the sun as such (e.g. a diffuse brightness of <code>100.0</code>). This allows us to more properly configure a scene's lighting with more realistic lighting parameters, something that wouldn't be possible with LDR rendering as they'd then directly get clamped to <code>1.0</code>.
    354 </p>
    355 
    356 <p>
    357   As (non-HDR) monitors only display colors in the range between <code>0.0</code> and <code>1.0</code> we do need to transform the currently high dynamic range of color values back to the monitor's range. Simply re-transforming the colors back with a simple average wouldn't do us much good as brighter areas then become a lot more dominant. What we can do, is use different equations and/or curves to transform the HDR values back to LDR that give us complete control over the scene's brightness. This is the process earlier denoted as tone mapping and the final step of HDR rendering. 
    358 </p>
    359     
    360 <h2>Floating point framebuffers</h2>
    361 <p>
    362   To implement high dynamic range rendering we need some way to prevent color values getting clamped after each fragment shader run. When framebuffers use a normalized fixed-point color format (like <var>GL_RGB</var>) as their color buffer's internal format, OpenGL automatically clamps the values between <code>0.0</code> and <code>1.0</code> before storing them in the framebuffer. This operation holds for most types of framebuffer formats, except for floating point formats.
    363 </p>
    364     
    365 <p>
    366   When the internal format of a framebuffer's color buffer is specified as <var>GL_RGB16F</var>, <var>GL_RGBA16F</var>, <var>GL_RGB32F</var>, or <var>GL_RGBA32F</var> the framebuffer is known as a <def>floating point framebuffer</def> that can store floating point values outside the default range of <code>0.0</code> and <code>1.0</code>. This is perfect for rendering in high dynamic range!
    367 </p>
    368     
    369 <p>
    370   To create a floating point framebuffer the only thing we need to change is its color buffer's internal format parameter:
    371 </p>
    372     
    373 <pre><code>
    374 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, colorBuffer);
    375 <function id='52'>glTexImage2D</function>(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);  
    376 </code></pre>
    377     
    378 <p>
    379   The default framebuffer of OpenGL (by default) only takes up 8 bits per color component. With a floating point framebuffer with 32 bits per color component (when using <var>GL_RGB32F</var> or <var>GL_RGBA32F</var>) we're using 4 times more memory for storing color values. As 32 bits isn't really necessary (unless you need a high level of precision) using <var>GL_RGBA16F</var> will suffice.
    380 </p>
    381     
    382 <p>
    383   With a floating point color buffer attached to a framebuffer we can now render the scene into this framebuffer knowing color values won't get clamped between <code>0.0</code> and <code>1.0</code>. In this chapter's example demo we first render a lit scene into the floating point framebuffer and then display the framebuffer's color buffer on a screen-filled quad; it'll look a bit like this:
    384 </p>
    385     
    386 <pre><code>
    387 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, hdrFBO);
    388     <function id='10'>glClear</function>(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
    389     // [...] render (lit) scene 
    390 <function id='77'>glBindFramebuffer</function>(GL_FRAMEBUFFER, 0);
    391 
    392 // now render hdr color buffer to 2D screen-filling quad with tone mapping shader
    393 hdrShader.use();
    394 <function id='49'>glActiveTexture</function>(GL_TEXTURE0);
    395 <function id='48'>glBindTexture</function>(GL_TEXTURE_2D, hdrColorBufferTexture);
    396 RenderQuad();
    397 </code></pre>
    398     
    399 <p>
    400   Here a scene's color values are filled into a floating point color buffer which can contain any arbitrary color value, possibly exceeding <code>1.0</code>. For this chapter, a simple demo scene was created with a large stretched cube acting as a tunnel with four point lights, one being extremely bright positioned at the tunnel's end:
    401 </p>
    402     
    403 <pre><code>
    404 std::vector&lt;glm::vec3&gt; lightColors;
    405 lightColors.push_back(glm::vec3(200.0f, 200.0f, 200.0f));
    406 lightColors.push_back(glm::vec3(0.1f, 0.0f, 0.0f));
    407 lightColors.push_back(glm::vec3(0.0f, 0.0f, 0.2f));
    408 lightColors.push_back(glm::vec3(0.0f, 0.1f, 0.0f));  
    409 </code></pre>
    410     
    411 <p>
    412   Rendering to a floating point framebuffer is exactly the same as we would normally render into a framebuffer. What is new is <var>hdrShader</var>'s fragment shader that renders the final 2D quad with the floating point color buffer texture attached. Let's first define a simple pass-through fragment shader:
    413 </p>
    414     
    415 <pre><code>
    416 #version 330 core
    417 out vec4 FragColor;
    418   
    419 in vec2 TexCoords;
    420 
    421 uniform sampler2D hdrBuffer;
    422 
    423 void main()
    424 {             
    425     vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
    426     FragColor = vec4(hdrColor, 1.0);
    427 }  
    428 </code></pre>
    429     
    430 <p>
    431   Here we directly sample the floating point color buffer and use its color value as the fragment shader's output. However, as the 2D quad's output is directly rendered into the default framebuffer, all the fragment shader's output values will still end up clamped between <code>0.0</code> and <code>1.0</code> even though we have several values in the floating point color texture exceeding <code>1.0</code>. 
    432 </p>
    433     
    434     <img src="/img/advanced-lighting/hdr_direct.png" alt="Direct rendering of floating point color values to the default framebuffer without tone mapping."/>
    435   
    436 <p>
    437   It becomes clear the intense light values at the end of the tunnel are clamped to <code>1.0</code> as a large portion of it is completely white, effectively losing all lighting details in the process. As we directly write HDR values to an LDR output buffer it is as if we have no HDR enabled in the first place. What we need to do is transform all the floating point color values into the <code>0.0</code> - <code>1.0</code> range without losing any of its details. We need to apply a process called <def>tone mapping</def>.
    438 </p>
    439       
    440 <h2>Tone mapping</h2>
    441 <p>
    442   Tone mapping is the process of transforming floating point color values to the expected [<code>0.0</code>, <code>1.0</code>] range known as low dynamic range without losing too much detail, often accompanied with a specific stylistic color balance.
    443 </p>
    444       
    445 <p>
    446   One of the more simple tone mapping algorithms is <def>Reinhard tone mapping</def> that involves dividing the entire HDR color values to LDR color values. The Reinhard tone mapping algorithm evenly balances out all brightness values onto LDR. We include Reinhard tone mapping into the previous fragment shader and also add a <a href="https://learnopengl.com/Advanced-Lighting/Gamma-Correction" target="_blank">gamma correction</a> filter for good measure (including the use of sRGB textures): 
    447 </p>
    448       
    449 <pre><code>
    450 void main()
    451 {             
    452     const float gamma = 2.2;
    453     vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
    454   
    455     // reinhard tone mapping
    456     vec3 mapped = hdrColor / (hdrColor + vec3(1.0));
    457     // gamma correction 
    458     mapped = pow(mapped, vec3(1.0 / gamma));
    459   
    460     FragColor = vec4(mapped, 1.0);
    461 }    
    462 </code></pre>
    463       
    464 <p>
    465   With Reinhard tone mapping applied we no longer lose any detail at the bright areas of our scene. It does tend to slightly favor brighter areas, making darker regions seem less detailed and distinct: 
    466 </p>
    467       
    468       <img src="/img/advanced-lighting/hdr_reinhard.png" class="clean" alt="Reinhard tone mapping algorithm applied with HDR rendering in OpenGL"/>
    469         
    470 <p>
    471   Here you can again see details at the end of the tunnel as the wood texture pattern becomes visible again. With this relatively simple tone mapping algorithm we can properly see the entire range of HDR values stored in the floating point framebuffer, giving us precise control over the scene's lighting without losing details.
    472 </p>
    473         
    474 <note>
    475 	Note that we could also directly tone map at the end of our lighting shader, not needing any floating point framebuffer at all! However, as scenes get more complex you'll frequently find the need to store intermediate HDR results as floating point buffers so this is a good exercise.  
    476 </note>
    477         
    478 <p>
    479   Another interesting use of tone mapping is to allow the use of an exposure parameter. You probably remember from the introduction that HDR images contain a lot of details visible at different exposure levels. If we have a scene that features a day and night cycle it makes sense to use a lower exposure at daylight and a higher exposure at night time, similar to how the human eye adapts. With such an exposure parameter it allows us to configure lighting parameters that work both at day and night under different lighting conditions as we only have to change the exposure parameter.
    480 </p>
    481         
    482 <p>
    483   A relatively simple exposure tone mapping algorithm looks as follows:
    484 </p>
    485         
    486 <pre><code>
    487 uniform float exposure;
    488 
    489 void main()
    490 {             
    491     const float gamma = 2.2;
    492     vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb;
    493   
    494     // exposure tone mapping
    495     vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);
    496     // gamma correction 
    497     mapped = pow(mapped, vec3(1.0 / gamma));
    498   
    499     FragColor = vec4(mapped, 1.0);
    500 }  
    501 </code></pre>
    502         
    503 <p>
    504   Here we defined an <var>exposure</var> uniform that defaults at <code>1.0</code> and allows us to more precisely specify whether we'd like to focus more on dark or bright regions of the HDR color values. For instance, with high exposure values the darker areas of the tunnel show significantly more detail. In contrast, a low exposure largely removes the dark region details, but allows us to see more detail in the bright areas of a scene. Take a look at the image below to see the tunnel at multiple exposure levels:
    505 </p>
    506         
    507         <img src="/img/advanced-lighting/hdr_exposure.png" alt="Multiple exposure levels of HDR tone mapping in OpenGL"/>
    508           
    509 <p>
    510   This image clearly shows the benefit of high dynamic range rendering. By changing the exposure level we get to see a lot of details of our scene, that would've been otherwise lost with low dynamic range rendering. Take the end of the tunnel for example. With a normal exposure the wood structure is barely visible, but with a low exposure the detailed wooden patterns are clearly visible. The same holds for the wooden patterns close by that are more visible with a high exposure. 
    511 </p>
    512           
    513 <p>
    514   You can find the source code of the demo <a href="/code_viewer_gh.php?code=src/5.advanced_lighting/6.hdr/hdr.cpp" target="_blank">here</a>.
    515 </p>
    516           
    517 <h3>More HDR</h3>
    518 <p>
    519   The two tone mapping algorithms shown are only a few of a large collection of (more advanced) tone mapping algorithms of which each has their own strengths and weaknesses. Some tone mapping algorithms favor certain colors/intensities above others and some algorithms display both the low and high exposure colors at the same time to create more colorful and detailed images. There is also a collection of techniques known as <def>automatic exposure adjustment</def> or <def>eye adaptation</def> techniques that determine the brightness of the scene in the previous frame and (slowly) adapt the exposure parameter such that the scene gets brighter in dark areas or darker in bright areas mimicking the human eye.
    520 </p>
    521                     
    522 <p>
    523   The real benefit of HDR rendering really shows itself in large and complex scenes with heavy lighting algorithms. As it is difficult to create such a complex demo scene for teaching purposes while keeping it accessible, the chapter's demo scene is small and lacks detail. While relatively simple it does show some of the benefits of HDR rendering: no details are lost in high and dark regions as they can be restored with tone mapping, the addition of multiple lights doesn't cause clamped regions, and light values can be specified by real brightness values not being limited by LDR values. Furthermore, HDR rendering also makes several other interesting effects more feasible and realistic; one of these effects is <def>bloom</def> that we'll discuss in the next <a href="https://learnopengl.com/Advanced-Lighting/Bloom" target="_blank">next</a> chapter.
    524 </p>
    525           
    526 <h2>Additional resources</h2>
    527 <ul>
    528   <li><a href="http://gamedev.stackexchange.com/questions/62836/does-hdr-rendering-have-any-benefits-if-bloom-wont-be-applied" target="_blank">Does HDR rendering have any benefits if bloom won't be applied?</a>: a stackexchange question that features a great lengthy answer describing some of the benefits of HDR rendering.</li>
    529  <li><a href="http://photo.stackexchange.com/questions/7630/what-is-tone-mapping-how-does-it-relate-to-hdr" target="_blank">What is tone mapping? How does it relate to HDR?</a>: another interesting answer with great reference images to explain tone mapping.</li>
    530 </ul>       
    531 
    532     </div>
    533     
    534     <div id="hover">
    535         HI
    536     </div>
    537    <!-- 728x90/320x50 sticky footer -->
    538 <div id="waldo-tag-6196"></div>
    539 
    540    <div id="disqus_thread"></div>
    541 
    542     
    543 
    544 
    545 </div> <!-- container div -->
    546 
    547 
    548 </div> <!-- super container div -->
    549 </body>
    550 </html>
    551 	</main>
    552 </body>
    553 </html>