Advertisement
Guest User

GTAO shader

a guest
Aug 11th, 2018
3,272
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #version 330
  2. layout(location = 0) out vec4 fragcolor;
  3.  
  4. // Ground truth-based ambient occlusion
  5. // Implementation based on:
  6. // Practical Realtime Strategies for Accurate Indirect Occlusion, Siggraph 2016
  7. // Jorge Jimenez, Xianchun Wu, Angelo Pesce, Adrian Jarabo
  8.  
  9. // Implementation by /u/Kvaleya
  10. // 2018-08-11
  11.  
  12. #include sharedUniformsBuffer.glsl
  13. /*
  14.     The only varibale needed from sharedUniformsBuffer is:
  15.     vec2 viewsizediv = vec2(1.0 / sreenWidth, 1.0 / screenHeight)
  16. */
  17.  
  18. #define PI 3.1415926535897932384626433832795
  19. #define PI_HALF 1.5707963267948966192313216916398
  20.  
  21. // [Eberly2014] GPGPU Programming for Games and Science
  22. float GTAOFastAcos(float x)
  23. {
  24.     float res = -0.156583 * abs(x) + PI_HALF;
  25.     res *= sqrt(1.0 - abs(x));
  26.     return x >= 0 ? res : PI - res;
  27. }
  28.  
  29. float IntegrateArc(float h1, float h2, float n)
  30. {
  31.     float cosN = cos(n);
  32.     float sinN = sin(n);
  33.     return 0.25 * (-cos(2.0 * h1 - n) + cosN + 2.0 * h1 * sinN - cos(2.0 * h2 - n) + cosN + 2.0 * h2 * sinN);
  34. }
  35.  
  36. // Depth buffer
  37. uniform sampler2D gDepth;
  38.  
  39. // Used to get vector from camera to pixel
  40. uniform float aspect;
  41. // These are offsets that change every frame, results are accumulated using temporal filtering in a separate shader
  42. uniform float angleOffset;
  43. uniform float spacialOffset;
  44.  
  45. // The normalized coordinates of the current pixel, range 0.0 .. 1.0
  46. in vec2 vTexCoord;
  47.  
  48. vec3 Visualize_0_3(float x)
  49. {
  50.     const vec3 color0 = vec3(1.0, 0.0, 0.0);
  51.     const vec3 color1 = vec3(1.0, 1.0, 0.0);
  52.     const vec3 color2 = vec3(0.0, 1.0, 0.0);
  53.     const vec3 color3 = vec3(0.0, 1.0, 1.0);
  54.     vec3 color = mix(color0, color1, clamp(x - 0.0, 0.0, 1.0));
  55.     color = mix(color, color2, clamp(x - 1.0, 0.0, 1.0));
  56.     color = mix(color, color3, clamp(x - 2.0, 0.0, 1.0));
  57.     return color;
  58. }
  59.  
  60. vec3 GetCameraVec(vec2 uv)
  61. {  
  62.     // Returns the vector from camera to the specified position on the camera plane (uv argument), located one unit away from the camera
  63.     // This vector is not normalized.
  64.     // The nice thing about this setup is that the returned vector from this function can be simply multiplied with the linear depth to get pixel's position relative to camera position.
  65.     // This particular function does not account for camera rotation or position or FOV at all (since we don't need it for AO)
  66.     // TODO: AO is dependent on FOV, this function is not!
  67.     // The outcome of using this simplified function is that the effective AO range is larger when using larger FOV
  68.     // Use something more accurate to get proper FOV-independent world-space range, however you will likely also have to adjust the SSAO constants below
  69.     return vec3(uv.x * -2.0 + 1.0, uv.y * 2.0 * aspect - aspect, 1.0);
  70. }
  71.  
  72. #define SSAO_LIMIT 100
  73. #define SSAO_SAMPLES 4
  74. #define SSAO_RADIUS 2.5
  75. #define SSAO_FALLOFF 1.5
  76. #define SSAO_THICKNESSMIX 0.2
  77. #define SSAO_MAX_STRIDE 32
  78.  
  79. void SliceSample(vec2 tc_base, vec2 aoDir, int i, float targetMip, vec3 ray, vec3 v, inout float closest)
  80. {
  81.     vec2 uv = tc_base + aoDir * i;
  82.     float depth = textureLod(gDepth, uv, targetMip).x;
  83.     // Vector from current pixel to current slice sample
  84.     vec3 p = GetCameraVec(uv) * depth - ray;
  85.     // Cosine of the horizon angle of the current sample
  86.     float current = dot(v, normalize(p));
  87.     // Linear falloff for samples that are too far away from current pixel
  88.     float falloff = clamp((SSAO_RADIUS - length(p)) / SSAO_FALLOFF, 0.0, 1.0);
  89.     if(current > closest)
  90.         closest = mix(closest, current, falloff);
  91.     // Helps avoid overdarkening from thin objects
  92.     closest = mix(closest, current, SSAO_THICKNESSMIX * falloff);
  93. }
  94.  
  95. void main()
  96. {  
  97.     vec2 tc_original = vTexCoord;
  98.    
  99.     // Depth of the current pixel
  100.     float dhere = textureLod(gDepth, tc_original, 0.0).x;
  101.     // Vector from camera to the current pixel's position
  102.     vec3 ray = GetCameraVec(tc_original) * dhere;
  103.    
  104.     const float normalSampleDist = 1.0;
  105.    
  106.     // Calculate normal from the 4 neighbourhood pixels
  107.     vec2 uv = tc_original + vec2(viewsizediv.x * normalSampleDist, 0.0);
  108.     vec3 p1 = ray - GetCameraVec(uv) * textureLod(gDepth, uv, 0.0).x;
  109.    
  110.     uv = tc_original + vec2(0.0, viewsizediv.y * normalSampleDist);
  111.     vec3 p2 = ray - GetCameraVec(uv) * textureLod(gDepth, uv, 0.0).x;
  112.    
  113.     uv = tc_original + vec2(-viewsizediv.x * normalSampleDist, 0.0);
  114.     vec3 p3 = ray - GetCameraVec(uv) * textureLod(gDepth, uv, 0.0).x;
  115.    
  116.     uv = tc_original + vec2(0.0, -viewsizediv.y * normalSampleDist);
  117.     vec3 p4 = ray - GetCameraVec(uv) * textureLod(gDepth, uv, 0.0).x;
  118.    
  119.     vec3 normal1 = normalize(cross(p1, p2));
  120.     vec3 normal2 = normalize(cross(p3, p4));
  121.    
  122.     vec3 normal = normalize(normal1 + normal2);
  123.    
  124.     // Calculate the distance between samples (direction vector scale) so that the world space AO radius remains constant but also clamp to avoid cache trashing
  125.     // viewsizediv = vec2(1.0 / sreenWidth, 1.0 / screenHeight)
  126.     float stride = min((1.0 / length(ray)) * SSAO_LIMIT, SSAO_MAX_STRIDE);
  127.     vec2 dirMult = viewsizediv.xy * stride;
  128.     // Get the view vector (normalized vector from pixel to camera)
  129.     vec3 v = normalize(-ray);
  130.    
  131.     // Calculate slice direction from pixel's position
  132.     float dirAngle = (PI / 16.0) * (((int(gl_FragCoord.x) + int(gl_FragCoord.y) & 3) << 2) + (int(gl_FragCoord.x) & 3)) + angleOffset;
  133.     vec2 aoDir = dirMult * vec2(sin(dirAngle), cos(dirAngle));
  134.    
  135.     // Project world space normal to the slice plane
  136.     vec3 toDir = GetCameraVec(tc_original + aoDir);
  137.     vec3 planeNormal = normalize(cross(v, -toDir));
  138.     vec3 projectedNormal = normal - planeNormal * dot(normal, planeNormal);
  139.    
  140.     // Calculate angle n between view vector and projected normal vector
  141.     vec3 projectedDir = normalize(normalize(toDir) + v);
  142.     float n = GTAOFastAcos(dot(-projectedDir, normalize(projectedNormal))) - PI_HALF;
  143.    
  144.     // Init variables
  145.     float c1 = -1.0;
  146.     float c2 = -1.0;
  147.    
  148.     vec2 tc_base = tc_original + aoDir * (0.25 * ((int(gl_FragCoord.y) - int(gl_FragCoord.x)) & 3) - 0.375 + spacialOffset);
  149.    
  150.     const float minMip = 0.0;
  151.     const float maxMip = 3.0;
  152.     const float mipScale = 1.0 / 12.0;
  153.    
  154.     float targetMip = floor(clamp(pow(stride, 1.3) * mipScale, minMip, maxMip));
  155.    
  156.     // Find horizons of the slice
  157.     for(int i = -1; i >= -SSAO_SAMPLES; i--)
  158.     {
  159.         SliceSample(tc_base, aoDir, i, targetMip, ray, v, c1);
  160.     }
  161.     for(int i = 1; i <= SSAO_SAMPLES; i++)
  162.     {
  163.         SliceSample(tc_base, aoDir, i, targetMip, ray, v, c2);
  164.     }
  165.    
  166.     // Finalize
  167.     float h1a = -GTAOFastAcos(c1);
  168.     float h2a = GTAOFastAcos(c2);
  169.    
  170.     // Clamp horizons to the normal hemisphere
  171.     float h1 = n + max(h1a - n, -PI_HALF);
  172.     float h2 = n + min(h2a - n, PI_HALF);
  173.    
  174.     float visibility = mix(1.0, IntegrateArc(h1, h2, n), length(projectedNormal));
  175.    
  176.     fragcolor = vec4(visibility);
  177. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement