Created
September 30, 2013 21:12
-
-
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…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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