SSAOShader.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. *
  4. * Screen-space ambient occlusion shader
  5. * - ported from
  6. * SSAO GLSL shader v1.2
  7. * assembled by Martins Upitis (martinsh) (http://devlog-martinsh.blogspot.com)
  8. * original technique is made by ArKano22 (http://www.gamedev.net/topic/550699-ssao-no-halo-artifacts/)
  9. * - modifications
  10. * - modified to use RGBA packed depth texture (use clear color 1,1,1,1 for depth pass)
  11. * - made fog more compatible with three.js linear fog
  12. * - refactoring and optimizations
  13. */
  14. THREE.SSAOShader = {
  15. uniforms: {
  16. "tDiffuse": { type: "t", value: null },
  17. "tDepth": { type: "t", value: null },
  18. "size": { type: "v2", value: new THREE.Vector2( 512, 512 ) },
  19. "cameraNear": { type: "f", value: 1 },
  20. "cameraFar": { type: "f", value: 100 },
  21. "fogNear": { type: "f", value: 5 },
  22. "fogFar": { type: "f", value: 100 },
  23. "fogEnabled": { type: "i", value: 0 },
  24. "onlyAO": { type: "i", value: 0 },
  25. "aoClamp": { type: "f", value: 0.3 },
  26. "lumInfluence": { type: "f", value: 0.9 }
  27. },
  28. vertexShader: [
  29. "varying vec2 vUv;",
  30. "void main() {",
  31. "vUv = uv;",
  32. "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
  33. "}"
  34. ].join("\n"),
  35. fragmentShader: [
  36. "uniform float cameraNear;",
  37. "uniform float cameraFar;",
  38. "uniform float fogNear;",
  39. "uniform float fogFar;",
  40. "uniform bool fogEnabled;", // attenuate AO with linear fog
  41. "uniform bool onlyAO;", // use only ambient occlusion pass?
  42. "uniform vec2 size;", // texture width, height
  43. "uniform float aoClamp;", // depth clamp - reduces haloing at screen edges
  44. "uniform float lumInfluence;", // how much luminance affects occlusion
  45. "uniform sampler2D tDiffuse;",
  46. "uniform sampler2D tDepth;",
  47. "varying vec2 vUv;",
  48. // "#define PI 3.14159265",
  49. "#define DL 2.399963229728653", // PI * ( 3.0 - sqrt( 5.0 ) )
  50. "#define EULER 2.718281828459045",
  51. // helpers
  52. "float width = size.x;", // texture width
  53. "float height = size.y;", // texture height
  54. "float cameraFarPlusNear = cameraFar + cameraNear;",
  55. "float cameraFarMinusNear = cameraFar - cameraNear;",
  56. "float cameraCoef = 2.0 * cameraNear;",
  57. // user variables
  58. "const int samples = 8;", // ao sample count
  59. "const float radius = 5.0;", // ao radius
  60. "const bool useNoise = false;", // use noise instead of pattern for sample dithering
  61. "const float noiseAmount = 0.0003;", // dithering amount
  62. "const float diffArea = 0.4;", // self-shadowing reduction
  63. "const float gDisplace = 0.4;", // gauss bell center
  64. "const vec3 onlyAOColor = vec3( 1.0, 0.7, 0.5 );",
  65. // "const vec3 onlyAOColor = vec3( 1.0, 1.0, 1.0 );",
  66. // RGBA depth
  67. "float unpackDepth( const in vec4 rgba_depth ) {",
  68. "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );",
  69. "float depth = dot( rgba_depth, bit_shift );",
  70. "return depth;",
  71. "}",
  72. // generating noise / pattern texture for dithering
  73. "vec2 rand( const vec2 coord ) {",
  74. "vec2 noise;",
  75. "if ( useNoise ) {",
  76. "float nx = dot ( coord, vec2( 12.9898, 78.233 ) );",
  77. "float ny = dot ( coord, vec2( 12.9898, 78.233 ) * 2.0 );",
  78. "noise = clamp( fract ( 43758.5453 * sin( vec2( nx, ny ) ) ), 0.0, 1.0 );",
  79. "} else {",
  80. "float ff = fract( 1.0 - coord.s * ( width / 2.0 ) );",
  81. "float gg = fract( coord.t * ( height / 2.0 ) );",
  82. "noise = vec2( 0.25, 0.75 ) * vec2( ff ) + vec2( 0.75, 0.25 ) * gg;",
  83. "}",
  84. "return ( noise * 2.0 - 1.0 ) * noiseAmount;",
  85. "}",
  86. "float doFog() {",
  87. "float zdepth = unpackDepth( texture2D( tDepth, vUv ) );",
  88. "float depth = -cameraFar * cameraNear / ( zdepth * cameraFarMinusNear - cameraFar );",
  89. "return smoothstep( fogNear, fogFar, depth );",
  90. "}",
  91. "float readDepth( const in vec2 coord ) {",
  92. // "return ( 2.0 * cameraNear ) / ( cameraFar + cameraNear - unpackDepth( texture2D( tDepth, coord ) ) * ( cameraFar - cameraNear ) );",
  93. "return cameraCoef / ( cameraFarPlusNear - unpackDepth( texture2D( tDepth, coord ) ) * cameraFarMinusNear );",
  94. "}",
  95. "float compareDepths( const in float depth1, const in float depth2, inout int far ) {",
  96. "float garea = 2.0;", // gauss bell width
  97. "float diff = ( depth1 - depth2 ) * 100.0;", // depth difference (0-100)
  98. // reduce left bell width to avoid self-shadowing
  99. "if ( diff < gDisplace ) {",
  100. "garea = diffArea;",
  101. "} else {",
  102. "far = 1;",
  103. "}",
  104. "float dd = diff - gDisplace;",
  105. "float gauss = pow( EULER, -2.0 * dd * dd / ( garea * garea ) );",
  106. "return gauss;",
  107. "}",
  108. "float calcAO( float depth, float dw, float dh ) {",
  109. "float dd = radius - depth * radius;",
  110. "vec2 vv = vec2( dw, dh );",
  111. "vec2 coord1 = vUv + dd * vv;",
  112. "vec2 coord2 = vUv - dd * vv;",
  113. "float temp1 = 0.0;",
  114. "float temp2 = 0.0;",
  115. "int far = 0;",
  116. "temp1 = compareDepths( depth, readDepth( coord1 ), far );",
  117. // DEPTH EXTRAPOLATION
  118. "if ( far > 0 ) {",
  119. "temp2 = compareDepths( readDepth( coord2 ), depth, far );",
  120. "temp1 += ( 1.0 - temp1 ) * temp2;",
  121. "}",
  122. "return temp1;",
  123. "}",
  124. "void main() {",
  125. "vec2 noise = rand( vUv );",
  126. "float depth = readDepth( vUv );",
  127. "float tt = clamp( depth, aoClamp, 1.0 );",
  128. "float w = ( 1.0 / width ) / tt + ( noise.x * ( 1.0 - noise.x ) );",
  129. "float h = ( 1.0 / height ) / tt + ( noise.y * ( 1.0 - noise.y ) );",
  130. "float pw;",
  131. "float ph;",
  132. "float ao;",
  133. "float dz = 1.0 / float( samples );",
  134. "float z = 1.0 - dz / 2.0;",
  135. "float l = 0.0;",
  136. "for ( int i = 0; i <= samples; i ++ ) {",
  137. "float r = sqrt( 1.0 - z );",
  138. "pw = cos( l ) * r;",
  139. "ph = sin( l ) * r;",
  140. "ao += calcAO( depth, pw * w, ph * h );",
  141. "z = z - dz;",
  142. "l = l + DL;",
  143. "}",
  144. "ao /= float( samples );",
  145. "ao = 1.0 - ao;",
  146. "if ( fogEnabled ) {",
  147. "ao = mix( ao, 1.0, doFog() );",
  148. "}",
  149. "vec3 color = texture2D( tDiffuse, vUv ).rgb;",
  150. "vec3 lumcoeff = vec3( 0.299, 0.587, 0.114 );",
  151. "float lum = dot( color.rgb, lumcoeff );",
  152. "vec3 luminance = vec3( lum );",
  153. "vec3 final = vec3( color * mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // mix( color * ao, white, luminance )
  154. "if ( onlyAO ) {",
  155. "final = onlyAOColor * vec3( mix( vec3( ao ), vec3( 1.0 ), luminance * lumInfluence ) );", // ambient occlusion only
  156. "}",
  157. "gl_FragColor = vec4( final, 1.0 );",
  158. "}"
  159. ].join("\n")
  160. };