{"id":23547,"date":"2014-07-07T12:39:03","date_gmt":"2014-07-07T17:39:03","guid":{"rendered":"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=23547"},"modified":"2014-07-07T15:06:30","modified_gmt":"2014-07-07T20:06:30","slug":"project-unearth-part-3-enclosed-solids","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=23547","title":{"rendered":"Project Unearth Part 4: Enclosed Solids"},"content":{"rendered":"<p>Last time I promised we&#8217;d be dealing with rendering performance problems. Lies. We&#8217;re going to backtrack instead. I skimmed a lot of concepts <a href=\"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=23460\" title=\"Project Unearth Part 2: Skimming Hazzard\">back in part 2<\/a>, and I think we need to talk about stencil shadows in more detail before we can proceed. <\/p>\n<p>I&#8217;ve gone over this before, but polygons have front and back faces. Typically, the back face isn&#8217;t drawn. If I&#8217;m staring at a wall in (say) Doom 3:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_backface1.jpg' class='insetimage'   alt='unearth_backface1.jpg' title='unearth_backface1.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>In the real world, if I pass through the wall<span class='snote' title='1'>How?<\/span> and turn around, I&#8217;d find myself looking at the back side of this blue wall. But in a videogame&#8230;<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_backface2.jpg' class='insetimage'   alt='unearth_backface2.jpg' title='unearth_backface2.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>&#8230;I just look back into the level. The back side of the blue wall (and indeed, of all the walls) isn&#8217;t drawn. It would be a waste to do so, since you&#8217;d never see it during the normal course of play. Similarly, if you stuck your head inside a Minecraft cube, you wouldn&#8217;t find your head in a box. Instead, you would find yourself outside the world looking in, as with the Doom image above.<\/p>\n<p>Let&#8217;s go back to the horrible MS Paint diagram I was using before:<\/p>\n<p><!--more--><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_volume13.jpg' class='insetimage'   alt='unearth_volume13.jpg' title='unearth_volume13.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>As I said <a href=\"http:\/\/www.shamusyoung.com\/twentysidedtale\/?p=23460\" title=\"Project Unearth Part 2: Skimming Hazzard\">before<\/a>, we take the thing that should cast a shadow (the green cube) and extrude it away from the light. Everywhere this new object pierces the existing scenery is a place where the light can&#8217;t reach. What I neglected to mention is that for this to work we also have to draw the back faces and not the front ones. So, the object is effectively inside-out. Normally, that green cube would only draw the polygons that face the viewer. (The blue eye.) So the downward facing line and the leftward facing line would get drawn, and the other two would be left out. When we turn the cube inside-out, the opposite is true.  <\/p>\n<p>This also means that everything that casts a shadow must be an enclosed solid. This is sometimes called making an object &#8220;airtight&#8221;.  Here&#8217;s why:<\/p>\n<p>Let&#8217;s imagine our clever level designer realizes that, for whatever gameplay reason, the player will never, ever be able to reach the space to the right of the green cube. Since this is true, then we can just leave off that polygon:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_volume14.jpg' class='insetimage'   alt='unearth_volume14.jpg' title='unearth_volume14.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>Now the green cube is no longer an enclosed solid. Sure, it leaves hole in the level, but if the player can never get in a position to see it then it won&#8217;t do any harm, right? This is fine, and you can see this sort of polygon-trimming done frequently in older games<span class='snote' title='2'>It&#8217;s generally not worth optimizing these one-poly cases on modern machines, but you can see it in titles like Half-Life 2. Use cheat codes to fly around and you&#8217;ll see how aggressive the team was at removing stuff like this.<\/span>. But it becomes a problem when you use these objects to project shadows.<\/p>\n<p>Without the right-side face, there&#8217;s nothing to project a shadow onto the wall. <\/p>\n<p>EDIT: If you&#8217;re one of the many people annoyed\/ confused by this and are wondering why the LEFT side of the cube isn&#8217;t blocking the light, then reading <a href=\"?p=23460\" title=\"Project Unearth Part 2: Skimming Hazzard\">part 2<\/a> might help you out. I know this is tricky stuff. Good luck!<\/p>\n<p>You can also think of it this way:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_volume15.jpg' class='insetimage'   alt='unearth_volume15.jpg' title='unearth_volume15.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>The little regions between the dotted lines could (depending on viewing angle) have proper shadows, but the space between them would be fully bright because the back face of the cube isn&#8217;t there to project shadows. And while this is an extreme example, it&#8217;s actually easy for tiny flaws to produce scene-altering results. Since the polygons are projected away from the light to infinity, any leak ends up expanding to cover large areas of the screen. In practice this looks like a bright stripe of light, visible through all the walls, standing at a great distance away. <\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_minecraft.jpg' class='insetimage'   alt='unearth_minecraft.jpg' title='unearth_minecraft.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>The requirement that all shadow-making shapes need to be enclosed solids puts some interesting additional challenges on those of us working with large dynamic worlds. If you&#8217;re looking at a mountain in Minecraft, then in theory the mountain should be a fully enclosed solid<span class='snote' title='3'>Otherwise there would be somewhere you could go to &#8220;fall out of the world&#8221;.<\/span>. But in practice this isn&#8217;t the case. Maybe the mountain is so huge that we don&#8217;t have the far side of the mountain in memory. Or maybe that part of the mountain hasn&#8217;t been generated yet. And even when the far side of the mountain is loaded, there are sill more hills and caves behind that, and more beyond those. You never get to a hard edge where all the space is closed off once and for all.  The scenery on the far edge of your view always has a gaping void facing the horizon, and those missing faces &#8211; like our broken green cube above &#8211; will project malfunctioning shadows<span class='snote' title='4'>You may say, &#8220;Who cares if the far side of a mountain isn&#8217;t shadowed right, we can&#8217;t see it!&#8221; But imagine if you&#8217;re looking into the sunrise over that mountain. Those broken shadows will be projected RIGHT INTO YOUR FACE. The area around you will be shadowed all wrong.<\/span>.<\/p>\n<p>Again, reducing the problem to 2d, the typical Minecraft world looks like this-ish:<\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_solid1.jpg' class='insetimage'   alt='unearth_solid1.jpg' title='unearth_solid1.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>Think of this as a sort of cutaway view. When turned into polygons, it 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\/unearth_solid2.jpg' class='insetimage'   alt='unearth_solid2.jpg' title='unearth_solid2.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>Those open gaps at the sides and bottom are the problem. That&#8217;s where our bad shadows will originate. The solution I&#8217;ve settled on is to just cut up the world into chunks. Actually, you have to do this anyway so you can load and render the world piecemeal. The world is sectioned off into 8x8x8 chunks and so all we need to do is have it cap off every chunk. <\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_solid3.jpg' class='insetimage'   alt='unearth_solid3.jpg' title='unearth_solid3.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>This is really wasteful, but as far as I can tell it&#8217;s unavoidable if we want to use this shadow technique. (I might noodle around with other shadowing systems. I might not. We&#8217;ll see what sounds interesting when the time comes.) This also means we&#8217;re now working with two different sets of polygons: There are the polygons that you see, and there are the polygons that project shadows. The visible version of the chunk can be open (not enclosed) but needs to have information for normal mapping and surface texture included. The other version just needs to be a flat-color enclosed solid. <\/p>\n<p><table   class=\"\" cellpadding='0' cellspacing='0' border='0' align='center'><tr><td><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/unearth_solid4.jpg' class='insetimage'   alt='unearth_solid4.jpg' title='unearth_solid4.jpg'\/><\/td><\/tr><\/table><\/p>\n<p>Now we&#8217;re ready to look into this ridiculous low framerate. And by &#8220;now&#8221; I mean &#8220;next time&#8221;.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Last time I promised we&#8217;d be dealing with rendering performance problems. Lies. We&#8217;re going to backtrack instead. I skimmed a lot of concepts back in part 2, and I think we need to talk about stencil shadows in more detail before we can proceed. I&#8217;ve gone over this before, but polygons have front and back [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[],"class_list":["post-23547","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\/23547","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=23547"}],"version-history":[{"count":0,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/23547\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=23547"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=23547"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=23547"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}