SSAO.glsl.js 5.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. All material copyright ESRI, All Rights Reserved, unless otherwise specified.
  3. See https://js.arcgis.com/4.25/esri/copyright.txt for details.
  4. */
  5. import{unwrap as e}from"../core/maybe.js";import{s as r}from"./vec2.js";import{a as o}from"./vec2f64.js";import{ScreenSpacePass as t}from"../views/3d/webgl-engine/core/shaderLibrary/ScreenSpacePass.js";import{ReadLinearDepth as a}from"../views/3d/webgl-engine/core/shaderLibrary/output/ReadLinearDepth.glsl.js";import{CameraSpace as n,getZScale as i}from"../views/3d/webgl-engine/core/shaderLibrary/util/CameraSpace.glsl.js";import{Float2PassUniform as s}from"../views/3d/webgl-engine/core/shaderModules/Float2PassUniform.js";import{FloatPassUniform as c}from"../views/3d/webgl-engine/core/shaderModules/FloatPassUniform.js";import{glsl as l}from"../views/3d/webgl-engine/core/shaderModules/interfaces.js";import{ShaderBuilder as u}from"../views/3d/webgl-engine/core/shaderModules/ShaderBuilder.js";import{Texture2DPassUniform as f}from"../views/3d/webgl-engine/core/shaderModules/Texture2DPassUniform.js";const m=16,p=.5;function d(){const o=new u,d=o.fragment;return o.include(t),d.include(a),o.include(n),d.uniforms.add(new c("radius",((e,r)=>v(r)))),d.code.add(l`vec3 sphere[16];
  6. void fillSphere() {
  7. sphere[0] = vec3(0.186937, 0.0, 0.0);
  8. sphere[1] = vec3(0.700542, 0.0, 0.0);
  9. sphere[2] = vec3(-0.864858, -0.481795, -0.111713);
  10. sphere[3] = vec3(-0.624773, 0.102853, -0.730153);
  11. sphere[4] = vec3(-0.387172, 0.260319, 0.007229);
  12. sphere[5] = vec3(-0.222367, -0.642631, -0.707697);
  13. sphere[6] = vec3(-0.01336, -0.014956, 0.169662);
  14. sphere[7] = vec3(0.122575, 0.1544, -0.456944);
  15. sphere[8] = vec3(-0.177141, 0.85997, -0.42346);
  16. sphere[9] = vec3(-0.131631, 0.814545, 0.524355);
  17. sphere[10] = vec3(-0.779469, 0.007991, 0.624833);
  18. sphere[11] = vec3(0.308092, 0.209288,0.35969);
  19. sphere[12] = vec3(0.359331, -0.184533, -0.377458);
  20. sphere[13] = vec3(0.192633, -0.482999, -0.065284);
  21. sphere[14] = vec3(0.233538, 0.293706, -0.055139);
  22. sphere[15] = vec3(0.417709, -0.386701, 0.442449);
  23. }
  24. float fallOffFunction(float vv, float vn, float bias) {
  25. float f = max(radius * radius - vv, 0.0);
  26. return f * f * f * max(vn-bias, 0.0);
  27. }`),d.code.add(l`float aoValueFromPositionsAndNormal(vec3 C, vec3 n_C, vec3 Q) {
  28. vec3 v = Q - C;
  29. float vv = dot(v, v);
  30. float vn = dot(normalize(v), n_C);
  31. return fallOffFunction(vv, vn, 0.1);
  32. }`),d.uniforms.add([new s("nearFar",((e,r)=>r.camera.nearFar)),new f("normalMap",(e=>e.normalTexture)),new f("depthMap",(e=>e.depthTexture)),new s("zScale",((e,r)=>i(r))),new c("projScale",(e=>e.projScale)),new f("rnm",(e=>e.noiseTexture)),new s("rnmScale",((o,t)=>r(h,t.camera.fullWidth/e(o.noiseTexture).descriptor.width,t.camera.fullHeight/e(o.noiseTexture).descriptor.height))),new c("intensity",((e,r)=>4*p/v(r)**6)),new s("screenSize",((e,o)=>r(h,o.camera.fullWidth,o.camera.fullHeight)))]),d.code.add(l`
  33. void main(void) {
  34. fillSphere();
  35. vec3 fres = normalize((texture2D(rnm, uv * rnmScale).xyz * 2.0) - vec3(1.0));
  36. float currentPixelDepth = linearDepthFromTexture(depthMap, uv, nearFar);
  37. if (-currentPixelDepth>nearFar.y || -currentPixelDepth<nearFar.x) {
  38. gl_FragColor = vec4(0.0);
  39. return;
  40. }
  41. vec3 currentPixelPos = reconstructPosition(gl_FragCoord.xy,currentPixelDepth);
  42. // get the normal of current fragment
  43. vec4 norm4 = texture2D(normalMap, uv);
  44. vec3 norm = vec3(-1.0) + 2.0 * norm4.xyz;
  45. bool isTerrain = norm4.w<0.5;
  46. float sum = .0;
  47. vec3 tapPixelPos;
  48. // note: the factor 2.0 should not be necessary, but makes ssao much nicer.
  49. // bug or deviation from CE somewhere else?
  50. float ps = projScale / (2.0 * currentPixelPos.z * zScale.x + zScale.y);
  51. for(int i = 0; i < ${l.int(m)}; ++i) {
  52. vec2 unitOffset = reflect(sphere[i], fres).xy;
  53. vec2 offset = vec2(-unitOffset * radius * ps);
  54. //don't use current or very nearby samples
  55. if ( abs(offset.x)<2.0 || abs(offset.y)<2.0) continue;
  56. vec2 tc = vec2(gl_FragCoord.xy + offset);
  57. if (tc.x < 0.0 || tc.y < 0.0 || tc.x > screenSize.x || tc.y > screenSize.y) continue;
  58. vec2 tcTap = tc / screenSize;
  59. float occluderFragmentDepth = linearDepthFromTexture(depthMap, tcTap, nearFar);
  60. if (isTerrain) {
  61. bool isTerrainTap = texture2D(normalMap, tcTap).w<0.5;
  62. if (isTerrainTap) {
  63. continue;
  64. }
  65. }
  66. tapPixelPos = reconstructPosition(tc, occluderFragmentDepth);
  67. sum+= aoValueFromPositionsAndNormal(currentPixelPos, norm, tapPixelPos);
  68. }
  69. // output the result
  70. float A = max(1.0 - sum * intensity / float(${l.int(m)}),0.0);
  71. // Anti-tone map to reduce contrast and drag dark region farther: (x^0.2 + 1.2 * x^4)/2.2
  72. A = (pow(A, 0.2) + 1.2 * A*A*A*A) / 2.2;
  73. gl_FragColor = vec4(A);
  74. }
  75. `),o}function v(e){return Math.max(10,20*e.camera.computeRenderPixelSizeAtDist(Math.abs(4*e.camera.relativeElevation)))}const h=o(),x=Object.freeze(Object.defineProperty({__proto__:null,build:d},Symbol.toStringTag,{value:"Module"}));export{x as S,d as b};