SSAOShader.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /**
  2. * References:
  3. * http://john-chapman-graphics.blogspot.com/2013/01/ssao-tutorial.html
  4. * https://learnopengl.com/Advanced-Lighting/SSAO
  5. * https://github.com/McNopper/OpenGL/blob/master/Example28/shader/ssao.frag.glsl
  6. */
  7. THREE.SSAOShader = {
  8. defines: {
  9. 'PERSPECTIVE_CAMERA': 1,
  10. 'KERNEL_SIZE': 32
  11. },
  12. uniforms: {
  13. 'tDiffuse': { value: null },
  14. 'tNormal': { value: null },
  15. 'tDepth': { value: null },
  16. 'tNoise': { value: null },
  17. 'kernel': { value: null },
  18. 'cameraNear': { value: null },
  19. 'cameraFar': { value: null },
  20. 'resolution': { value: new THREE.Vector2() },
  21. 'cameraProjectionMatrix': { value: new THREE.Matrix4() },
  22. 'cameraInverseProjectionMatrix': { value: new THREE.Matrix4() },
  23. 'kernelRadius': { value: 8 },
  24. 'minDistance': { value: 0.005 },
  25. 'maxDistance': { value: 0.05 },
  26. },
  27. vertexShader: [
  28. 'varying vec2 vUv;',
  29. 'void main() {',
  30. ' vUv = uv;',
  31. ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
  32. '}'
  33. ].join( '\n' ),
  34. fragmentShader: [
  35. 'uniform sampler2D tDiffuse;',
  36. 'uniform sampler2D tNormal;',
  37. 'uniform sampler2D tDepth;',
  38. 'uniform sampler2D tNoise;',
  39. 'uniform vec3 kernel[ KERNEL_SIZE ];',
  40. 'uniform vec2 resolution;',
  41. 'uniform float cameraNear;',
  42. 'uniform float cameraFar;',
  43. 'uniform mat4 cameraProjectionMatrix;',
  44. 'uniform mat4 cameraInverseProjectionMatrix;',
  45. 'uniform float kernelRadius;',
  46. 'uniform float minDistance;', // avoid artifacts caused by neighbour fragments with minimal depth difference
  47. 'uniform float maxDistance;', // avoid the influence of fragments which are too far away
  48. 'varying vec2 vUv;',
  49. '#include <packing>',
  50. 'float getDepth( const in vec2 screenPosition ) {',
  51. ' return texture2D( tDepth, screenPosition ).x;',
  52. '}',
  53. 'float getLinearDepth( const in vec2 screenPosition ) {',
  54. ' #if PERSPECTIVE_CAMERA == 1',
  55. ' float fragCoordZ = texture2D( tDepth, screenPosition ).x;',
  56. ' float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );',
  57. ' return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );',
  58. ' #else',
  59. ' return texture2D( tDepth, screenPosition ).x;',
  60. ' #endif',
  61. '}',
  62. 'float getViewZ( const in float depth ) {',
  63. ' #if PERSPECTIVE_CAMERA == 1',
  64. ' return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );',
  65. ' #else',
  66. ' return orthographicDepthToViewZ( depth, cameraNear, cameraFar );',
  67. ' #endif',
  68. '}',
  69. 'vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) {',
  70. ' float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3];',
  71. ' vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 );',
  72. ' clipPosition *= clipW; // unprojection.',
  73. ' return ( cameraInverseProjectionMatrix * clipPosition ).xyz;',
  74. '}',
  75. 'vec3 getViewNormal( const in vec2 screenPosition ) {',
  76. ' return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );',
  77. '}',
  78. 'void main() {',
  79. ' float depth = getDepth( vUv );',
  80. ' float viewZ = getViewZ( depth );',
  81. ' vec3 viewPosition = getViewPosition( vUv, depth, viewZ );',
  82. ' vec3 viewNormal = getViewNormal( vUv );',
  83. ' vec2 noiseScale = vec2( resolution.x / 4.0, resolution.y / 4.0 );',
  84. ' vec3 random = texture2D( tNoise, vUv * noiseScale ).xyz;',
  85. // compute matrix used to reorient a kernel vector
  86. ' vec3 tangent = normalize( random - viewNormal * dot( random, viewNormal ) );',
  87. ' vec3 bitangent = cross( viewNormal, tangent );',
  88. ' mat3 kernelMatrix = mat3( tangent, bitangent, viewNormal );',
  89. ' float occlusion = 0.0;',
  90. ' for ( int i = 0; i < KERNEL_SIZE; i ++ ) {',
  91. ' vec3 sampleVector = kernelMatrix * kernel[ i ];', // reorient sample vector in view space
  92. ' vec3 samplePoint = viewPosition + ( sampleVector * kernelRadius );', // calculate sample point
  93. ' vec4 samplePointNDC = cameraProjectionMatrix * vec4( samplePoint, 1.0 );', // project point and calculate NDC
  94. ' samplePointNDC /= samplePointNDC.w;',
  95. ' vec2 samplePointUv = samplePointNDC.xy * 0.5 + 0.5;', // compute uv coordinates
  96. ' float realDepth = getLinearDepth( samplePointUv );', // get linear depth from depth texture
  97. ' float sampleDepth = viewZToOrthographicDepth( samplePoint.z, cameraNear, cameraFar );', // compute linear depth of the sample view Z value
  98. ' float delta = sampleDepth - realDepth;',
  99. ' if ( delta > minDistance && delta < maxDistance ) {', // if fragment is before sample point, increase occlusion
  100. ' occlusion += 1.0;',
  101. ' }',
  102. ' }',
  103. ' occlusion = clamp( occlusion / float( KERNEL_SIZE ), 0.0, 1.0 );',
  104. ' gl_FragColor = vec4( vec3( 1.0 - occlusion ), 1.0 );',
  105. '}'
  106. ].join( '\n' )
  107. };
  108. THREE.SSAODepthShader = {
  109. defines: {
  110. 'PERSPECTIVE_CAMERA': 1
  111. },
  112. uniforms: {
  113. 'tDepth': { value: null },
  114. 'cameraNear': { value: null },
  115. 'cameraFar': { value: null },
  116. },
  117. vertexShader: [
  118. 'varying vec2 vUv;',
  119. 'void main() {',
  120. ' vUv = uv;',
  121. ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
  122. '}'
  123. ].join( '\n' ),
  124. fragmentShader: [
  125. 'uniform sampler2D tDepth;',
  126. 'uniform float cameraNear;',
  127. 'uniform float cameraFar;',
  128. 'varying vec2 vUv;',
  129. '#include <packing>',
  130. 'float getLinearDepth( const in vec2 screenPosition ) {',
  131. ' #if PERSPECTIVE_CAMERA == 1',
  132. ' float fragCoordZ = texture2D( tDepth, screenPosition ).x;',
  133. ' float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );',
  134. ' return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );',
  135. ' #else',
  136. ' return texture2D( tDepth, screenPosition ).x;',
  137. ' #endif',
  138. '}',
  139. 'void main() {',
  140. ' float depth = getLinearDepth( vUv );',
  141. ' gl_FragColor = vec4( vec3( 1.0 - depth ), 1.0 );',
  142. '}'
  143. ].join( '\n' )
  144. };
  145. THREE.SSAOBlurShader = {
  146. uniforms: {
  147. 'tDiffuse': { value: null },
  148. 'resolution': { value: new THREE.Vector2() }
  149. },
  150. vertexShader: [
  151. 'varying vec2 vUv;',
  152. 'void main() {',
  153. ' vUv = uv;',
  154. ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
  155. '}'
  156. ].join( '\n' ),
  157. fragmentShader: [
  158. 'uniform sampler2D tDiffuse;',
  159. 'uniform vec2 resolution;',
  160. 'varying vec2 vUv;',
  161. 'void main() {',
  162. ' vec2 texelSize = ( 1.0 / resolution );',
  163. ' float result = 0.0;',
  164. ' for ( int i = - 2; i <= 2; i ++ ) {',
  165. ' for ( int j = - 2; j <= 2; j ++ ) {',
  166. ' vec2 offset = ( vec2( float( i ), float( j ) ) ) * texelSize;',
  167. ' result += texture2D( tDiffuse, vUv + offset ).r;',
  168. ' }',
  169. ' }',
  170. ' gl_FragColor = vec4( vec3( result / ( 5.0 * 5.0 ) ), 1.0 );',
  171. '}'
  172. ].join( '\n' )
  173. };