import { Color, HalfFloatType, MeshDepthMaterial, NearestFilter, NoBlending, RGBADepthPacking, ShaderMaterial, UniformsUtils, WebGLRenderTarget } from 'three'; import { Pass, FullScreenQuad } from './Pass.js'; import { BokehShader } from '../shaders/BokehShader.js'; /** * Depth-of-field post-process with bokeh shader */ class BokehPass extends Pass { constructor( scene, camera, params ) { super(); this.scene = scene; this.camera = camera; const focus = ( params.focus !== undefined ) ? params.focus : 1.0; const aperture = ( params.aperture !== undefined ) ? params.aperture : 0.025; const maxblur = ( params.maxblur !== undefined ) ? params.maxblur : 1.0; // render targets this.renderTargetDepth = new WebGLRenderTarget( 1, 1, { // will be resized later minFilter: NearestFilter, magFilter: NearestFilter, type: HalfFloatType } ); this.renderTargetDepth.texture.name = 'BokehPass.depth'; // depth material this.materialDepth = new MeshDepthMaterial(); this.materialDepth.depthPacking = RGBADepthPacking; this.materialDepth.blending = NoBlending; // bokeh material const bokehShader = BokehShader; const bokehUniforms = UniformsUtils.clone( bokehShader.uniforms ); bokehUniforms[ 'tDepth' ].value = this.renderTargetDepth.texture; bokehUniforms[ 'focus' ].value = focus; bokehUniforms[ 'aspect' ].value = camera.aspect; bokehUniforms[ 'aperture' ].value = aperture; bokehUniforms[ 'maxblur' ].value = maxblur; bokehUniforms[ 'nearClip' ].value = camera.near; bokehUniforms[ 'farClip' ].value = camera.far; this.materialBokeh = new ShaderMaterial( { defines: Object.assign( {}, bokehShader.defines ), uniforms: bokehUniforms, vertexShader: bokehShader.vertexShader, fragmentShader: bokehShader.fragmentShader } ); this.uniforms = bokehUniforms; this.fsQuad = new FullScreenQuad( this.materialBokeh ); this._oldClearColor = new Color(); } render( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) { // Render depth into texture this.scene.overrideMaterial = this.materialDepth; renderer.getClearColor( this._oldClearColor ); const oldClearAlpha = renderer.getClearAlpha(); const oldAutoClear = renderer.autoClear; renderer.autoClear = false; renderer.setClearColor( 0xffffff ); renderer.setClearAlpha( 1.0 ); renderer.setRenderTarget( this.renderTargetDepth ); renderer.clear(); renderer.render( this.scene, this.camera ); // Render bokeh composite this.uniforms[ 'tColor' ].value = readBuffer.texture; this.uniforms[ 'nearClip' ].value = this.camera.near; this.uniforms[ 'farClip' ].value = this.camera.far; if ( this.renderToScreen ) { renderer.setRenderTarget( null ); this.fsQuad.render( renderer ); } else { renderer.setRenderTarget( writeBuffer ); renderer.clear(); this.fsQuad.render( renderer ); } this.scene.overrideMaterial = null; renderer.setClearColor( this._oldClearColor ); renderer.setClearAlpha( oldClearAlpha ); renderer.autoClear = oldAutoClear; } setSize( width, height ) { this.materialBokeh.uniforms[ 'aspect' ].value = width / height; this.renderTargetDepth.setSize( width, height ); } dispose() { this.renderTargetDepth.dispose(); this.materialDepth.dispose(); this.materialBokeh.dispose(); this.fsQuad.dispose(); } } export { BokehPass };