{"id":12434,"date":"2011-07-25T09:20:23","date_gmt":"2011-07-25T14:20:23","guid":{"rendered":"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=12434"},"modified":"2011-07-25T09:20:40","modified_gmt":"2011-07-25T14:20:40","slug":"project-frontier-18-particle-man","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=12434","title":{"rendered":"Project Frontier #18: Particle Man"},"content":{"rendered":"<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/frontier17_5.jpg' class='insetimage'   alt='frontier17_5.jpg' title='frontier17_5.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>I&#8217;m actually taking a break from the project this week to work on some other things, but there are a few completed features I want to cover.  Let&#8217;s start with the particle engine. <\/p>\n<p><!--more-->I wrote a particle engine about eight years ago, as part of my day job.  It was good for its time, but since then I&#8217;ve come up with a lot of ways that it could have been done better.  <\/p>\n<p>I&#8217;m using the term &#8220;particles&#8221; here very broadly to refer to any small objects that are created in groups and have no physical presence.  They don&#8217;t collide with stuff, they can&#8217;t be picked up or manipulated.  They are visual only.  Some examples of particle effects from other games include:  Fire, smoke, fireworks, billowing fog, puffs of dust when you take a step, splashes of water droplets, things blowing in the wind, rain, snow, blowing sand, muzzle-flashes, airborne blood spatters, magic missiles and other spell effects.   <\/p>\n<p>I don&#8217;t need all of those effects, but any system I build needs to be at least flexible enough to produce them.  <\/p>\n<p>Particles come from particle emitters, and particle emitters are created using a long list of settings.  The settings are things like:<\/p>\n<ul>\n<li><strong>Texture<\/strong> &#8211; What texture to apply to all of the particles that this emitter will create. If I need more than one texture (say, if I wanted to make a shower of gold coins and rubies) then I&#8217;ll need to use multiple emitters.  I could alter this so that an emitter could use multiple textures from a list, or maybe cut up and use selected sections of a texture.  But for now this is good enough.\n<\/li>\n<li><strong>Blending style<\/strong> &#8211; Note how fire or muzzle flashes seem to emit light of their own, while smoke and dirt to not.  This is controlled by how I set the blend properties at render time.  &#8220;Bright&#8221; particles (and other special effect) are usually created so that they lighten the pixels already on-screen, which is what makes them glow.\n<\/li>\n<li><strong>Emitter lifespan<\/strong> &#8211; How long should this emitter last?  A burst of fireworks releases all of its particles at once, after which the emitter is useless and can be discarded, while a plume of smoke is expected to keep churning out smoke as long as it&#8217;s in the scene.\n<\/li>\n<li><strong>Emission count &#038; emission interval<\/strong>  &#8211; How often should particles be released, and how many should appear when they do?  Sparks from a loose wire might release a bunch of particles at once, but wait for several seconds between busts.  A fire creates flames at a steady rate, and creates them one at a time.\n<\/li>\n<li><strong>Fade in &#038; out<\/strong> &#8211; We need a way to control how long it takes for particles to appear and vanish.  Fog and smoke should fade in and out very slowly.  A burst of fireworks appears instantly, but fades out slowly. The aura of a blinking light should come and go instantly.\n<\/li>\n<li><strong>Rotation<\/strong> &#8211; Something blowing in the wind should tumble through the air, while raindrops should remain pointed the same direction.\n<\/li>\n<li><strong>Size<\/strong> &#8211; Some particles effects will be larger than others.\n<\/li>\n<li><strong>Cubic volume<\/strong> &#8211; The volume of the emitter is a cubic area.  New particles will appear at a random point inside of the volume.  If you want all of the particles to come from a single point, you make this volume zero size.  If you want to make the churning spray at the base of a waterfall, you&#8217;d make the volume roughly the size of the area where the falling water is striking the still water.\n<\/li>\n<li><strong>Color<\/strong> &#8211; What color to tint the particles.  I make all of the particle textures white and use this property to color them as needed.  With any luck, I&#8217;ll be able to re-use textures and effects.\n<\/li>\n<li><em>Other<\/em> &#8211; I&#8217;ve got a few other properties for special cases: Should particles be pulled down by gravity?  Should they be affected by wind? Should they leave an imprint of the z buffer?\n<\/li>\n<\/ul>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/frontier18_2.jpg' class='insetimage'   alt='First steps:  Here I&#8217;ve got an emitter (the blue wireframe box) creating particles. (The blue rectangles.) These particles appear, persist for a second, then vanish.' title='First steps:  Here I&#8217;ve got an emitter (the blue wireframe box) creating particles. (The blue rectangles.) These particles appear, persist for a second, then vanish.'\/><\/td><\/tr><tr><td class='insetcaption'>First steps:  Here I&#8217;ve got an emitter (the blue wireframe box) creating particles. (The blue rectangles.) These particles appear, persist for a second, then vanish.<\/td><\/tr><\/table><\/p>\n<p>The upshot is that one set of properties will create one kind of particle effect, but a different set of numbers will yield an entirely different effect. Rather than have them hard-coded, I stick these settings into text files where I can edit them while the program is running.  Here is an example, the effect I use for flower petals blowing in the wind:<\/p>\n<pre lang=\"xml\">\r\n<cvars>\r\n    <particle_texture>  particle_flower.png    <\/particle_texture>\r\n    <particle_acceleration>  [ 0,  0,  0.0 ]    <\/particle_acceleration>\r\n    <particle_blend>  0 <\/particle_blend>\r\n    <particle_emitter_lifespan>  0   <\/particle_emitter_lifespan>\r\n    <particle_emit_count>  1    <\/particle_emit_count>\r\n    <particle_emit_interval>  400    <\/particle_emit_interval>\r\n    <particle_fade_in>  5    <\/particle_fade_in>\r\n    <particle_fade_out>  500    <\/particle_fade_out>\r\n    <particle_interpolate>  0    <\/particle_interpolate>\r\n    <particle_lifespan>  3000    <\/particle_lifespan>\r\n    <particle_origin>  [ 0,  0,  -0.25 ]    <\/particle_origin>\r\n    <particle_panel_type>  3    <\/particle_panel_type>\r\n    <particle_rotation>  [ 0,  0,  0 ]    <\/particle_rotation>\r\n    <particle_size_min>  [ 0.07,  0.07, 0.07 ]    <\/particle_size_min>\r\n    <particle_size_max>  [ 0.17,  0.17, 0.17 ]    <\/particle_size_max>\r\n    <particle_speed_min>  [ 2,  -1,  0.05 ]    <\/particle_speed_min>\r\n    <particle_speed_max>  [ 3,   1,  0.25 ]    <\/particle_speed_max>\r\n    <particle_spin>  [ 20,  40,  0 ]    <\/particle_spin>\r\n    <particle_volume_min>  [ -2,  -2,  1.0 ]    <\/particle_volume_min>\r\n    <particle_volume_max>  [  2,   2,  1.1 ]    <\/particle_volume_max>\r\n    <particle_wind>  0    <\/particle_wind>\r\n    <particle_gravity>  0    \r\n    <particle_z_buffer>  0    <\/particle_z_buffer>\r\n<\/particle_gravity><\/cvars>\r\n<\/pre>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/frontier18_3.jpg' class='insetimage'   alt='Now I can feed an emitter a list of colors.  When it creates a particle, it selects randomly from the available colors.  It&#8217;s now using a texture map (of a circle) and making them slowly spin through the air.' title='Now I can feed an emitter a list of colors.  When it creates a particle, it selects randomly from the available colors.  It&#8217;s now using a texture map (of a circle) and making them slowly spin through the air.'\/><\/td><\/tr><tr><td class='insetcaption'>Now I can feed an emitter a list of colors.  When it creates a particle, it selects randomly from the available colors.  It&#8217;s now using a texture map (of a circle) and making them slowly spin through the air.<\/td><\/tr><\/table><\/p>\n<p>Thanks again to <a href=\"?p=12304\">glConsole<\/a>, which is the gift that keeps on giving. I was able to use its environment variable system to load these particle properties, basically for free.  <\/p>\n<p>The next step is to populate the world with emitters.  I make a system to examine the local climate and time of day and pick an appropriate emitter.  Swamp?  Swirling ground fog.  Desert?  Blowing sand.  Field of flowers?  Blowing flower petals.  Evening in an open area? Fireflies.  <\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/frontier18_4.jpg' class='insetimage'   alt='I set the particles to all move and spin at the same speed, which produces this ever-spooling ribbon effect. Cute.' title='I set the particles to all move and spin at the same speed, which produces this ever-spooling ribbon effect. Cute.'\/><\/td><\/tr><tr><td class='insetcaption'>I set the particles to all move and spin at the same speed, which produces this ever-spooling ribbon effect. Cute.<\/td><\/tr><\/table> <\/p>\n<p>Other parts of the program can initiate one-off effects.  When the avatar takes a step, it looks at the color of the terrain under its foot and creates a puff of particles.  This looks great on sand or dirt, but kind of lame on grass.  But you get the idea.  It&#8217;s just one more thing making the world seem more like a living thing and less like a static scene.  <\/p>\n<p>Next time I&#8217;ll talk about those clouds you&#8217;re seeing in the screenshots.<\/p>\n<p><table class='nomargin' cellspacing='0' width='100%' cellpadding='0' align='center' border='0'><tr><td><iframe loading=\"lazy\" width=\"1024\" height=\"576\" src=\"https:\/\/www.youtube.com\/embed\/kHgziac87-Y\" frameborder=\"0\" allowfullscreen class=\"embed\"><\/iframe><br\/><small><a href='http:\/\/www.youtube.com\/watch?v=kHgziac87-Y'>Link (YouTube)<\/a><\/small><\/td><\/tr><\/table><\/p>\n<p>Because.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m actually taking a break from the project this week to work on some other things, but there are a few completed features I want to cover. Let&#8217;s start with the particle engine.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[],"class_list":["post-12434","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/12434","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=12434"}],"version-history":[{"count":0,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/12434\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=12434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=12434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=12434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}