{"id":15843,"date":"2012-05-09T04:16:42","date_gmt":"2012-05-09T09:16:42","guid":{"rendered":"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=15843"},"modified":"2012-05-09T05:40:37","modified_gmt":"2012-05-09T10:40:37","slug":"project-octant-part-5the-rainbow-collection","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=15843","title":{"rendered":"Project Octant Part 5:The Rainbow Collection"},"content":{"rendered":"<p>Today we&#8217;re finally going to start adding some features to make this thing look a bit more&#8230; What? You say you want another digression on noise filtering and interpolation techniques? You sure? Okay then! <\/p>\n<p>(Nerd!)<\/p>\n<p>If you remember from last time, we&#8217;re taking tables of random white noise and expanding them to create &#8220;interesting&#8221; patterns.  Stuff like this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_1.png' class='insetimage'   alt='octant5_1.png' title='octant5_1.png'\/><\/td><\/tr><\/table><\/p>\n<p>Now, I really don&#8217;t want to have the next bunch of images be black &#038; white scramble squares.  That&#8217;s boring and it&#8217;s actually hard to see the effect I&#8217;m talking about.  So I&#8217;ve altered my program to output example images that will use color-blending to make the gradients more clear.  So the above image now looks like this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_2.png' class='insetimage'   alt='octant5_2.png' title='octant5_2.png'\/><\/td><\/tr><\/table><\/p>\n<p>Just remember we&#8217;re not <em>really<\/em> dealing with color data right now.  We&#8217;re actually just generating heaps of numbers between zero (dark blue) and one (red) and this color-fade makes it easier to see what we&#8217;re doing. Okay? Great. <\/p>\n<p><!--more-->In the image above we&#8217;re looking at around 16&#215;16 pixels, give or take the partials on the edges.  We need to be able to expand this data and come up with values between these points. <\/p>\n<p>In the <a href=\"?p=15777\">previous entry<\/a>, I put in a system based on cutting a quad (rectangle) into a pair of triangles and blending across it. Doing so yields this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_3.png' class='insetimage'   alt='octant5_3.png' title='octant5_3.png'\/><\/td><\/tr><\/table><\/p>\n<p>(Am I the only one who thinks that circle with a tail in the middle of the image looks kind of like the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Mandelbrot_set\">Mandelbrot set<\/a>?)<\/p>\n<p>I&#8217;ve been using this snippet of code for years. It wasn&#8217;t until I posted the last entry that I even questioned it. Someone asked why I wasn&#8217;t using <a href=\"http:\/\/en.wikipedia.org\/wiki\/Bilinear_filtering\">bilinear filtering<\/a> and I realized I didn&#8217;t have a good reason. There might <em>be<\/em> a good reason, but I hadn&#8217;t even considered the question.  I&#8217;ve been using the quad-fade code for so long I just sort of take it for granted. <\/p>\n<p>See, the quad code has two important features:<\/p>\n<ol>\n<li>It is fast. This is probably the fastest possible method that won&#8217;t create nasty seams.\n<\/li>\n<li>It breaks things into triangles.<\/li>\n<\/ol>\n<p>The triangles thing is important in certain cases. Like, in collision detection.  It&#8217;s handy if the player is standing on a square of terrain and I want to see if they&#8217;re ankle-deep, or floating above it, so that I can nudge them up or drop them down according to the long-understood rules of gravity and&#8230; walking up hills.   If they&#8217;re walking on a triangle (and you are always walking on triangles in a 3D game) then I don&#8217;t want to treat the surface like it&#8217;s rounded.  That will not look right. <\/p>\n<p>So I used this code out of habit. I saw a blend-four-values problem and pulled out the hammer I always use on four-value problems. But is that the right choice to make here?<\/p>\n<p>The quad blending begins with four values. Say you&#8217;ve got four pixels you want to blend together:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_6.png' class='insetimage'   alt='octant5_6.png' title='octant5_6.png'\/><\/td><\/tr><\/table><\/p>\n<p>We take this square and divide it into a pair of triangles. We can do this by cutting from upper-right to lower-left, or from upper-left to lower-right. Whatever. It&#8217;s best to alternate your cuts in a checkerboard pattern to avoid ugly artifacts. (Alternating our cuts will lead to the &#8220;diamond&#8221; pattern you see in the earlier image.)<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_7.png' class='insetimage'   alt='octant5_7.png' title='octant5_7.png'\/><\/td><\/tr><\/table><\/p>\n<p>If the point we&#8217;re trying to generate falls in the lower triangle, then we blend between those three points.  If it falls in the upper triangle, we use the corners of the other triangle. If I&#8217;m generating point X on the image above, then I create a value that is 1\/4 cyan (upper left) and 3\/4 orange (lower left) because we&#8217;re about 3\/4 of the way down the image.  Then I take that blended value and mix it half and half with dark blue (lower right) because we&#8217;re halfway across the image. It might sound confusing, but the code to accomplish this is actually a good bit smaller than this paragraph and only slightly less readable.<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_8.png' class='insetimage'   alt='octant5_8.png' title='octant5_8.png'\/><\/td><\/tr><\/table><\/p>\n<p>The downside of this is that the points aren&#8217;t given equal weight. The two points that form the right angles can&#8217;t effect the middle. The exact center is a blend of the two blues, without any weighting from the orange or green.  (Please don&#8217;t correct me and explain that these are peach and avocado or whatever artists call these colors. I&#8217;m making polygons, not a salad. I&#8217;m an engineer, and the only color names I know are the ones from the Crayola 8-box. <a href=\"http:\/\/thedoghousediaries.com\/1406\">Doghouse Diaries<\/a> and <a href=\"http:\/\/blog.xkcd.com\/2010\/05\/03\/color-survey-results\/\">XKCD<\/a> have already slain this horse and gave it a good pummeling afterward. (Insert &#8220;pummel horse&#8221; joke here.) Let&#8217;s move on.)<\/p>\n<p>Instead, let&#8217;s try bilinear filetering. (&#8220;bi&#8221; meaning two-way. Yes, just like the sex thing, you <em>complete<\/em> juvenile. &#8220;linear&#8221; meaning in a straight line. So, a couple of lines? Let&#8217;s try it.)<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_10.png' class='insetimage'   alt='octant5_10.png' title='octant5_10.png'\/><\/td><\/tr><\/table><\/p>\n<p>Bilinear filtering gives the values a more equitable distribution. To solve for the same x as before, we would blend halfway between the top two pixels for point A. Then we blend halfway between the bottom two for point B.  Then we blend 75% of the way from A to B for x. Clear? I hope so, because I want to move on.<\/p>\n<p>Oh, the same square with biliner filering looks like this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_9.png' class='insetimage'   alt='octant5_9.png' title='octant5_9.png'\/><\/td><\/tr><\/table><\/p>\n<p>Note that we needed to do three blending operations to get this value, as opposed to two blends for the cheapo blend I&#8217;ve been using.  Now, a single blend is nothing. A few math operations.  But remember what we&#8217;re doing with this data. We need to do three blends per pixel.  But we&#8217;re doing this in three dimensions, so we need to generate <em>two<\/em> pixels and blend <em>those<\/em> together for a single octave of noise. And we generally want to combine about 8 octaves to make our noise interesting. So&#8230; <\/p>\n<p><center><code>(3 blends * 2 pixels + 1 blend) * 8 octaves = 56 blend operations<\/code><\/center><\/p>\n<p>That&#8217;s per cube. Oh, and most cubes need 2 bits of noise. (One to shape hills and one to dig caves, for example.)  And a single 16-meter block of the world needs 4,096 cubes. And in a scene, even at the <strong>lowest possible<\/strong> visibility settings you&#8217;ve probably got around 400 such blocks rolling around in memory.   (I think Notch calls them chunks. I&#8217;ve taken to calling them nodes.) <\/p>\n<p>So even a crappy low-visibility scene needs to perform 183,500,800 blend operations. Also keep in mind that a single blend operation is&#8230;<\/p>\n<pre lang=\"c\">\r\ninline float Lerp (float n1, float n2, float delta)\r\n{\r\n  return n1 * (1.0f - delta) + n2 * delta;\r\n}\r\n<\/pre>\n<p>Looks like a subtract, a couple of multiply operations, and an add. We need to do that, one hundred and eighty-three million times. That will wipe the smug off the face of your quad-core 4Ghz processor in a hurry. Your machine is going to <em>work<\/em> for this scenery, kiddo. So no, increasing the number of blends we need to do by 50% is not something to be done lightly. We need a really good reason before we start dumping more CPU juice on the problem. We need something important, like marginally better graphics or something.<\/p>\n<p>Anyway. So this is what we have now:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_3.png' class='insetimage'   alt='octant5_3.png' title='octant5_3.png'\/><\/td><\/tr><\/table><\/p>\n<p>And here is the same thing generated with bilinear filtering:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_4.png' class='insetimage'   alt='octant5_4.png' title='octant5_4.png'\/><\/td><\/tr><\/table><\/p>\n<p>So&#8230; is it worth it? It&#8217;s hard to tell.  Obviously it looks better in RAINBOW VIEW, but that&#8217;s not what the data is used for.  In our program, the data is used to make caves.  Does it make better caves? <\/p>\n<p>True story bro: As of writing this paragraph, I have yet to try it.  I honestly don&#8217;t know, 1,200 words into this post, if this is a complete waste of time or not.  Let&#8217;s find out.<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant_brb.jpg' class='insetimage'   alt='octant_brb.jpg' title='octant_brb.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>That didn&#8217;t take long. Okay, so I made a huge volume of noise caves with the threshold set at 0.5. (In English, it should be a roughly even 50-50 mix of air and solid&#8230; block stuff.) First, I take a screenshot of a nice bit of cave using the discount triangle-interpolation blending:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_old_busted.jpg' class='insetimage'   alt='octant5_old_busted.jpg' title='octant5_old_busted.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>And now the exact same location, but generated with bilinear whatsits:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_new_hotness.jpg' class='insetimage'   alt='octant5_new_hotness.jpg' title='octant5_new_hotness.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>Is one of these really better than the other? It&#8217;s hard to say. What&#8217;s &#8220;better&#8221;? More visually interesting? More fun to explore? More realistic? Is the slow one really 50% slower? <\/p>\n<p>This sounds like a decision to make later, when one of these variables matters. I&#8217;ve got both systems sitting side-by-side and can flip between them as I need. I guess for testing it makes sense to stick with the faster system anyway. If I stick with this project then eventually I&#8217;ll have to add a bunch of timers to keep track of where all the CPU is going, and that would be a good time to come back to this.<\/p>\n<p>Also, in the process of writing the new filter, I managed to mess up and make this:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/octant5_5.png' class='insetimage'   alt='octant5_5.png' title='octant5_5.png'\/><\/td><\/tr><\/table><\/p>\n<p>(I was blending between the wrong corners.) It&#8217;s useless, but kind of pretty in a strange way.  I like it because it looks like one of those shuffle puzzles. I suppose it would be considered evil to present this as a shuffle puzzle and let someone drive themselves insane trying to get things to match up?<\/p>\n<p>So that&#8217;s what we accomplished today&#8230; nothing! This riveting series will continue in the next entry unless there isn&#8217;t one.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we&#8217;re finally going to start adding some features to make this thing look a bit more&#8230; What? You say you want another digression on noise filtering and interpolation techniques? You sure? Okay then! (Nerd!) If you remember from last time, we&#8217;re taking tables of random white noise and expanding them to create &#8220;interesting&#8221; patterns. [&hellip;]<\/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":[233],"class_list":["post-15843","post","type-post","status-publish","format-standard","hentry","category-programming","tag-octant"],"_links":{"self":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/15843","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=15843"}],"version-history":[{"count":0,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/15843\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=15843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=15843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=15843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}