Wednesday, September 13, 2017

Adventures in Screen Space

Eight years ago, just when I first started writing this blog my second post was about screen space ambient occlusion. I used that renderer for all my physics experiments, leading up to the fluid simulation that became Sprinkle. At that point I left desktop computing in favor of mobile devices. Ten games later I'm now back to desktop machines and I'm completely blown away by all the computing power.

For the first Sprinkle game I had to make dedicated geometry with holes in it when drawing large alpha blended overlays because the fill rate was so terrible. Now I'm running hundreds of lines of code really doing complex computations per pixel. Sorry, you have probably already adjusted but this will take me a while. 

So what would be more fitting than to freshen up that old physics renderer (well more like starting from scratch, but still). I have been wanting to experiment with physics in VR for a while and now is the time. For this I need a renderer that can handle a truly dynamic world with no precomputed lighting.

I have implemented screen space ambient occlusion with temporal reprojection filtering that takes a lot of the noise away without smearing out the result. I've always hated shadow maps. They are hard to implement and the result is usually disappointing, so for this renderer I tried doing shadows entirely in screen space using ray marching towards the light source. It's a bit of an experiment, but I find the results really interesting. The characteristics are very different from regular shadow maps – instead of getting precise but jagged shadows this one gives imprecise and smooth, blurry shadows. I can't really decide if I like it or not. For a sunny outdoor setting, regular shadow maps are probably better, but for the more diffuse, indoor lighting this is quite promising.

There is also depth of field close to the camera done in four passes on half resolution and motion blur on everything. I'm going for a old, analogue look on the final result, so any imperfections that can tone down the artificial computer graphics characteristics is a good thing. The ambient occlusion and screen space shadows do add a little bit of noise, but there is one cheap and paradoxically efficient way of hiding unwanted noise: add more noise. So at the final stages of the pipeline I add 5-7% of greyscale noise which hides some of the noise in occluded areas and adds to the analogue look.

I have a bloom pass as well and I just started playing with tone mapping. I'm not sure I'm really getting it, but I'll keep experimenting. For anti-aliasing my friend Ludde Andersson over at Scaupa pointed me to a temporal reprojection method that I found very interesting. Since I'm already doing temporal repojection for the occlusion and shadows it was quite easy to do the same for anti-aliasing. The idea is to move the viewport at sub-pixel resolution every frame and smooth out the result with an accumulation buffer. It also turned out that one of me absolute favourite games Inside has a great presentation on the topic from last years GDC. The results are absolutely stunning. I'm not sure I have ever come a cross a new rendering technique that is so clever and simple yet produces so fantastic results with almost no computational overhead. Am I missing something or why aren't everybody using this?