UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

116 lines (113 loc) 4.52 kB
var glslSsaoPS = ` #include "screenDepthPS" varying vec2 uv0; uniform vec2 uInvResolution; uniform float uAspect; #define saturate(x) clamp(x,0.0,1.0) highp float getWFromProjectionMatrix(const mat4 p, const vec3 v) { return -v.z; } highp float getViewSpaceZFromW(const mat4 p, const float w) { return -w; } const float kLog2LodRate = 3.0; float random(const highp vec2 w) { const vec3 m = vec3(0.06711056, 0.00583715, 52.9829189); return fract(m.z * fract(dot(w, m.xy))); } highp vec2 getFragCoord() { return gl_FragCoord.xy; } highp vec3 computeViewSpacePositionFromDepth(highp vec2 uv, highp float linearDepth) { return vec3((0.5 - uv) * vec2(uAspect, 1.0) * linearDepth, linearDepth); } highp vec3 faceNormal(highp vec3 dpdx, highp vec3 dpdy) { return normalize(cross(dpdx, dpdy)); } highp vec3 computeViewSpaceNormal(const highp vec3 position) { return faceNormal(dFdx(position), dFdy(position)); } highp vec3 computeViewSpaceNormal(const highp vec3 position, const highp vec2 uv) { highp vec2 uvdx = uv + vec2(uInvResolution.x, 0.0); highp vec2 uvdy = uv + vec2(0.0, uInvResolution.y); highp vec3 px = computeViewSpacePositionFromDepth(uvdx, -getLinearScreenDepth(uvdx)); highp vec3 py = computeViewSpacePositionFromDepth(uvdy, -getLinearScreenDepth(uvdy)); highp vec3 dpdx = px - position; highp vec3 dpdy = py - position; return faceNormal(dpdx, dpdy); } uniform vec2 uSampleCount; uniform float uSpiralTurns; #define PI (3.14159) mediump vec3 tapLocation(mediump float i, const mediump float noise) { mediump float offset = ((2.0 * PI) * 2.4) * noise; mediump float angle = ((i * uSampleCount.y) * uSpiralTurns) * (2.0 * PI) + offset; mediump float radius = (i + noise + 0.5) * uSampleCount.y; return vec3(cos(angle), sin(angle), radius * radius); } highp vec2 startPosition(const float noise) { float angle = ((2.0 * PI) * 2.4) * noise; return vec2(cos(angle), sin(angle)); } uniform vec2 uAngleIncCosSin; highp mat2 tapAngleStep() { highp vec2 t = uAngleIncCosSin; return mat2(t.x, t.y, -t.y, t.x); } mediump vec3 tapLocationFast(mediump float i, mediump vec2 p, const mediump float noise) { mediump float radius = (i + noise + 0.5) * uSampleCount.y; return vec3(p, radius * radius); } uniform float uMaxLevel; uniform float uInvRadiusSquared; uniform float uMinHorizonAngleSineSquared; uniform float uBias; uniform float uPeak2; void computeAmbientOcclusionSAO(inout mediump float occlusion, mediump float i, mediump float ssDiskRadius, const highp vec2 uv, const highp vec3 origin, const mediump vec3 normal, const mediump vec2 tapPosition, const float noise) { mediump vec3 tap = tapLocationFast(i, tapPosition, noise); mediump float ssRadius = max(1.0, tap.z * ssDiskRadius); mediump vec2 uvSamplePos = uv + vec2(ssRadius * tap.xy) * uInvResolution; mediump float level = clamp(floor(log2(ssRadius)) - kLog2LodRate, 0.0, float(uMaxLevel)); highp float occlusionDepth = -getLinearScreenDepth(uvSamplePos); highp vec3 p = computeViewSpacePositionFromDepth(uvSamplePos, occlusionDepth); vec3 v = p - origin; float vv = dot(v, v); float vn = dot(v, normal); mediump float w = max(0.0, 1.0 - vv * uInvRadiusSquared); w = w * w; w *= step(vv * uMinHorizonAngleSineSquared, vn * vn); occlusion += w * max(0.0, vn + origin.z * uBias) / (vv + uPeak2); } uniform float uProjectionScaleRadius; uniform float uIntensity; uniform float uRandomize; float scalableAmbientObscurance(highp vec2 uv, highp vec3 origin, vec3 normal) { float noise = random(getFragCoord()) + uRandomize; highp vec2 tapPosition = startPosition(noise); highp mat2 angleStep = tapAngleStep(); float ssDiskRadius = -(uProjectionScaleRadius / origin.z); float occlusion = 0.0; for (float i = 0.0; i < uSampleCount.x; i += 1.0) { computeAmbientOcclusionSAO(occlusion, i, ssDiskRadius, uv, origin, normal, tapPosition, noise); tapPosition = angleStep * tapPosition; } return occlusion; } uniform float uPower; void main() { highp vec2 uv = uv0; highp float depth = -getLinearScreenDepth(uv0); highp vec3 origin = computeViewSpacePositionFromDepth(uv, depth); vec3 normal = computeViewSpaceNormal(origin, uv); float occlusion = 0.0; if (uIntensity > 0.0) { occlusion = scalableAmbientObscurance(uv, origin, normal); } float ao = max(0.0, 1.0 - occlusion * uIntensity); ao = pow(ao, uPower); gl_FragColor = vec4(ao, ao, ao, 1.0); } `; export { glslSsaoPS as default };