LearnOpenGL

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

Postprocessing.html (23313B)


      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">Postprocessing</h1>
    319 <h1 id="content-url" style='display:none;'>In-Practice/2D-Game/Postprocessing</h1>
    320 <p>
    321   Wouldn't it be fun if we could completely spice up the visuals of the Breakout game with just a few postprocessing effects? We could create a blurry shake effect, inverse all the colors of the scene, do crazy vertex movement, and/or make use of other interesting effects with relative ease thanks to OpenGL's framebuffers.
    322 </p>
    323 
    324 <note>
    325   This chapters makes extensive use of concepts from the <a href="https://learnopengl.com/Advanced-OpenGL/Framebuffers" target="_blank">framebuffers</a> and <a href="https://learnopengl.com!Advanced-OpenGL/Anti-Aliasing" target="_blank">anti-aliasing</a> chapters. 
    326 </note>
    327 
    328 <p>
    329   In the framebuffers chapter we demonstrated how we could use postprocessing to achieve interesting effects using just a single texture. In Breakout we're going to do something similar: we're going to create a framebuffer object with a multisampled renderbuffer object attached as its color attachment. All the game's render code should render to this multisampled framebuffer that then blits its content to a different framebuffer with a texture attachment as its color buffer. This texture contains the rendered anti-aliased image of the game that we'll render to a full-screen 2D quad with zero or more postprocessing effects applied. 
    330 </p>
    331 
    332 <p>
    333   So to summarize, the rendering steps are:
    334 </p>
    335 
    336 <ol>
    337   <li>Bind to multisampled framebuffer.</li>
    338   <li>Render game as normal.</li>
    339   <li>Blit multisampled framebuffer to normal framebuffer with texture attachment.</li>
    340   <li>Unbind framebuffer (use default framebuffer).</li>
    341   <li>Use color buffer texture from normal framebuffer in postprocessing shader.</li>
    342   <li>Render quad of screen-size as output of postprocessing shader.</li>  
    343 </ol>
    344 
    345 <p>
    346   The postprocessing shader allows for three type of effects: shake, confuse, and chaos.
    347 </p>
    348 
    349 <ul>
    350   <li><strong>shake</strong>: slightly shakes the scene with a small blur.</li>
    351   <li><strong>confuse</strong>: inverses the colors of the scene, but also the <code>x</code> and <code>y</code> axis.</li>
    352   <li><strong>chaos</strong>: makes use of an edge detection kernel to create interesting visuals and also moves the textured image in a circular fashion for an interesting <em>chaotic</em> effect.</li>
    353 </ul>
    354 
    355 
    356 <p>
    357   Below is a glimpse of what these effects are going to look like:
    358 </p>
    359 
    360 <img src="/img/in-practice/breakout/postprocessing_effects.png" alt="Postprocessing effects in OpenGL Breakout game"/>
    361 
    362 <p>
    363   Operating on a 2D quad, the vertex shader looks as follows:
    364 </p>
    365 
    366 <pre><code>
    367 #version 330 core
    368 layout (location = 0) in vec4 vertex; // &lt;vec2 position, vec2 texCoords&gt;
    369 
    370 out vec2 TexCoords;
    371 
    372 uniform bool  chaos;
    373 uniform bool  confuse;
    374 uniform bool  shake;
    375 uniform float time;
    376 
    377 void main()
    378 {
    379     gl_Position = vec4(vertex.xy, 0.0f, 1.0f); 
    380     vec2 texture = vertex.zw;
    381     if (chaos)
    382     {
    383         float strength = 0.3;
    384         vec2 pos = vec2(texture.x + sin(time) * strength, texture.y + cos(time) * strength);        
    385         TexCoords = pos;
    386     }
    387     else if (confuse)
    388     {
    389         TexCoords = vec2(1.0 - texture.x, 1.0 - texture.y);
    390     }
    391     else
    392     {
    393         TexCoords = texture;
    394     }
    395     if (shake)
    396     {
    397         float strength = 0.01;
    398         gl_Position.x += cos(time * 10) * strength;        
    399         gl_Position.y += cos(time * 15) * strength;        
    400     }
    401 }  
    402 </code></pre>
    403   
    404 <p>
    405   Based on whatever uniform is set to <code>true</code>, the vertex shader takes different paths. If either <var>chaos</var> or <var>confuse</var> is set to <code>true</code>, the vertex shader will manipulate the texture coordinates to move the scene around (either translate texture coordinates in a circle-like fashion, or inverse them). Because we set the texture wrapping methods to <code>GL_REPEAT</code>, the chaos effect will cause the scene to repeat itself at various parts of the quad. Additionally if <var>shake</var> is set to <code>true</code>, it will move the vertex positions around by a small amount, as if the screen shakes. Note that <var>chaos</var> and <var>confuse</var> shouldn't be <code>true</code> at the same time while <var>shake</var> is able to work with any of the other effects on.
    406 </p>
    407 
    408 <p>
    409   In addition to offsetting the vertex positions or texture coordinates, we'd also like to create some visual change as soon as any of the effects are active. We can accomplish this within the fragment shader:
    410 </p>
    411 
    412 <pre><code>
    413 #version 330 core
    414 in  vec2  TexCoords;
    415 out vec4  color;
    416   
    417 uniform sampler2D scene;
    418 uniform vec2      offsets[9];
    419 uniform int       edge_kernel[9];
    420 uniform float     blur_kernel[9];
    421 
    422 uniform bool chaos;
    423 uniform bool confuse;
    424 uniform bool shake;
    425 
    426 void main()
    427 {
    428     color = vec4(0.0f);
    429     vec3 sample[9];
    430     // sample from texture offsets if using convolution matrix
    431     if(chaos || shake)
    432         for(int i = 0; i &lt; 9; i++)
    433             sample[i] = vec3(texture(scene, TexCoords.st + offsets[i]));
    434 
    435     // process effects
    436     if (chaos)
    437     {           
    438         for(int i = 0; i &lt; 9; i++)
    439             color += vec4(sample[i] * edge_kernel[i], 0.0f);
    440         color.a = 1.0f;
    441     }
    442     else if (confuse)
    443     {
    444         color = vec4(1.0 - texture(scene, TexCoords).rgb, 1.0);
    445     }
    446     else if (shake)
    447     {
    448         for(int i = 0; i &lt; 9; i++)
    449             color += vec4(sample[i] * blur_kernel[i], 0.0f);
    450         color.a = 1.0f;
    451     }
    452     else
    453     {
    454         color =  texture(scene, TexCoords);
    455     }
    456 }
    457 
    458 </code></pre>
    459 
    460 <p>
    461   This long shader almost directly builds upon the fragment shader from the framebuffers chapter and processes several postprocessing effects based on the effect type activated. This time though, the offset matrix and convolution kernels are defined as a uniform that we set from the OpenGL code. The advantage is that we only have to set this once, instead of recalculating these matrices each fragment shader run. For example, the <var>offsets</var> matrix is configured as follows:
    462 </p>
    463   
    464 <pre><code>
    465 float offset = 1.0f / 300.0f;
    466 float offsets[9][2] = {
    467     { -offset,  offset  },  // top-left
    468     {  0.0f,    offset  },  // top-center
    469     {  offset,  offset  },  // top-right
    470     { -offset,  0.0f    },  // center-left
    471     {  0.0f,    0.0f    },  // center-center
    472     {  offset,  0.0f    },  // center - right
    473     { -offset, -offset  },  // bottom-left
    474     {  0.0f,   -offset  },  // bottom-center
    475     {  offset, -offset  }   // bottom-right    
    476 };
    477 <function id='44'>glUniform</function>2fv(<function id='45'>glGetUniformLocation</function>(shader.ID, "offsets"), 9, (float*)offsets);  
    478 </code></pre>
    479 
    480 <p>
    481   Since all of the concepts of managing (multisampled) framebuffers were already extensively discussed in earlier chapters, I won't delve into the details this time. Below you'll find the code of a <fun>PostProcessor</fun> class that manages initialization, writing/reading the framebuffers, and rendering a screen quad. You should be able to understand the code if you understood the framebuffers and anti-aliasing chapter:
    482 </p>
    483 
    484 <ul>
    485   <li><strong>PostProcessor</strong>: <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/post_processor.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/post_processor.cpp" target="_blank">code</a>.</li>
    486 </ul>
    487 
    488 <p>
    489   What is interesting to note here are the <fun>BeginRender</fun> and <fun>EndRender</fun> functions. Since we have to render the entire game scene into the framebuffer we can conventiently call <fun>BeginRender()</fun> and <fun>EndRender()</fun> before and after the scene's rendering code respectively. The class will then handle the behind-the-scenes framebuffer operations. For example, using the <fun>PostProcessor</fun> class will look like this within the game's <fun>Render</fun> function:
    490 </p>
    491 
    492 <pre><code>
    493 PostProcessor   *Effects;
    494   
    495 void Game::Render()
    496 {
    497     if (this-&gt;State == GAME_ACTIVE)
    498     {
    499         Effects-&gt;BeginRender();
    500             // draw background
    501             // draw level
    502             // draw player
    503             // draw particles	
    504             // draw ball
    505         Effects-&gt;EndRender();
    506         Effects-&gt;Render(<function id='47'>glfwGetTime</function>());
    507     }
    508 }
    509 </code></pre>
    510 
    511 <p>
    512   Wherever we want, we can now conveniently set the required effect property of the postprocessing class to <code>true</code> and its effect will be immediately active.
    513 </p>
    514 
    515 <h3>Shake it</h3>
    516 <p>
    517   As a (practical) demonstration of these effects we'll emulate the visual impact of the ball when it hits a solid concrete block. By enabling the shake effect for a short period of time wherever a solid collision occurs, it'll look like the collision had a stronger impact.
    518 </p>
    519   
    520 <p>
    521    We want to enable the screen shake effect only over a small period of time. We can get this to work by creating a variable called <var>ShakeTime</var> that manages the duration the shake effect is supposed to be active. Wherever a solid collision occurs, we reset this variable to a specific duration:
    522 </p>
    523   
    524 <pre><code>
    525 float ShakeTime = 0.0f;  
    526 
    527 void Game::DoCollisions()
    528 {
    529     for (GameObject &box : this-&gt;Levels[this-&gt;Level].Bricks)
    530     {
    531         if (!box.Destroyed)
    532         {
    533             Collision collision = CheckCollision(*Ball, box);
    534             if (std::get&lt;0&gt;(collision)) // if collision is true
    535             {
    536                 // destroy block if not solid
    537                 if (!box.IsSolid)
    538                     box.Destroyed = true;
    539                 else
    540                 {   // if block is solid, enable shake effect
    541                     ShakeTime = 0.05f;
    542                     Effects-&gt;Shake = true;
    543                 }
    544                 [...]
    545             }
    546         }    
    547     }
    548     [...]
    549 }  
    550 </code></pre>
    551   
    552 <p>
    553   Then within the game's <fun>Update</fun> function, we decrease the <var>ShakeTime</var> variable until it's <code>0.0</code> after which we disable the shake effect:
    554 </p>
    555   
    556 <pre><code>
    557 void Game::Update(float dt)
    558 {
    559     [...]
    560     if (ShakeTime &gt; 0.0f)
    561     {
    562         ShakeTime -= dt;
    563         if (ShakeTime &lt;= 0.0f)
    564             Effects-&gt;Shake = false;
    565     }
    566 }  
    567 </code></pre>
    568   
    569 <p>
    570   Then each time we hit a solid block, the screen briefly starts to shake and blur, giving the player some visual feedback the ball collided with a solid object. 
    571 </p>
    572   
    573 <div class="video paused" onclick="ClickVideo(this)">
    574   <video width="600" height="450" loop>
    575     <source src="/video/in-practice/breakout/postprocessing_shake.mp4" type="video/mp4" />
    576     <img src="/img/in-practice/breakout/postprocessing_shake.png" class="clean"/>
    577   </video>
    578 </div>
    579   
    580 <p>
    581   You can find the updated source code of the game class <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/7.game.cpp" target="_blank">here</a>.
    582 </p>
    583   
    584 <p>
    585   In the <a href="https://learnopengl.com/In-Practice/2D-Game/Powerups" target="_blank">next</a> chapter about powerups we'll bring the other two postprocessing effects to good use.
    586 </p>       
    587 
    588     </div>
    589     
    590     <div id="hover">
    591         HI
    592     </div>
    593    <!-- 728x90/320x50 sticky footer -->
    594 <div id="waldo-tag-6196"></div>
    595 
    596    <div id="disqus_thread"></div>
    597 
    598     
    599 
    600 
    601 </div> <!-- container div -->
    602 
    603 
    604 </div> <!-- super container div -->
    605 </body>
    606 </html>
    607 	</main>
    608 </body>
    609 </html>