Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #version 140
- // sao_downscale_and_reconstruct.fs
- #extension GL_ARB_gpu_shader5 : enable
- #include "sao_include.fs"
- out vec3 out_FragColor;
- #define visibility out_FragColor.r
- #define bilateralKey out_FragColor.gb
- ////////////////////////////////////////////////////////////////
- // Tweakable parameters. You can mess with these, to change
- // the look of the effect.
- #define projScale 250.0
- #define radius 0.75
- #define radius2 (radius * radius)
- #define bias 0.01
- #define intensity 0.33
- #define intensityDivR6 0.333333
- #define epsilon 0.001
- //** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */
- vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR)
- {
- // Radius relative to ssR
- float alpha = float(sampleNumber + 0.5) * (1.0 / NUM_SAMPLES);
- float angle = alpha * (NUM_SPIRAL_TURNS * 6.28) + spinAngle;
- ssR = alpha;
- return vec2(cos(angle), sin(angle));
- }
- //** Read the camera-space position of the point at screen-space pixel ssP */
- vec3 getPosition(ivec2 ssP)
- {
- vec3 P;
- P.z = texelFetch(PostSourceTexture, ssP, 0).r;
- // Offset to pixel center
- P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
- return P;
- }
- // Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */
- vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR)
- {
- // Derivation:
- // mipLevel = floor(log(ssR / MAX_OFFSET));
- # ifdef GL_ARB_gpu_shader5
- int mipLevel = clamp(findMSB(int(ssR)) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
- # else
- int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
- # endif
- ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
- vec3 P;
- // We need to divide by 2^mipLevel to read the appropriately scaled coordinate from a MIP-map.
- // Manually clamp to the texture size because texelFetch bypasses the texture unit
- ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), textureSize(PostSourceTexture, mipLevel) - ivec2(1));
- P.z = texelFetch(PostSourceTexture, mipP, mipLevel).r;
- // Offset to pixel center
- P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
- return P;
- }
- //** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds
- // to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
- //
- // Note that units of H() in the HPG12 paper are meters, not
- // unitless. The whole falloff/sampling function is therefore
- // unitless. In this implementation, we factor out (9 / radius).
- //
- // Four versions of the falloff function are implemented below
- //
- float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in int tapIndex, in float randomPatternRotationAngle)
- {
- // Offset on the unit disk, spun for this pixel
- float ssR;
- vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
- ssR *= ssDiskRadius;
- // The occluding point in camera space
- vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
- vec3 v = Q - C;
- float vv = dot(v, v);
- float vn = dot(v, n_C);
- // A: From the HPG12 paper
- // Note large epsilon to avoid overdarkening within cracks
- // return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
- // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
- float f = max(radius2 - vv, 0.0); return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
- // C: Medium contrast (which looks better at high radii), no division. Note that the
- // contribution still falls off with radius^2, but we've adjusted the rate in a way that is
- // more computationally efficient and happens to be aesthetically pleasing.
- // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
- // D: Low contrast, no division operation
- // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
- }
- void main()
- {
- // Pixel being shaded
- ivec2 ssC = ivec2(gl_FragCoord.xy);
- // World space point being shaded
- vec3 C = getPosition(ssC);
- packKey(CSZToKey(C.z), bilateralKey);
- // if (C.z < FAR_PLANE_Z)
- // {
- // // We're on the skybox
- // discard;
- // }
- // Hash function used in the HPG12 AlchemyAO paper
- float randomPatternRotationAngle = (3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10;
- // Reconstruct normals from positions. These will lead to 1-pixel black lines
- // at depth discontinuities, however the blur will wipe those out so they are not visible
- // in the final image.
- vec3 n_C = reconstructCSFaceNormal(C);
- // Choose the screen-space sample radius
- // proportional to the projected area of the sphere
- float ssDiskRadius = -projScale * radius / C.z;
- float sum = 0.0;
- for (int i = 0; i < NUM_SAMPLES; ++i)
- {
- sum += sampleAO(ssC, C, n_C, ssDiskRadius, i, randomPatternRotationAngle);
- }
- float A = max(0.0, 1.0 - sum * intensityDivR6 * (5.0 / NUM_SAMPLES));
- // Bilateral box-filter over a quad for free, respecting depth edges
- // (the difference that this makes is subtle)
- if (abs(dFdx(C.z)) < 0.02)
- {
- A -= dFdx(A) * ((ssC.x & 1) - 0.5);
- }
- if (abs(dFdy(C.z)) < 0.02)
- {
- A -= dFdy(A) * ((ssC.y & 1) - 0.5);
- }
- visibility = A;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement