DepthLimitedBlurShader.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import {
  2. Vector2
  3. } from 'three';
  4. /**
  5. * TODO
  6. */
  7. const DepthLimitedBlurShader = {
  8. name: 'DepthLimitedBlurShader',
  9. defines: {
  10. 'KERNEL_RADIUS': 4,
  11. 'DEPTH_PACKING': 1,
  12. 'PERSPECTIVE_CAMERA': 1
  13. },
  14. uniforms: {
  15. 'tDiffuse': { value: null },
  16. 'size': { value: new Vector2( 512, 512 ) },
  17. 'sampleUvOffsets': { value: [ new Vector2( 0, 0 ) ] },
  18. 'sampleWeights': { value: [ 1.0 ] },
  19. 'tDepth': { value: null },
  20. 'cameraNear': { value: 10 },
  21. 'cameraFar': { value: 1000 },
  22. 'depthCutoff': { value: 10 },
  23. },
  24. vertexShader: /* glsl */`
  25. #include <common>
  26. uniform vec2 size;
  27. varying vec2 vUv;
  28. varying vec2 vInvSize;
  29. void main() {
  30. vUv = uv;
  31. vInvSize = 1.0 / size;
  32. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  33. }`,
  34. fragmentShader: /* glsl */`
  35. #include <common>
  36. #include <packing>
  37. uniform sampler2D tDiffuse;
  38. uniform sampler2D tDepth;
  39. uniform float cameraNear;
  40. uniform float cameraFar;
  41. uniform float depthCutoff;
  42. uniform vec2 sampleUvOffsets[ KERNEL_RADIUS + 1 ];
  43. uniform float sampleWeights[ KERNEL_RADIUS + 1 ];
  44. varying vec2 vUv;
  45. varying vec2 vInvSize;
  46. float getDepth( const in vec2 screenPosition ) {
  47. #if DEPTH_PACKING == 1
  48. return unpackRGBAToDepth( texture2D( tDepth, screenPosition ) );
  49. #else
  50. return texture2D( tDepth, screenPosition ).x;
  51. #endif
  52. }
  53. float getViewZ( const in float depth ) {
  54. #if PERSPECTIVE_CAMERA == 1
  55. return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
  56. #else
  57. return orthographicDepthToViewZ( depth, cameraNear, cameraFar );
  58. #endif
  59. }
  60. void main() {
  61. float depth = getDepth( vUv );
  62. if( depth >= ( 1.0 - EPSILON ) ) {
  63. discard;
  64. }
  65. float centerViewZ = -getViewZ( depth );
  66. bool rBreak = false, lBreak = false;
  67. float weightSum = sampleWeights[0];
  68. vec4 diffuseSum = texture2D( tDiffuse, vUv ) * weightSum;
  69. for( int i = 1; i <= KERNEL_RADIUS; i ++ ) {
  70. float sampleWeight = sampleWeights[i];
  71. vec2 sampleUvOffset = sampleUvOffsets[i] * vInvSize;
  72. vec2 sampleUv = vUv + sampleUvOffset;
  73. float viewZ = -getViewZ( getDepth( sampleUv ) );
  74. if( abs( viewZ - centerViewZ ) > depthCutoff ) rBreak = true;
  75. if( ! rBreak ) {
  76. diffuseSum += texture2D( tDiffuse, sampleUv ) * sampleWeight;
  77. weightSum += sampleWeight;
  78. }
  79. sampleUv = vUv - sampleUvOffset;
  80. viewZ = -getViewZ( getDepth( sampleUv ) );
  81. if( abs( viewZ - centerViewZ ) > depthCutoff ) lBreak = true;
  82. if( ! lBreak ) {
  83. diffuseSum += texture2D( tDiffuse, sampleUv ) * sampleWeight;
  84. weightSum += sampleWeight;
  85. }
  86. }
  87. gl_FragColor = diffuseSum / weightSum;
  88. }`
  89. };
  90. const BlurShaderUtils = {
  91. createSampleWeights: function ( kernelRadius, stdDev ) {
  92. const weights = [];
  93. for ( let i = 0; i <= kernelRadius; i ++ ) {
  94. weights.push( gaussian( i, stdDev ) );
  95. }
  96. return weights;
  97. },
  98. createSampleOffsets: function ( kernelRadius, uvIncrement ) {
  99. const offsets = [];
  100. for ( let i = 0; i <= kernelRadius; i ++ ) {
  101. offsets.push( uvIncrement.clone().multiplyScalar( i ) );
  102. }
  103. return offsets;
  104. },
  105. configure: function ( material, kernelRadius, stdDev, uvIncrement ) {
  106. material.defines[ 'KERNEL_RADIUS' ] = kernelRadius;
  107. material.uniforms[ 'sampleUvOffsets' ].value = BlurShaderUtils.createSampleOffsets( kernelRadius, uvIncrement );
  108. material.uniforms[ 'sampleWeights' ].value = BlurShaderUtils.createSampleWeights( kernelRadius, stdDev );
  109. material.needsUpdate = true;
  110. }
  111. };
  112. function gaussian( x, stdDev ) {
  113. return Math.exp( - ( x * x ) / ( 2.0 * ( stdDev * stdDev ) ) ) / ( Math.sqrt( 2.0 * Math.PI ) * stdDev );
  114. }
  115. export { DepthLimitedBlurShader, BlurShaderUtils };