Realtime Ambient Occlusion using multiple shadowmaps

Started by
5 comments, last by Hodgman 5 years, 8 months ago

So, i'm currently on a quest of finding a realtime world-space Ambient Occlusion algorithm for a game i'm making. (Or at least check if it's feasible. I wanted to avoid baking AO/lightmaps in a mapeditor as i would like to avoid storing lightmap data in my levelfiles in order to reduce the filesize as much as possible and avoid expensive/long precomputations in the first place.)

Now, i stumbled upon an AO concept which works by using multiple shadowmaps which are placed on the skys hemishpere and then merged together to create the Ambient Occlusion effect.

Here is an old example/demo from nvidia:

http://developer.download.nvidia.com/SDK/9.5/Samples/samples.html#ambient_occlusion

I was able to find a video which shows this in action:

Spoiler

 

It seems to work rather well, although i can see a couple issues with it:

- Rendering multiple shadowmaps is expensive (though that's expected with realtime AO)

- As shadows are only cast from the top, every surface which is pointing downwards will be 100% in shadow/black. (normally such a surface would have a bit of light around the edges due to the light bouncing around. It works best for surfaces facing upwards/towards the sky.)

- Flickering can be an issue if the shadowmap is covering a large scene/area or if the resolution of the shadowmap is too low. (could be fixed?)

 

It's incredibely hard to find information on this technique on the internet. (either demos, implementation/improvement details, etc...). I suppose because it's not that widely used?

Did anybody implement AO in a similar style like this? Are there any known sources which are covering this technique in more detail?

Advertisement

I implemented this on a PS3/360 game, but I rendered hundreds of shadow maps during the loading screen, and accumulated the results in texture space (a lightmap). For each shadow direction, I'd add 1/255 to any pixels in the lightmap that weren't shadowed. A few hundred shadowmaps later, and you got decent AO/skydome shadowing. 

If you don't use enough shadowmaps, the individual shadows can be quite visible, so you'd want to use a good soft shadowing technique (maybe VSM and friends?). 

To solve the resolution problem, I used a 1024px shadow map, but didn't do the entire level at one time - instead splitting the shadow view into a grid, and rendering each cell into the 1024px map (so it was actually like 256 directions x 9 grid cells = 2304 shadows). To split the work over multiple frames, I also didn't apply each shadowmap to the entire lightmap in one go - instead splitting the 4k lightmap into 4x4 1024px sections (so each shadowmap had to be applied up to 16 times, or up to 36864 total shadowmap->lightmap application steps). This kept the GPU cost as under 33ms per frame so the loading screens were interactive :)

I just tested this simple setup in blender and baked AO there:

issue.png.8c3f1272b6bf823d550eb0f4af8f7512.png

The middle part is correctly occluded but the edges on the side wouldn't be lit by the shadowmaps (because they are coming from the top.)

I suppose that placing additional shadowmaps on the botton isn't enough as those may then interfere with additional geometry (like a floor for example)

How did you handle this issue? Or is this just an artifact one has to accept with this technique?

 

Baking those lightmaps during the loading process is a good idea. (Hopefully it doesn't drag the loadingtimes out too much.)

5 hours ago, Lewa said:

It's incredibely hard to find information on this technique on the internet. (either demos, implementation/improvement details, etc...). I suppose because it's not that widely used? 

http://madebyevan.com/shaders/lightmap/

On 7/11/2018 at 5:25 PM, Jihodg said:

Thanks! The visualisation helped me to grasp the concept better.

I was able to implement this into my c++ project. Some screenshots:

 

Spoiler

a1.png

a2.png

a3.png

a4.png

It works quite well. (There are some issues like lightbleeding on the intersections between two planes and the UV map isn't that great but this can be fixed.)

I used blenders Icosphere to create uniformly distributed points on the sky. The samplecount had to be quite high to avoid any banding artifacts:

points.PNG

 

Now the issue is that due to the shadowmaps only being cast from above the ground (pointing downards) all triangles which point downwards (face normal at 0,0,-1) will be completely black.

An example:

blackUndersideMarked.png

One possible solution would be to have additional points under the ground (basically creating a full pointcloud sphere instead only a halfsphere) but the results were subpar. (Especially as the ground mesh occludes most of the stuff anyways.)

Removing the floor mesh from rendering for shadowmaps with the origin under the ground might work, but this introduces artifacts on geometry which is in contact with the ground.

 

I think the only proper solution for that would be to use the half-sphere (like in the screenshot above) and have (at least) one bounce lighting in the AO calculation to lighten interiors up a bit but i wasn't able to find a solution which would work well enough with this baking approach. (Maybe reflective shadowmaps? The issue is that they don't seem to check for occlusion of the bounced light.)

 

On 7/27/2018 at 11:46 AM, Lewa said:

I think the only proper solution for that would be to use the half-sphere (like in the screenshot above) and have (at least) one bounce lighting in the AO calculation to lighten interiors up a bit but i wasn't able to find a solution which would work well enough with this baking approach. (Maybe reflective shadowmaps? The issue is that they don't seem to check for occlusion of the bounced light.)

You might be able to use something like Imperfect Shadow Maps to implement a fairly cheap bounce. You could use it to do the direct light pass instead of traditional shadow maps too, actually :D 

This topic is closed to new replies.

Advertisement