Skip to content

Instantly share code, notes, and snippets.

@transitive-bullshit
Created September 30, 2013 21:12
Show Gist options
  • Save transitive-bullshit/6770363 to your computer and use it in GitHub Desktop.
Save transitive-bullshit/6770363 to your computer and use it in GitHub Desktop.
WebGL GLSL SSAO (Screen-Space Ambient Occlusion) fragment shader. Converts the g-buffer to an occlusion buffer which estimates local ambient occlusion at each fragment in screen-space. This SSAO version uses per-fragment depth and normal data to integrate local visibility over a normal-oriented hemisphere in world space by comparing the linear d…
#define SAMPLE_COUNT {{ sampleCount }}
#define USE_ACTUAL_NORMALS {{ useActualNormals }}
uniform sampler2D sGBuffer;
uniform sampler2D sNoise;
uniform float uSampleRadius;
uniform float uIntensity;
uniform vec2 uNoiseScale;
uniform vec3 uKernel[SAMPLE_COUNT];
// reconstructs view-space unit normal from view-space position
vec3 reconstructNormalVS(vec3 positionVS) {
return normalize(cross(dFdx(positionVS), dFdy(positionVS)));
}
void main() {
gBufferGeomComponents gBufferValue = decodeGBufferGeom(sGBuffer, varyingTexCoords, clipFar);
vec3 cameraToPositionRay = normalize(varyingCameraFarPlaneWorldSpace - cameraPositionWorldSpace);
vec3 origin = cameraToPositionRay * gBufferValue.depth + cameraPositionWorldSpace;
#if USE_ACTUAL_NORMALS
vec3 normal = gBufferValue.normal;
#else
vec3 originVS = (viewMatrix * vec4(origin, 1.0)).xyz;
vec3 normal = reconstructNormalVS(originVS);
#endif
normal = normalize(normal * normalMatrix);
vec3 rvec = texture2D(sNoise, varyingTexCoords * uNoiseScale).xyz * 2.0 - 1.0;
vec3 tangent = normalize(rvec - normal * dot(rvec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 tbn = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
for (int i = 0; i < SAMPLE_COUNT; ++i) {
vec3 sample = origin + (tbn * uKernel[i]) * uSampleRadius;
vec4 offset = viewProjectionMatrix * vec4(sample, 1.0);
offset.xy = (offset.xy / offset.w) * 0.5 + 0.5;
float depth = length(sample - cameraPositionWorldSpace);
float sampleDepth = decodeGBufferDepth(sGBuffer, offset.xy, clipFar);
float rangeDelta = abs(gBufferValue.depth - sampleDepth);
float rangeCheck = smoothstep(0.0, 1.0, uSampleRadius / rangeDelta);
occlusion += rangeCheck * step(sampleDepth, depth);
}
occlusion = 1.0 - occlusion / float(SAMPLE_COUNT);
occlusion = clamp(pow(occlusion, uIntensity), 0.0, 1.0);
gl_FragColor = vec4(occlusion, occlusion, occlusion, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment