{"id":49788,"date":"2020-04-21T06:00:05","date_gmt":"2020-04-21T10:00:05","guid":{"rendered":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=49788"},"modified":"2020-04-21T13:14:15","modified_gmt":"2020-04-21T17:14:15","slug":"adventures-in-raytracing","status":"publish","type":"post","link":"https:\/\/www.shamusyoung.com\/twentysidedtale\/?p=49788","title":{"rendered":"Adventures in Raytracing"},"content":{"rendered":"<p>In the previous entry I ended with an abrupt half-joke where I said I got raytracing working. The idea was that I spent days struggling to get simple old technology working properly, but then casually mastered cutting-edge tech in a single sentence. Sadly, it&#8217;s not totally true. I got access to raytracing, but I think it&#8217;s a stretch to say it&#8217;s &#8220;working&#8221;.<\/p>\n<p>When I left off, I presented you with an image that looked more or less like this:<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/basalt5.jpg' width=100% alt='I&apos;ve fiddled with the lighting \/ textures \/ render settings since the last entry, which is why this looks different than it did a few days ago. This is still the same room \/ viewing angle we&apos;ve been looking at all along.' title='I&apos;ve fiddled with the lighting \/ textures \/ render settings since the last entry, which is why this looks different than it did a few days ago. This is still the same room \/ viewing angle we&apos;ve been looking at all along.'\/><\/div><div class='mouseover-alt'>I&apos;ve fiddled with the lighting \/ textures \/ render settings since the last entry, which is why this looks different than it did a few days ago. This is still the same room \/ viewing angle we&apos;ve been looking at all along.<\/div><\/p>\n<p>That&#8217;s what the program looks like when you leave it alone, but if you move the camera even slightly then it looks something like this: <!--more--><\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/basalt6.jpg' width=100% alt='I know this looks bad in still frame, but trust me: It&apos;s actually way worse in motion.' title='I know this looks bad in still frame, but trust me: It&apos;s actually way worse in motion.'\/><\/div><div class='mouseover-alt'>I know this looks bad in still frame, but trust me: It&apos;s actually way worse in motion.<\/div><\/p>\n<p>To a certain extent, this is expected. This is what you get with raytracing \/ path tracing. Even on the cutting-edge magic hardware we have these days, you still don&#8217;t get more than a few thousand rays per frame. We get around this with two techniques:<\/p>\n<ol>\n<li>We take the little bit of data available and spread it out. I&#8217;m not sure of the exact algorithm used, but it&#8217;s probably something like &#8220;if you&#8217;re rendering a spot that hasn&#8217;t been hit with ANY rays, then use the nearest available one&#8221;. So those existing pixels of light would get smeared out to fill the gaps. This means that the lighting starts out &#8220;blurry&#8221;. The walls and textures remain crisp, but the patterns of light and dark are initially vague. This gives the images a kind of &#8220;dreamy&#8221; quality.<\/li>\n<li>We accumulate rays over multiple frames. Each frame adds a few more rays to the scene, gradually filling things in and sharpening up the lighting. This means the room is initially dark if the whole thing enters the frame abruptly. The room starts out dim, and then gradually lightens as more light rays are added. You&#8217;d think this would look wrong, but it ends up feeling like your eyes adjusting when you enter a dark room. This works even if the previous room and this new one are supposed to be the same level of brightness. You can run back and forth between the two rooms, and it will always feel like you&#8217;re moving from a brighter room to a dimmer one. It seems to be one of those tricks that your brain just ignores.<\/li>\n<\/ol>\n<p>As far as I can tell, these features are collectively called &#8220;denoising&#8221;. In the <a href=\"https:\/\/store.steampowered.com\/app\/1089130\/Quake_II_RTX\/\">Quake 2 RTX demo<\/a>, there&#8217;s a console command to turn denoising off and allow you to see the raw images with low ray counts, like my image above. The problem I&#8217;m having in Unity is that I can&#8217;t find either of these features. There are a few possibilities:<\/p>\n<ol>\n<li>Denoising hasn&#8217;t been implemented. I&#8217;m using a preview version of Unity for this project<span class='snote' title='1'>Unity is REALLY graceful about letting you have several different versions installed simultaneously, and it keeps track of which projects belong with which versions. It&#8217;s pretty great.<\/span> and it&#8217;s possible that denoising is still on someone&#8217;s to-do list.<\/li>\n<li>The denoising in the Quake 2 demo is an implementation of a very NVIDIA-specific feature. Maybe the Unity team wants to avoid manufacturer-specific gimmicks like that and aim for generalized solutions. Therefore, this is as good as it&#8217;s going to get until NVIDIA and AMD embrace some sort of standard. That will probably take months or years.<\/li>\n<li>The denoising feature exists, but it&#8217;s not documented and so I have no way of knowing where to find it or how to use it.<\/li>\n<\/ol>\n<p>Normally I&#8217;m hard on the Unity team for the state of their documentation<span class='snote' title='2'>Particularly this ludicrous habit of documenting important things inside of hour-long video presentations. Arg. My rage is boundless.<\/span>, but in this case I&#8217;m obliged to cut them some slack. It&#8217;s called a &#8220;preview&#8221; version for a reason, and documentation is usually the last step. It&#8217;s annoying to have to fumble around in the dark like this, but that comes with the territory if you&#8217;re messing around with beta software.<\/p>\n<h3>Soon, or Never?<\/h3>\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\/lyfTPG-dwOE\" frameborder=\"0\" allowfullscreen class=\"embed\"><\/iframe><br\/><small><a href='http:\/\/www.youtube.com\/watch?v=lyfTPG-dwOE'>Link (YouTube)<\/a><\/small><\/td><\/tr><\/table><\/p>\n<p>While I understand the lack of documentation, I really wish I could figure out if this is a problem that Unity plans to solve in the future. Without denoising, this system is largely useless for realtime projects. Indeed, on the forums it seems like everyone else is doing slow renders of photorealistic scenes.<\/p>\n<p><strong>But Shamus! I use Unity, and I&#8217;ve seen a &#8220;denoise&#8221; feature in the past. Are you blind?!<\/strong><\/p>\n<p>Yes, there&#8217;s actually a feature CALLED &#8220;denoising&#8221; in the render options, but it doesn&#8217;t seem to do anything and I&#8217;m not even sure it&#8217;s related to raytracing. One of the things I&#8217;m struggling with is that the options aren&#8217;t very organized right now. Like, there are two competing systems in use right now: Raytracing, and path tracing. But in Unity you have to enable raytracing, and then under the raytracing dialog you get a checkbox for path tracing. That&#8217;s like making Coke a subset of Pepsi. The menus are full of options for old-school rendering, current-gen rendering, raytracing, and path tracing. Some options only impact one of these systems, and there&#8217;s no way to tell if the feature you&#8217;re looking at is relevant in the render path you&#8217;re currently using.<\/p>\n<p>At one point I clipped outside the level and I saw the sky was a gradient color with a horizon. It was really confusing to have all that background detail while I was trying to examine the level from the outside, and I wanted a simple flat color. I found <strong>four different dialogs<\/strong> that had settings for the gradient sky. I turned them all off, and the feature is <strong>still<\/strong> active.<\/p>\n<p>The point I&#8217;m getting at is that the interface needs a re-work to support all this new stuff, and until that happens we have random features scattered everywhere and doing anything requires a ton of trial and error.<\/p>\n<p>Anyway, back to the problem at hand.<\/p>\n<p>It&#8217;s a shame I can&#8217;t make this work a little better. It&#8217;s really annoying trying to view the world through this odd shimmering snow, and if I want to see what I&#8217;m doing I have to hold perfectly still for 4-7 seconds to allow the rays to build up.<\/p>\n<p>One way to make this slightly less painful is to make it so that there&#8217;s a lot more light. To this end, I slapped a grid of lights on the ceiling texture. It looks terrible, but it also makes it so the image stabilizes in 2-3 seconds instead of 4-7. I also added a reflective floor, because what else are you gonna do when you have raytracing? I predict that mirrored floors will be all the rage once raytracing catches on. In the 90s, game designers went nuts with the new colored lighting and turned their levels into rainbow neon puke fests<span class='snote' title='3'>The original Unreal was the most over the top about this. And to be fair, it really did look amazing at the time.<\/span>. I expect we&#8217;ll get the same thing with overly-polished surfaces in the next couple of years.<\/p>\n<h3>If Only This Worked&#8230;<\/h3>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/basalt7.jpg' width=100% alt='I know last time I said I wasn&apos;t going to implement water. Looks like I lied. Again.' title='I know last time I said I wasn&apos;t going to implement water. Looks like I lied. Again.'\/><\/div><div class='mouseover-alt'>I know last time I said I wasn&apos;t going to implement water. Looks like I lied. Again.<\/div><\/p>\n<p>I&#8217;ve been waiting for this moment for a long time. Once we get proper raytracing working, everything gets WAY easier for those of us making procgen content. In traditional rendering, making interesting lighting ends up being a massive pain in the ass. Lights are expensive. If you have too many in the same room, then you&#8217;ll kill the framerate. Too few, and you end up with either pitch black areas, or large sections where the lighting is very flat. You have to make sure your real light sources<span class='snote' title='4'>The point in space that creates light.<\/span> are reasonably close to your apparent light sources <span class='snote' title='5'>Example: A 3D model of a lamp<\/span> and you need to position them so that you don&#8217;t get strange shadows<span class='snote' title='6'>You don&#8217;t want some little corner of the lamp to cast huge dramatic shadows all over the room.<\/span> or visual artifacts<span class='snote' title='7'>If you stick the light INSIDE the lamp, then it will be inside a hull of outward-facing polygons. Little bits of geometry will end up blocking the light in odd ways.<\/span>.<\/p>\n<p>But in a raytracing context, none of this is a problem. You don&#8217;t need to worry about having an extra light here or there, because lights are literally free. Actually, a bunch of people nitpicked the video I linked above, explaining to me that lights aren&#8217;t actually free. Lights still cost CPU + GPU cycles to use! You fool!<\/p>\n<p>To which I say: <em>It actually depends on how you set them up<\/em>. Yes, if you add traditional light sources then there&#8217;s some additional overhead. But why bother with that? In my project, I don&#8217;t have any light sources. I just have some textures set to glow. The renderer doesn&#8217;t even need to know that I&#8217;m using this thing as a light source. Rays bounce off of it and hit a wall, and you get light. That&#8217;s not any more expensive than bouncing a ray off a dark wall.<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/basalt8.jpg?' width=100% alt='The foreground looks fantastic thanks to this lit cube, but you can see the dim walls in the background are still really noisy.' title='The foreground looks fantastic thanks to this lit cube, but you can see the dim walls in the background are still really noisy.'\/><\/div><div class='mouseover-alt'>The foreground looks fantastic thanks to this lit cube, but you can see the dim walls in the background are still really noisy.<\/div><\/p>\n<p>Also, making light sources out of objects solves other problems. In the real world, lights generally have a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Umbra,_penumbra_and_antumbra#Penumbra\">penumbra<\/a>. You get a spot on the table that&#8217;s in half-light because it&#8217;s exposed to the left half of the lightbulb, but the right half of the light bulb is blocked by an object on the table.\u00a0In traditional rendering, room lights come from an infinitely small point in space. This means they cast unnaturally harsh shadows with perfectly crisp edges. For years we&#8217;ve been trying to fix this by taking our crisp shadows and deliberately blurring them a bit.\u00a0 That softens the shadow, but it&#8217;s expensive and can lead to nonsensical results. Like the blurring goes both ways, which means it looks like the very edge of a wall is slightly transparent because some light appears to pass through it.<\/p>\n<p>When the light is coming from an object, this stops being a problem because it works just like the real world. Larger lights will cast softer shadows because they&#8217;ll have a larger penumbra. The light comes out of whatever shape you make, so a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Fluorescent_lamp\">tube light<\/a> will behave differently compared to a light bulb, which will give different results than a bonfire. You don&#8217;t need any special code to do this. You just make your object the right shape and texture and you&#8217;ll get light.<\/p>\n<p>With tracing, rooms won&#8217;t be overpowered if you use too many lights. Just like in real life, turning on three lamps doesn&#8217;t turn the room into a blinding white-out. It just makes it a little brighter. Likewise, having too few won&#8217;t make the image flat because you&#8217;ll still have lights reflected in from other places. And in either case, you can have all the lights you want without worrying about performance. You don&#8217;t have to turn off shadows for all the lights in the level and just have shadows enabled for the closest few, and then have a system for fading the shadows in and out as you change position. That&#8217;s a huge pain in the ass with lots of weird edge cases and fussy details to worry about<span class='snote' title='8'>Like, this light is one of the five closest, so we want to enable expensive shadows for it, right? No! It&#8217;s close spatially, but it&#8217;s in another hotel room and there&#8217;s no way for any of the emitted light to reach me. So this lamp is wasting processing cycles for no reason and should be turned off.<\/span>. With tracing, you just let the lighting happen. You get shadows everywhere, all the time, and you don&#8217;t even need to care about where it&#8217;s coming from. A room made entirely of glowing bricks isn&#8217;t any more expensive to render than a room made of regular bricks.<\/p>\n<p>All of this makes everything so much simpler for procgen content.<\/p>\n<p><div class='imagefull'><img src='https:\/\/www.shamusyoung.com\/twentysidedtale\/images\/basalt9.jpg?' width=100% alt='I hung a light tube from the ceiling and the light is coming from the entire tube rather than some arbitrary point in the middle.' title='I hung a light tube from the ceiling and the light is coming from the entire tube rather than some arbitrary point in the middle.'\/><\/div><div class='mouseover-alt'>I hung a light tube from the ceiling and the light is coming from the entire tube rather than some arbitrary point in the middle.<\/div><\/p>\n<p>As for this project: I don&#8217;t know that there&#8217;s anything left to do at this point. I got a BSP reader working to my satisfaction, and I&#8217;ve fiddled with Unity&#8217;s current ray \/ path tracing solution. Maybe I&#8217;ll come back to this in a few weeks \/ months when there&#8217;s some new information or a new version to try, but for now I think I&#8217;m done.<\/p>\n<p>But! There&#8217;s more programming content coming Real Soon Now.<\/p>\n<p>WARNING: This post was thrown together at the last minute and didn&#8217;t get my usual editing pass. There may be (and probably are) many grammatical and typographical errors. Proceed at your own risk. Additionally, I may have put this warning in the wrong place.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous entry I ended with an abrupt half-joke where I said I got raytracing working. The idea was that I spent days struggling to get simple old technology working properly, but then casually mastered cutting-edge tech in a single sentence. Sadly, it&#8217;s not totally true. I got access to raytracing, but I think [&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-49788","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\/49788","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=49788"}],"version-history":[{"count":17,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/49788\/revisions"}],"predecessor-version":[{"id":49805,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=\/wp\/v2\/posts\/49788\/revisions\/49805"}],"wp:attachment":[{"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=49788"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=49788"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.shamusyoung.com\/twentysidedtale\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=49788"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}