Crysis Screen-Space Ambient Occlusion (ShaderX^7 article)

Started by
8 comments, last by Manoel Balbino 13 years, 9 months ago
Hey guys,

I'm trying to understand how screen space ambient occlusion is done in various games (specially in Crysis and Starcraft 2), but there something I'm not getting right.

In the ShaderX^7 article they say that high-frequency details at high distance are not recognizable by the human visual system, as so does low frequency details at very close proximity. Then they conclude that AO size, or area taken into account can be fixed in screen space. This allows to apply AO simulteanously to close tiny objects like faces, and far huge objects like mountains.

The problem I see is that, if you keep the area fixed in screen-space, when for example, you travel towards a person, the size of the ambient occluded areas in its face will shrink as the area taken into account is keep fixed.

On the other hand, this seems to be done differently in Starcraft, as they apply the offset vectors in eye space then project to screen space, thus they have a varying AO area depending on how far is the object from the camera. This means AO will look the same independently of the distance from the rendered object to the camera.

Somebody knows if these conclusions are correct, or if I'am not getting something?

Thanks!!
Advertisement
This approach:
http://www.gamedev.net/reference/programming/features/simpleSSAO/

uses a sample radius size that is adjusted depending on fragment depth, so the AO "size" is constant in world space. I think it looks great.
For what it's worth, I've just implemented SSAO using a fixed size "kernel" (that is, fixed in screen space) and while I occasionally notice some strangeness on approach to certain objects, overall I'm surprised at how natural it looks. If I wasn't looking for artifacts I would be hard pressed to identify them, and even knowing where to look, I don't find them very offensive.

The nice thing about the screen-space kernel is that the AO is very uniform in every view of every scene, so it's very unfussy.

With a proper world space kernel it will probably have to be adjusted differently for each scene, depending on the content, and that means exposing a bunch of artist controls and dealing with transitions, etc.

The Starcraft guys acknowledged in their paper that they had to ultimately limit the screen-space projection of their kernel anyway to avoid drastic performance loss in close-ups, so it seems unavoidable to some degree.
I believe the Starcraft guys also used two radiuses, one small and one larger. They averaged the samples for each radius separately, and choose the one with most occlusion. This approach gave them both local and slightly more global details....
Don't forget that starcraft has a very specific camera setup - it's RTS not FPS, where you can see someones face in front of you and mountaines behind him. I've implemented ssao with a kernel that is adjusted by a distance, so you get a minimum and maximum sampling radius. You cap maximum radius close to camera so depth is coherently sampled and at big distance so you capture ssao for very distant objects, like mountaines, trees, buildings. Minimum is caped in between so you sample at least 5x5 region around current fragment. If you make kernel in world space or view space, you will need to use such minimum and maximum sampling radius anyway.
Quote:Original post by venzon
This approach:
http://www.gamedev.net/reference/programming/features/simpleSSAO/

uses a sample radius size that is adjusted depending on fragment depth, so the AO "size" is constant in world space. I think it looks great.

Thanks for sharing!

Quote:Original post by 0xffffffff
For what it's worth, I've just implemented SSAO using a fixed size "kernel" (that is, fixed in screen space) and while I occasionally notice some strangeness on approach to certain objects, overall I'm surprised at how natural it looks.


After looking at how natural this movie looks:

http://video.google.com/videoplay?docid=-2592720445119800709#

I got to the conclussion that it was really impossible that the sample radious was kept fixed, so I thought that maybe I was getting something wrong. To me, in this movie the occlusion seems to be fixed independently on how far or close you are to the objects (but maybe it is just that, as you say, it just looks natural keeping the sample area fixed in screen space).

Quote:Original post by stalef
I believe the Starcraft guys also used two radiuses, one small and one larger. They averaged the samples for each radius separately, and choose the one with most occlusion. This approach gave them both local and slightly more global details....


I think this was because the AO shader was getting used by some artists for giving a GI-like look to the images, which required a larger area size. So they finally used two area sizes, one for GI and other for AO.

Quote:Original post by Viik
Don't forget that starcraft has a very specific camera setup - it's RTS not FPS, where you can see someones face in front of you and mountaines behind him. I've implemented ssao with a kernel that is adjusted by a distance, so you get a minimum and maximum sampling radius. You cap maximum radius close to camera so depth is coherently sampled and at big distance so you capture ssao for very distant objects, like mountaines, trees, buildings. Minimum is caped in between so you sample at least 5x5 region around current fragment. If you make kernel in world space or view space, you will need to use such minimum and maximum sampling radius anyway


So, that would be an hybrid approach between keeping it fixed and modulating it with distance.

Thanks all!
I changed our SSAO to use a fixed (in 3d space) kernel yesterday as a test, and it looked good too. On the plus side, the nice blob shadows around the feet didn't fuzz out when the camera pulled back, but the trade-off was the loss of the nice soft shading around large distant structures. I don't really have a strong preference either way--each approach has different advantages. I think I'll stick with screen space.
Related with this thing, I'm struggling to fully understand the ambient occlusion algorithm of Crysis.

The code first loops to generate 8 offset vectors that correspond to the vertices of a 2x2x2 cube centered around current pixel. Then these vectors are scaled and rotated by a random matrix. The resulting vRotatedOffset is then added to current pixel pos:

vSamplePos += float3(vRotatedOffset.xy, vRotatedOffset.z * depth * 2);

Where depth is the depth of current pixel (where AO is getting calculated). Then, vSamplePos is used to query the depth value of the sample, to check the occlusion for this sample.

What I fail to understand is where depth * 2 is coming from. I suppose that multiplying by depth is because in this AO implementation the sampling area is fixed in screen-space, thus calculating AO for pixels far from the camera require a bigger z-component for the offset than when it is near to the camera (as in this case the sampling sphere is bigger in 3D space). But why 2? Maybe it is magic number? There is comment accompanying this line that says: "shift coordinates by offset vector (range convert and width depth value)".

It would be great to contact Vladimir Kajalin (the author of the article), but I wasn't able to google his mail.

Thanks!

[Edited by - IrYoKu1 on July 18, 2010 12:58:36 PM]
My personal opinion about the radius of SSAO is that it should always be dependent on the depth. It is true that using a fixed radius provides occlusion for both close and distant objects, but it looks very unnatural.

I've tried both approaches and I can guaraantee that using a depth-dependent radius gives a much better look to SSAO.
Remember that StartCraft 2 also mixes pre-baked AO into SSAO by using the darker of the two at each fragment.

This way it's possible to use pre-baked AO (either baked in the vertex colors or in low-res lightmaps - or a combination of both) for low frequency, large area AO while using SSAO for the finer details and contact shadows.

This topic is closed to new replies.

Advertisement