SSAO Post Process

Share your helpful Urho3D code snippets, samples and tutorials here.

SSAO Post Process

PostPosted by artgolf1000 » 08 Nov 2016, 07:34

Hi,

I'm studying how to implement a good SSAO shader, the core code is ported from: https://github.com/jsj2008/Zombie-Blobs/blob/278e16229ccb77b2e11d788082b2ccebb9722ace/src/postproc.fs

The original shader always generates thick shadow on the background, I added a threshold to check if it is in this case, and I added some clear comments.

The result is fine enough, no need to add a blur pass, I make it a post process, it only support forward lighting now.

If you have any alpha layers, please merge ssao.xml and Forward.xml as one render path, and make sure all about alpha is after ssao pass.

Edit: It support mobile devices now, the performance is good, CPU increases 2% on my iPad mini retina.

c++:
Code: Select all
ResourceCache* cache = GetSubsystem<ResourceCache>();
GetSubsystem<Renderer>()->GetViewport(0)->GetRenderPath()->Append(cache->GetResource<XMLFile>("PostProcess/ssao.xml"));

Vector2 screenSize(GetSubsystem<Graphics>()->GetWidth(), GetSubsystem<Graphics>()->GetHeight());
GetSubsystem<Renderer>()->GetViewport(0)->GetRenderPath()->SetShaderParameter("ScreenSize", screenSize);


ssao.xml:
Code: Select all
<renderpath>
    <rendertarget name="depth" sizedivisor="1 1" format="lineardepth" />
    <command type="clear" color="1 1 1 1" depth="1.0" stencil="0" output="depth" />
    <command type="scenepass" pass="depth" output="depth" />
    <command type="quad" tag="ssao" vs="ssao" ps="ssao">
        <parameter name="ScreenSize" value="1024 768" />
        <texture unit="diffuse" name="viewport" />
        <texture unit="emissive" name="depth" />
    </command>
</renderpath>


ssao.glsl:
Code: Select all
#include "Uniforms.glsl"
#include "Samplers.glsl"
#include "Transform.glsl"
#include "ScreenPos.glsl"

varying highp vec2 vScreenPos;

#ifdef COMPILEVS

void VS()
{
    mat4 modelMatrix = iModelMatrix;
    vec3 worldPos = GetWorldPos(modelMatrix);
    gl_Position = GetClipPos(worldPos);
    vScreenPos = GetScreenPosPreDiv(gl_Position);
}

#endif


#ifdef COMPILEPS
uniform highp vec2 cScreenSize;

// Port from: https://github.com/jsj2008/Zombie-Blobs/blob/278e16229ccb77b2e11d788082b2ccebb9722ace/src/postproc.fs

// see T Möller, 1999: Efficiently building a matrix to rotate one vector to another
mat3 rotateNormalVecToAnother(vec3 f, vec3 t) {
    vec3 v = cross(f, t);
    float c = dot(f, t);
    float h = (1.0 - c) / (1.0 - c * c);
    return mat3(c + h * v.x * v.x, h * v.x * v.y + v.z, h * v.x * v.z - v.y,
                h * v.x * v.y - v.z, c + h * v.y * v.y, h * v.y * v.z + v.x,
                h * v.x * v.z + v.y, h * v.y * v.z - v.x, c + h * v.z * v.z);
}

vec3 normal_from_depth(float depth, highp vec2 texcoords) {
    // One pixel: 0.001 = 1 / 1000 (pixels)
    const vec2 offset1 = vec2(0.0, 0.001);
    const vec2 offset2 = vec2(0.001, 0.0);
   
    float depth1 = DecodeDepth(texture2D(sEmissiveMap, texcoords + offset1).rgb);
    float depth2 = DecodeDepth(texture2D(sEmissiveMap, texcoords + offset2).rgb);
   
    vec3 p1 = vec3(offset1, depth1 - depth);
    vec3 p2 = vec3(offset2, depth2 - depth);
   
    highp vec3 normal = cross(p1, p2);
    normal.z = -normal.z;
   
    return normalize(normal);
}

