4

I need to enhance the visual perception of some mechanical parts with very fine details, so I am playing now with different implementations of screen.space ambient occlusion.

Until now, I was drawing my geometries directly to the screen in forward-rendering by using gl.TRIANGLES at double the canvas resolution with antialiasing on, i.e. for instance, let say my canvas style is 800x600 px, then my canvas width/height are set to 1600x1200. Only by using screen antialiasing together with such a high resolution I can get the visual quality which I need.

By using a renderbuffer I am not able to get close to that needed quality, even by rendering at double the resolution, because of the lack of the antialiasing. I tried to implements many different antialiasing techniques in an additional post-processing step, but anyway I am not able to get clean, smooth lines. Here is an example of what I mean: see the long, slightly rotated parts at the bottom of the image.

antialiasing missed in renderbuffer

Is there any method to get clean, antialiased lines by drawing in a backbuffer during a screen-space post-processing? Any additional hint about other strategies/techniques will be appreciated.

Has someone successfully implemented - just to mention an example - FXAA, or something like that, during the SSAO pass, to get smooth antialiased long diagonal lines, without jagging?


Here is the fragment shader related to that picture above:

float compareDepths(in float depth1,in float depth2, in float aoMultiplier) {
    float aoCap = 1.0;
    float diff = sqrt( clamp(1.0-(depth1-depth2) / (u_aoRange/(u_zFar-u_zNear)),0.0,1.0) );
    float ao = min(aoCap,max(0.0, depth1 - depth2 - u_depthTolerance) * aoMultiplier) * diff;
    return ao;
}
void main(void) {
    vec2 UV = v_texCoord.st;
    float depth = readDepth(UV);
    float d;
    float pw = 1.0 / u_resolution.x;
    float ph = 1.0 / u_resolution.y;
    float aoCap = 1.0;
    float ao = 0.0;
    float aoMultiplier = u_aoMultiplier;

    // 4 samples w/out loop
    float aoscale=1.0;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    pw*=2.0;
    ph*=2.0;
    aoMultiplier/=2.0;
    aoscale*=1.2;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    pw*=2.0;
    ph*=2.0;
    aoMultiplier/=2.0;
    aoscale*=1.2;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    pw*=2.0;
    ph*=2.0;
    aoMultiplier/=2.0;
    aoscale*=1.2;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    ao/=16.0;',
    gl_FragColor = vec4( vec3(1.0-ao), 1.0 );
}

EDIT:

Below I am using the SSAO technique described by John Chapman in this great SSAO Tutorial.

Left at quadruple resolution, right at full resolution with separated gaussian blur.

comparison

Please note, the artifacts aren't disturbing by using some classic more "organic" or "curved" models like, for example, the Teapot, the Stanford Dragon or the Happy Buddha. These artifacts are noticeable with regular, geometrical long objects, typical mechanical or architectural shapes.

Is there any method to enhance the depth perception, by keeping that quality and preserving high frequency details, without using four times the canvas resolution?

EDIT2:

The final result looks very good at full canvas size on retina displays, for example on iPad, which has 264 pixels per inch resolution. However, the jagged lines are clearly visible and disturbing on desktop monitors, with typically 70 or 92 DPI.

I discovered this post: multiresolution ambient occlusion from Íñigo Quílez which contain some hints also about High frequency occlusion - procedural occlusion to enhance tiny details, but I am not able to understand if this could be applicable also for straight geometrical shapes. Someone did already experiments with this?

EDIT3:

here is the most useful reference I found so far, about this topic: Fast Prefiltered Lines from GPU Gems 2. Someone already implemented the technique described here together with SSAO?

deblocker
  • 7,629
  • 2
  • 24
  • 59
  • @Rabbid76: Please, see my edit, I added some details. Obviously, applying such high resolution isn't affordable. Any ideas how to smooth long geometrical lines while preserving high frequency details? – deblocker Feb 04 '18 at 10:56
  • @Rabbid76: correct, thank You for pointing out that. The 4*4 linear blur is also in my test suite. SSAO strenght is also exaggerated. Anyway, I am not able to get rid of that kind of artifact (jagged lines), still researching what I can do. – deblocker Feb 07 '18 at 08:36

2 Answers2

2

Screen Space Ambient Occlusion captures the low frequency lighting. It doesn't capture sharp shadows or Diffuse or Specular lighting. For this reason, SSAO is usually combined with Diffuse and Specular lighting to create a full lighting solution.

The SSAO exhibits global lighting effects in 3D-rendered scenes as a post effect. It approximates expensive raytraced global illumination quickly. So, artifacts may appear in certain situations (like yours).

SSAO rarely works out of the box, but requires some tweaking. The setup process involves adjusting the Kernel Radius and Number Of Samples to get the desired affect. The Kernel Radius depends on the natural scale of the scene. Initially there might appear to be no SSAO at all. At this point either the Kernel Radius is too small or too big and working values have to be found. And remember: SSAO is very slow on the CPU, but performs much better on the GPU.

SOLUTION: Combining multiple SSAO render passes with different Kernel Radii can produce better effect.

Look at picture's lower right corner:

(three multiplied images produce the final image with certain details)

enter image description here

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • It was made in Autodesk Maya and then layered in node-based compositing application like Apple Shake or The Foundry Nuke. There's no code. Depth-drawing pass can't be antialiased. Only Deep Pass can be antialiased. Read articles on Deep Shadows by Pixar. – Andy Jazz Feb 09 '18 at 08:15
1

SSAO is a sample-based technique, so by its very nature it tends towards salt-and-pepper noise in the output.

You can reduce the noise in the SSAO output itself by using variable sampling patterns for different pixels, so you don't get structural error harmonics.

You can also increase the number of samples, but this can get pretty expensive and doesn't really fix the problem, although SSAO can be processed at half resolution most of the time without much appreciable quality loss.

The usual fix is to further post-process the SSAO output multiple times with a Gaussian blur filter to smooth out the high frequency noise. Ambient light tends not to have high frequency components anyway, so the loss in quality is pretty small.

solidpixel
  • 10,688
  • 1
  • 20
  • 33
  • Thanks for Your time, Yours is a canonical description of SSAO... some ideas to solve that? I edited my question with more details. – deblocker Feb 04 '18 at 09:28
  • 1
    You can't "solve" this - the very nature of the algorithm is noisy. It's not designed for accurate high frequency output (given the normal use of blurs), and normally in gaming you're applying the SSAO output over the top of e.g. high frequency diffuse maps and other color data which will hide some of the artefacts. You're really using SSAO for something it's not designed for. – solidpixel Feb 05 '18 at 10:55