Today we're going to discuss ambient occlusion in SoA, in a continuation of discussing post-processing effects in the game. So let's jump straight to it!
For a better format, read the blog post here!
Ambient lighting is lighting that affects all things in the scene equally. It is a very simple approximation of light bouncing off of objects and is a way to improve lighting quality by darkening things that should be occluded by nearby objects. For instance the corner of a room should be a bit darker than the flat walls of a room. Traditionally, SoA used a baked ambient occlusion approach, where it approximates ambient occlusion for each vertex based on nearby voxels and darkens the mesh. However, this method can increase the amount of geometry in the scene because baked AO causes greedy merging to fail in many cases. Furthermore, dynamic objects such as NPCs and other entities will not contribute any ambient occlusion to the scene. Here's a really old image of AO in SoA. As you can see, the quality leaves much to be desired.
A better solution is to use a post processing effect to simulate ambient occlusion on the entire scene. Not only will the quality be better, but entities and other objects in the scene will also contribute to ambient occlusion! We decided to use Screen Space Ambient Occlusion (SSAO) since it works very well with our in-progress deferred rendering pipeline.
[ Stolen from wikipedia ]
This technique does not require anything to be done within the meshing, but instead calculates the darkening values for every frame on the fly using the depth values of the already rendered scene. This effect isn't free, though. It can be expensive if you want to have a good quality occlusion. We will have options to reduce the quality, and may even provide the option to use baked AO instead for graphics cards that can't handle SSAO. There can also be some artefacts, but most people do not notice these artefacts unless they know to look at them. (Even the witcher 3 has them, and it's not too bothersome.)
The way SSAO works, is that for each pixel in the scene, you generate a cloud of random points around it. For each of these points, you check if the pixel is closer to the camera than the original pixel. If it is, you increase the darkening factor of the original pixel! A hemisphere cloud gives a pretty good result. As you can see in the following image, the grey circles are ones that will contribute to the darkness for the pixel at the black circle.
[ Stolen from Learnopengl.com ]
Rather than randomly generate the cloud for every pixel, it's much cheaper to just use the same cloud of random points for every pixel, but because of the regularity you end up with ugly borders. An easy way to fix this is to use a noise pass, but that results in things looking noisy. However, by applying noise and bluring the result afterwards, we get fairly good results!
Here is a comparison without and with SSAO.
As you can see, it is a very pleasing effect! The implementation isn't quite there yet, there's a couple bugs and the performance could probably be tweaked, but it still looks great in game, and provides a subtle darkening for flora that we did not have with the old method!
Also, be sure to check out the 5th community spotlight video if you haven't already!
We have a new interview section starting the following video, in which a member of the team will be asked questions drawn from a thread on the forums (this thread). The first interview will be of Ben, so be sure to put forward any questions you have for him!