SAOShader.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import {
  2. Matrix4,
  3. Vector2
  4. } from 'three';
  5. /** @module SAOShader */
  6. /**
  7. * SAO shader.
  8. *
  9. * Used by {@link SAOPass}.
  10. *
  11. * @constant
  12. * @type {Object}
  13. */
  14. const SAOShader = {
  15. name: 'SAOShader',
  16. defines: {
  17. 'NUM_SAMPLES': 7,
  18. 'NUM_RINGS': 4,
  19. 'DIFFUSE_TEXTURE': 0,
  20. 'PERSPECTIVE_CAMERA': 1
  21. },
  22. uniforms: {
  23. 'tDepth': { value: null },
  24. 'tDiffuse': { value: null },
  25. 'tNormal': { value: null },
  26. 'size': { value: new Vector2( 512, 512 ) },
  27. 'cameraNear': { value: 1 },
  28. 'cameraFar': { value: 100 },
  29. 'cameraProjectionMatrix': { value: new Matrix4() },
  30. 'cameraInverseProjectionMatrix': { value: new Matrix4() },
  31. 'scale': { value: 1.0 },
  32. 'intensity': { value: 0.1 },
  33. 'bias': { value: 0.5 },
  34. 'minResolution': { value: 0.0 },
  35. 'kernelRadius': { value: 100.0 },
  36. 'randomSeed': { value: 0.0 }
  37. },
  38. vertexShader: /* glsl */`
  39. varying vec2 vUv;
  40. void main() {
  41. vUv = uv;
  42. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  43. }`,
  44. fragmentShader: /* glsl */`
  45. #include <common>
  46. varying vec2 vUv;
  47. #if DIFFUSE_TEXTURE == 1
  48. uniform sampler2D tDiffuse;
  49. #endif
  50. uniform highp sampler2D tDepth;
  51. uniform highp sampler2D tNormal;
  52. uniform float cameraNear;
  53. uniform float cameraFar;
  54. uniform mat4 cameraProjectionMatrix;
  55. uniform mat4 cameraInverseProjectionMatrix;
  56. uniform float scale;
  57. uniform float intensity;
  58. uniform float bias;
  59. uniform float kernelRadius;
  60. uniform float minResolution;
  61. uniform vec2 size;
  62. uniform float randomSeed;
  63. // RGBA depth
  64. #include <packing>
  65. vec4 getDefaultColor( const in vec2 screenPosition ) {
  66. #if DIFFUSE_TEXTURE == 1
  67. return texture2D( tDiffuse, vUv );
  68. #else
  69. return vec4( 1.0 );
  70. #endif
  71. }
  72. float getDepth( const in vec2 screenPosition ) {
  73. return texture2D( tDepth, screenPosition ).x;
  74. }
  75. float getViewZ( const in float depth ) {
  76. #if PERSPECTIVE_CAMERA == 1
  77. return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
  78. #else
  79. return orthographicDepthToViewZ( depth, cameraNear, cameraFar );
  80. #endif
  81. }
  82. vec3 getViewPosition( const in vec2 screenPosition, const in float depth, const in float viewZ ) {
  83. float clipW = cameraProjectionMatrix[2][3] * viewZ + cameraProjectionMatrix[3][3];
  84. vec4 clipPosition = vec4( ( vec3( screenPosition, depth ) - 0.5 ) * 2.0, 1.0 );
  85. clipPosition *= clipW; // unprojection.
  86. return ( cameraInverseProjectionMatrix * clipPosition ).xyz;
  87. }
  88. vec3 getViewNormal( const in vec3 viewPosition, const in vec2 screenPosition ) {
  89. return unpackRGBToNormal( texture2D( tNormal, screenPosition ).xyz );
  90. }
  91. float scaleDividedByCameraFar;
  92. float minResolutionMultipliedByCameraFar;
  93. float getOcclusion( const in vec3 centerViewPosition, const in vec3 centerViewNormal, const in vec3 sampleViewPosition ) {
  94. vec3 viewDelta = sampleViewPosition - centerViewPosition;
  95. float viewDistance = length( viewDelta );
  96. float scaledScreenDistance = scaleDividedByCameraFar * viewDistance;
  97. return max(0.0, (dot(centerViewNormal, viewDelta) - minResolutionMultipliedByCameraFar) / scaledScreenDistance - bias) / (1.0 + pow2( scaledScreenDistance ) );
  98. }
  99. // moving costly divides into consts
  100. const float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES );
  101. const float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES );
  102. float getAmbientOcclusion( const in vec3 centerViewPosition ) {
  103. // precompute some variables require in getOcclusion.
  104. scaleDividedByCameraFar = scale / cameraFar;
  105. minResolutionMultipliedByCameraFar = minResolution * cameraFar;
  106. vec3 centerViewNormal = getViewNormal( centerViewPosition, vUv );
  107. // jsfiddle that shows sample pattern: https://jsfiddle.net/a16ff1p7/
  108. float angle = rand( vUv + randomSeed ) * PI2;
  109. vec2 radius = vec2( kernelRadius * INV_NUM_SAMPLES ) / size;
  110. vec2 radiusStep = radius;
  111. float occlusionSum = 0.0;
  112. float weightSum = 0.0;
  113. for( int i = 0; i < NUM_SAMPLES; i ++ ) {
  114. vec2 sampleUv = vUv + vec2( cos( angle ), sin( angle ) ) * radius;
  115. radius += radiusStep;
  116. angle += ANGLE_STEP;
  117. float sampleDepth = getDepth( sampleUv );
  118. if( sampleDepth >= ( 1.0 - EPSILON ) ) {
  119. continue;
  120. }
  121. float sampleViewZ = getViewZ( sampleDepth );
  122. vec3 sampleViewPosition = getViewPosition( sampleUv, sampleDepth, sampleViewZ );
  123. occlusionSum += getOcclusion( centerViewPosition, centerViewNormal, sampleViewPosition );
  124. weightSum += 1.0;
  125. }
  126. if( weightSum == 0.0 ) discard;
  127. return occlusionSum * ( intensity / weightSum );
  128. }
  129. void main() {
  130. float centerDepth = getDepth( vUv );
  131. if( centerDepth >= ( 1.0 - EPSILON ) ) {
  132. discard;
  133. }
  134. float centerViewZ = getViewZ( centerDepth );
  135. vec3 viewPosition = getViewPosition( vUv, centerDepth, centerViewZ );
  136. float ambientOcclusion = getAmbientOcclusion( viewPosition );
  137. gl_FragColor = getDefaultColor( vUv );
  138. gl_FragColor.xyz *= 1.0 - ambientOcclusion;
  139. }`
  140. };
  141. export { SAOShader };
粤ICP备19079148号