LearnOpenGL

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

Particles.html (24933B)


      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">Particles</h1>
    319 <h1 id="content-url" style='display:none;'>In-Practice/2D-Game/Particles</h1>
    320 <p>
    321   A <def>particle</def>, as seen from OpenGL's perspective, is a tiny 2D quad that is always facing the camera (billboarding) and (usually) contains a texture with large parts of the sprite being transparent. A particle by itself is effectively just a sprite as we've been using extensively so far. However, when you put together hundreds or even thousands of these particles together you can create amazing effects.
    322 </p>
    323 
    324 <p>
    325   When working with particles, there is usually an object called a <def>particle emitter</def> or <def>particle generator</def> that, from its location, continuously <def>spawns</def> new particles  that decay over time. If such a particle emitter would for example spawn tiny particles with a smoke-like texture, color them less bright the larger the distance from the emitter, and give them a glowy appearance, you'd get a fire-like effect:
    326 </p>
    327 
    328 <img src="/img/in-practice/breakout/particles_example.jpg" alt="Example of particles as a fire"/>
    329   
    330 <p>
    331   A single particle often has a life variable that slowly decays once it's spawned. Once its life is less than a certain threshold (usually <code>0</code>), we <def>kill</def> the particle so it can be replaced with a new particle when the next particle spawns. A particle emitter controls all its spawned particles and changes their behavior based on their attributes. A particle generally has the following attributes:
    332 </p>
    333   
    334 <pre><code>
    335 struct Particle {
    336     glm::vec2 Position, Velocity;
    337     glm::vec4 Color;
    338     float     Life;
    339   
    340     Particle() 
    341       : Position(0.0f), Velocity(0.0f), Color(1.0f), Life(0.0f) { }
    342 };    
    343 </code></pre>
    344   
    345 <p>
    346   Looking at the fire example, the particle emitter probably spawns each particle with a position close to the emitter and with an upwards velocity. It seems to have 3 different regions, so it probably gives some particles a higher velocity than others. We can also see that the higher the <code>y</code> position of the particle, the less <em>yellow</em> or <em>bright</em> its color becomes. After the particles have reached a certain height, their life is depleted and the particles are killed; never reaching the stars.
    347 </p>
    348   
    349 <p>
    350   You can imagine that with systems like these we can create interesting effects like fire, smoke, fog, magic effects, gunfire residue etc. In Breakout, we're going to add a simple particle generator that follows the ball to make it all look just a bit more interesting. It'll look something like this:
    351 </p>
    352   
    353 <div class="video paused" onclick="ClickVideo(this)">
    354   <video width="600" height="450" loop>
    355     <source src="/video/in-practice/breakout/particles.mp4" type="video/mp4" />
    356     <img src="/img/in-practice/breakout/particles.png" class="clean"/>
    357   </video>
    358 </div>
    359   
    360 <p>
    361   Here, the particle generator spawns each particle at the ball's position, gives it a velocity equal to a fraction of the ball's velocity, and changes the color of the particle based on how long it lived. 
    362 </p>
    363   
    364 <p>
    365   For rendering the particles we'll be using a different set of shaders:
    366 </p>
    367   
    368 <pre><code>
    369 #version 330 core
    370 layout (location = 0) in vec4 vertex; // &lt;vec2 position, vec2 texCoords&gt;
    371 
    372 out vec2 TexCoords;
    373 out vec4 ParticleColor;
    374 
    375 uniform mat4 projection;
    376 uniform vec2 offset;
    377 uniform vec4 color;
    378 
    379 void main()
    380 {
    381     float scale = 10.0f;
    382     TexCoords = vertex.zw;
    383     ParticleColor = color;
    384     gl_Position = projection * vec4((vertex.xy * scale) + offset, 0.0, 1.0);
    385 }
    386 </code></pre>
    387 
    388 <p>
    389   And the fragment shader:
    390 </p>
    391   
    392 <pre><code>
    393 #version 330 core
    394 in vec2 TexCoords;
    395 in vec4 ParticleColor;
    396 out vec4 color;
    397 
    398 uniform sampler2D sprite;
    399 
    400 void main()
    401 {
    402     color = (texture(sprite, TexCoords) * ParticleColor);
    403 }  
    404 </code></pre>
    405 
    406 <p>
    407   We take the standard position and texture attributes per particle and also accept an <var>offset</var> and a <var>color</var> uniform for changing the outcome per particle. Note that in the vertex shader we scale the particle quad by <code>10.0f</code>; you can also set the scale as a uniform and control this individually per particle.
    408 </p>
    409   
    410 <p>
    411   First, we need a list of particles that we instantiate with default <fun>Particle</fun> structs:
    412 </p>
    413   
    414 <pre><code>
    415 unsigned int nr_particles = 500;
    416 std::vector&lt;Particle&gt; particles;
    417   
    418 for (unsigned int i = 0; i &lt; nr_particles; ++i)
    419     particles.push_back(Particle());
    420 </code></pre>
    421   
    422 <p>
    423   Then in each frame, we spawn several new particles with starting values. For each particle that is (still) alive we also update their values:
    424 </p>
    425   
    426 <pre><code>
    427 unsigned int nr_new_particles = 2;
    428 // add new particles
    429 for (unsigned int i = 0; i &lt; nr_new_particles; ++i)
    430 {
    431     int unusedParticle = FirstUnusedParticle();
    432     RespawnParticle(particles[unusedParticle], object, offset);
    433 }
    434 // update all particles
    435 for (unsigned int i = 0; i &lt; nr_particles; ++i)
    436 {
    437     Particle &p = particles[i];
    438     p.Life -= dt; // reduce life
    439     if (p.Life &gt; 0.0f)
    440     {	// particle is alive, thus update
    441         p.Position -= p.Velocity * dt;
    442         p.Color.a -= dt * 2.5f;
    443     }
    444 }  
    445 </code></pre>
    446   
    447 <p>
    448   The first loop may look a little daunting. As particles die over time we want to spawn <var>nr_new_particles</var> particles each frame, but since we don't want to infinitely keep spawning new particles (we'll quickly run out of memory this way) we only spawn up to a max of <var>nr_particles</var>. If were to push all new particles to the end of the list we'll quickly get a list filled with thousands of particles. This isn't really efficient considering only a small portion of that list has particles that are alive.
    449 </p>
    450   
    451 <p>
    452   What we want is to find the first particle that is dead (life &lt; <code>0.0f</code>) and update  that particle as a new respawned particle.
    453 </p>
    454 
    455 <p>
    456   The function <fun>FirstUnusedParticle</fun> tries to find the first particle that is dead and returns its index to the caller.    
    457   </p>
    458 
    459 <pre><code>
    460 unsigned int lastUsedParticle = 0;
    461 unsigned int FirstUnusedParticle()
    462 {
    463     // search from last used particle, this will usually return almost instantly
    464     for (unsigned int i = lastUsedParticle; i &lt; nr_particles; ++i) {
    465         if (particles[i].Life &lt;= 0.0f){
    466             lastUsedParticle = i;
    467             return i;
    468         }
    469     }
    470     // otherwise, do a linear search
    471     for (unsigned int i = 0; i &lt; lastUsedParticle; ++i) {
    472         if (particles[i].Life &lt;= 0.0f){
    473             lastUsedParticle = i;
    474             return i;
    475         }
    476     }
    477     // override first particle if all others are alive
    478     lastUsedParticle = 0;
    479     return 0;
    480 }  
    481 </code></pre>
    482   
    483 <p>
    484   The function stores the index of the last dead particle it found. Since the next dead particle will most likely be right after the last particle index, we first search from this stored index. If we found no dead particles this way, we simply do a slower linear search. If no particles are dead, it will return index <code>0</code> which results in the first particle being overwritten. Note that if it reaches this last case, it means your particles are alive for too long; you'd need to spawn less particles per frame and/or reserve a larger number of particles.
    485 </p>
    486   
    487 <p>
    488   Then, once the first dead particle in the list is found, we update its values by calling <fun>RespawnParticle</fun> that takes the particle, a <fun>GameObject</fun>, and an offset vector:
    489 </p>
    490   
    491 <pre><code>
    492 void RespawnParticle(Particle &particle, GameObject &object, glm::vec2 offset)
    493 {
    494     float random = ((rand() % 100) - 50) / 10.0f;
    495     float rColor = 0.5f + ((rand() % 100) / 100.0f);
    496     particle.Position = object.Position + random + offset;
    497     particle.Color = glm::vec4(rColor, rColor, rColor, 1.0f);
    498     particle.Life = 1.0f;
    499     particle.Velocity = object.Velocity * 0.1f;
    500 }  
    501 </code></pre>
    502   
    503 <p>
    504   This function simply resets the particle's life to <code>1.0f</code>, randomly gives it a brightness (via the color vector) starting from <code>0.5</code>, and assigns a (slightly random) position and velocity based on the game object's data.
    505 </p>
    506   
    507 <p>
    508   The second particle loop within the update function loops over all particles and for each particle reduces their life by the delta time variable; this way, each particle's life corresponds to exactly the second(s) it's allowed to live multiplied by some scalar. Then we check if the particle is alive and if so, update its position and color attributes. We also slowly reduce the alpha component of each particle so it looks like they're slowly disappearing over time. 
    509 </p>
    510   
    511 <p>
    512   Then what's left to do is render the particles:
    513 </p>
    514   
    515 <pre><code>
    516 <function id='70'>glBlendFunc</function>(GL_SRC_ALPHA, GL_ONE);
    517 particleShader.Use();
    518 for (Particle particle : particles)
    519 {
    520     if (particle.Life &gt; 0.0f)
    521     {
    522         particleShader.SetVector2f("offset", particle.Position);
    523         particleShader.SetVector4f("color", particle.Color);
    524         particleTexture.Bind();
    525         <function id='27'>glBindVertexArray</function>(particleVAO);
    526         <function id='1'>glDrawArrays</function>(GL_TRIANGLES, 0, 6);
    527         <function id='27'>glBindVertexArray</function>(0);
    528     } 
    529 } 
    530 <function id='70'>glBlendFunc</function>(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    531 </code></pre>
    532   
    533 <p>
    534   Here, for each particle, we set their offset and color uniform values, bind the texture, and render the 2D quad. What's interesting to note here are the two calls to <fun><function id='70'>glBlendFunc</function></fun>. When rendering the particles, instead of the default destination blend mode of <code>GL_ONE_MINUS_SRC_ALPHA</code>, we use the <code>GL_ONE</code> (additive) blend mode that gives the particles a very neat <def>glow effect</def> when stacked onto each other. This is also likely the blend mode used when rendering the fire at the top of the chapter, since the fire is more 'glowy' at the center where most of the particles are. 
    535 </p>
    536   
    537 <p>
    538   Because we (like most other parts of the Breakout chapters) like to keep things organized, we create another class called <fun>ParticleGenerator</fun> that hosts all the functionality we just described. You can find the source code below:
    539 </p>
    540   
    541 <ul>
    542   <li><a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/particle_generator.h" target="_blank">header</a>, <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/particle_generator.cpp" target="_blank">code</a></li>
    543 </ul>
    544   
    545 <p>
    546   Within the game code, we create a particle generator and initialize it with <a href="/img/in-practice/breakout/textures/particle.png" target="_blank">this</a> texture.
    547 </p>
    548   
    549 <pre><code>
    550 ParticleGenerator   *Particles; 
    551 
    552 void Game::Init()
    553 {
    554     [...]
    555     ResourceManager::LoadShader("shaders/particle.vs", "shaders/particle.frag", nullptr, "particle");
    556     [...]
    557     ResourceManager::LoadTexture("textures/particle.png", true, "particle"); 
    558     [...]
    559     Particles = new ParticleGenerator(
    560         ResourceManager::GetShader("particle"), 
    561         ResourceManager::GetTexture("particle"), 
    562         500
    563     );
    564 }
    565 </code></pre>
    566   
    567 <p>
    568   Then we change the game class's <fun>Update</fun> function by adding an update statement for the particle generator:
    569 </p>
    570   
    571 <pre><code>
    572 void Game::Update(float dt)
    573 {
    574     [...]
    575     // update particles
    576     Particles-&gt;Update(dt, *Ball, 2, glm::vec2(Ball-&gt;Radius / 2.0f));
    577     [...]
    578 }
    579 </code></pre>
    580   
    581 <p>
    582   Each of the particles will use the game object properties from the ball object, spawn 2 particles each frame, and their positions will be offset towards the center of the ball. Last up is rendering the particles:
    583 </p>
    584   
    585 <pre><code>
    586 void Game::Render()
    587 {
    588     if (this-&gt;State == GAME_ACTIVE)
    589     {
    590         [...]
    591         // draw player
    592         Player-&gt;Draw(*Renderer);
    593         // draw particles	
    594         Particles-&gt;Draw();
    595         // draw ball
    596         Ball-&gt;Draw(*Renderer);
    597     }
    598 }  
    599 </code></pre>
    600   
    601 <p>
    602   Note that we render the particles before we render the ball. This way, the particles end up rendered in front of all other objects, but behind the ball. You can find the updated game class code <a href="/code_viewer_gh.php?code=src/7.in_practice/3.2d_game/0.full_source/progress/6.game.cpp" target="_blank">here</a>.
    603 </p>
    604     
    605 <p>
    606   If you'd now compile and run your application you should see a trail of particles following the ball, just like at the beginning of the chapter, giving the game a more modern look. The system can also easily be extended to host more advanced effects, so feel free to experiment with the particle generation and see if you can come up with your own creative effects.
    607 </p>       
    608 
    609     </div>
    610     
    611     <div id="hover">
    612         HI
    613     </div>
    614    <!-- 728x90/320x50 sticky footer -->
    615 <div id="waldo-tag-6196"></div>
    616 
    617    <div id="disqus_thread"></div>
    618 
    619     
    620 
    621 
    622 </div> <!-- container div -->
    623 
    624 
    625 </div> <!-- super container div -->
    626 </body>
    627 </html>
    628 	</main>
    629 </body>
    630 </html>