BokehPass.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import {
  2. Color,
  3. HalfFloatType,
  4. MeshDepthMaterial,
  5. NearestFilter,
  6. NoBlending,
  7. RGBADepthPacking,
  8. ShaderMaterial,
  9. UniformsUtils,
  10. WebGLRenderTarget
  11. } from 'three';
  12. import { Pass, FullScreenQuad } from './Pass.js';
  13. import { BokehShader } from '../shaders/BokehShader.js';
  14. /**
  15. * Pass for creating depth of field (DOF) effect.
  16. *
  17. * ```js
  18. * const bokehPass = new BokehPass( scene, camera, {
  19. * focus: 500
  20. * aperture: 5,
  21. * maxblur: 0.01
  22. * } );
  23. * composer.addPass( bokehPass );
  24. * ```
  25. *
  26. * @augments Pass
  27. * @three_import import { BokehPass } from 'three/addons/postprocessing/BokehPass.js';
  28. */
  29. class BokehPass extends Pass {
  30. /**
  31. * Constructs a new Bokeh pass.
  32. *
  33. * @param {Scene} scene - The scene to render the DOF for.
  34. * @param {Camera} camera - The camera.
  35. * @param {BokehPass~Options} params - The pass options.
  36. */
  37. constructor( scene, camera, params ) {
  38. super();
  39. /**
  40. * The scene to render the DOF for.
  41. *
  42. * @type {Scene}
  43. */
  44. this.scene = scene;
  45. /**
  46. * The camera.
  47. *
  48. * @type {Camera}
  49. */
  50. this.camera = camera;
  51. const focus = ( params.focus !== undefined ) ? params.focus : 1.0;
  52. const aperture = ( params.aperture !== undefined ) ? params.aperture : 0.025;
  53. const maxblur = ( params.maxblur !== undefined ) ? params.maxblur : 1.0;
  54. // render targets
  55. this._renderTargetDepth = new WebGLRenderTarget( 1, 1, { // will be resized later
  56. minFilter: NearestFilter,
  57. magFilter: NearestFilter,
  58. type: HalfFloatType
  59. } );
  60. this._renderTargetDepth.texture.name = 'BokehPass.depth';
  61. // depth material
  62. this._materialDepth = new MeshDepthMaterial();
  63. this._materialDepth.depthPacking = RGBADepthPacking;
  64. this._materialDepth.blending = NoBlending;
  65. // bokeh material
  66. const bokehUniforms = UniformsUtils.clone( BokehShader.uniforms );
  67. bokehUniforms[ 'tDepth' ].value = this._renderTargetDepth.texture;
  68. bokehUniforms[ 'focus' ].value = focus;
  69. bokehUniforms[ 'aspect' ].value = camera.aspect;
  70. bokehUniforms[ 'aperture' ].value = aperture;
  71. bokehUniforms[ 'maxblur' ].value = maxblur;
  72. bokehUniforms[ 'nearClip' ].value = camera.near;
  73. bokehUniforms[ 'farClip' ].value = camera.far;
  74. /**
  75. * The pass bokeh material.
  76. *
  77. * @type {ShaderMaterial}
  78. */
  79. this.materialBokeh = new ShaderMaterial( {
  80. defines: Object.assign( {}, BokehShader.defines ),
  81. uniforms: bokehUniforms,
  82. vertexShader: BokehShader.vertexShader,
  83. fragmentShader: BokehShader.fragmentShader
  84. } );
  85. /**
  86. * The pass uniforms. Use this object if you want to update the
  87. * `focus`, `aperture` or `maxblur` values at runtime.
  88. *
  89. * ```js
  90. * pass.uniforms.focus.value = focus;
  91. * pass.uniforms.aperture.value = aperture;
  92. * pass.uniforms.maxblur.value = maxblur;
  93. * ```
  94. *
  95. * @type {Object}
  96. */
  97. this.uniforms = bokehUniforms;
  98. // internals
  99. this._fsQuad = new FullScreenQuad( this.materialBokeh );
  100. this._oldClearColor = new Color();
  101. }
  102. /**
  103. * Performs the Bokeh pass.
  104. *
  105. * @param {WebGLRenderer} renderer - The renderer.
  106. * @param {WebGLRenderTarget} writeBuffer - The write buffer. This buffer is intended as the rendering
  107. * destination for the pass.
  108. * @param {WebGLRenderTarget} readBuffer - The read buffer. The pass can access the result from the
  109. * previous pass from this buffer.
  110. * @param {number} deltaTime - The delta time in seconds.
  111. * @param {boolean} maskActive - Whether masking is active or not.
  112. */
  113. render( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {
  114. // Render depth into texture
  115. this.scene.overrideMaterial = this._materialDepth;
  116. renderer.getClearColor( this._oldClearColor );
  117. const oldClearAlpha = renderer.getClearAlpha();
  118. const oldAutoClear = renderer.autoClear;
  119. renderer.autoClear = false;
  120. renderer.setClearColor( 0xffffff );
  121. renderer.setClearAlpha( 1.0 );
  122. renderer.setRenderTarget( this._renderTargetDepth );
  123. renderer.clear();
  124. renderer.render( this.scene, this.camera );
  125. // Render bokeh composite
  126. this.uniforms[ 'tColor' ].value = readBuffer.texture;
  127. this.uniforms[ 'nearClip' ].value = this.camera.near;
  128. this.uniforms[ 'farClip' ].value = this.camera.far;
  129. if ( this.renderToScreen ) {
  130. renderer.setRenderTarget( null );
  131. this._fsQuad.render( renderer );
  132. } else {
  133. renderer.setRenderTarget( writeBuffer );
  134. renderer.clear();
  135. this._fsQuad.render( renderer );
  136. }
  137. this.scene.overrideMaterial = null;
  138. renderer.setClearColor( this._oldClearColor );
  139. renderer.setClearAlpha( oldClearAlpha );
  140. renderer.autoClear = oldAutoClear;
  141. }
  142. /**
  143. * Sets the size of the pass.
  144. *
  145. * @param {number} width - The width to set.
  146. * @param {number} height - The width to set.
  147. */
  148. setSize( width, height ) {
  149. this.materialBokeh.uniforms[ 'aspect' ].value = width / height;
  150. this._renderTargetDepth.setSize( width, height );
  151. }
  152. /**
  153. * Frees the GPU-related resources allocated by this instance. Call this
  154. * method whenever the pass is no longer used in your app.
  155. */
  156. dispose() {
  157. this._renderTargetDepth.dispose();
  158. this._materialDepth.dispose();
  159. this.materialBokeh.dispose();
  160. this._fsQuad.dispose();
  161. }
  162. }
  163. /**
  164. * Constructor options of `BokehPass`.
  165. *
  166. * @typedef {Object} BokehPass~Options
  167. * @property {number} [focus=1] - Defines the effect's focus which is the distance along the camera's look direction in world units.
  168. * @property {number} [aperture=0.025] - Defines the effect's aperture.
  169. * @property {number} [maxblur=1] - Defines the effect's maximum blur.
  170. **/
  171. export { BokehPass };