void PS()
{
    const float aoStrength = 1.0;
   
    highp vec2 tx = vScreenPos;
    highp vec2 px = vec2(1.0 / cScreenSize.x, 1.0 / cScreenSize.y);
   
    float depth = DecodeDepth(texture2D(sEmissiveMap, vScreenPos).rgb);
    vec3  normal = normal_from_depth(depth, vScreenPos);
   
    // radius is in world space unit
    const float radius = 1.0;
    float zRange = radius / (cFarClipPS - cNearClipPS);
   
    // calculate inverse matrix of the normal by rotate it to identity
    mat3 InverseNormalMatrix = rotateNormalVecToAnother(normal, vec3(0.0, 0.0, 1.0));
   
    // result of line sampling
    // See Loos & Sloan: Volumetric Obscurance
    // http://www.cs.utah.edu/~loos/publications/vo/vo.pdf
    float hemi = 0.0;
    float maxi = 0.0;
   
    for (int x = -2; x <= 2; ++x) {
        for (int y = -2; y <= 2; ++y) {
            // make virtual sphere of unit volume, more closer to center, more ambient occlusion contributions
            float rx = 0.3 * float(x);
            float ry = 0.3 * float(y);
            float rz = sqrt(1.0 - rx * rx - ry * ry);
           
            highp vec3 screenCoord = vec3(float(x) * px.x, float(y) * px.y, 0.0);
            // 0.25 times smaller when farest, 5.0 times bigger when nearest.
            highp vec2 coord = tx + (5.0 - 4.75 * depth) * screenCoord.xy;
            // fetch depth from texture
            screenCoord.z = DecodeDepth(texture2D(sEmissiveMap, coord).rgb);
            // move to origin
            screenCoord.z -= depth;

            // ignore occluders which are too far away
            if (screenCoord.z < -zRange) continue;

            // Transform to normal-oriented hemisphere space
            highp vec3 localCoord = InverseNormalMatrix * screenCoord;
            // ralative depth in the world space radius
            float dr = localCoord.z / zRange;
            // calculate contribution
            float v = clamp(rz + dr * aoStrength, 0.0, 2.0 * rz);

            maxi += rz;
            hemi += v;
        }
    }

    float ao = clamp(hemi / maxi, 0.0, 1.0);

    gl_FragColor = vec4(texture2D(sDiffMap, vScreenPos).rgb * ao, 1.0);
}

#endif
Last edited by artgolf1000 on 10 Nov 2016, 08:00, edited 10 times in total.
User avatar
artgolf1000
Have some posts
Have some posts
 
Posts: 38
Joined: 31 Aug 2016, 08:49

Re: SSAO Shader

PostPosted by sabotage3d » 08 Nov 2016, 16:16

Nice! Some screens?
User avatar
sabotage3d
Have many posts
Have many posts
 
Posts: 515
Joined: 25 Oct 2014, 13:26

Re: SSAO Shader

PostPosted by dragonCASTjosh » 09 Nov 2016, 02:51

Any plan for a hlsl version
User avatar
dragonCASTjosh
Moderator
Moderator
 
Posts: 205
Joined: 04 Aug 2015, 18:59

Re: SSAO Post Process

PostPosted by artgolf1000 » 10 Nov 2016, 07:21

SSAO:
Image
Original:
Image
Original+SSAO:
Image
User avatar
artgolf1000
Have some posts
Have some posts
 
Posts: 38
Joined: 31 Aug 2016, 08:49

Re: SSAO Post Process

PostPosted by rasteron » 11 Nov 2016, 07:16

Nice work but quickly checking the original+ssao results, I don't see any much difference. Maybe do a side by side comparison? ;)
User avatar
rasteron
Have many posts
Have many posts
 
Posts: 437
Joined: 07 Mar 2014, 07:46
Location: web


Return to Code Exchange

Who is online

Users browsing this forum: No registered users and 0 guests

cron