173 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			173 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | import { | ||
|  | 	AdditiveBlending, | ||
|  | 	HalfFloatType, | ||
|  | 	ShaderMaterial, | ||
|  | 	UniformsUtils, | ||
|  | 	Vector2, | ||
|  | 	WebGLRenderTarget | ||
|  | } from 'three'; | ||
|  | import { Pass, FullScreenQuad } from './Pass.js'; | ||
|  | import { ConvolutionShader } from '../shaders/ConvolutionShader.js'; | ||
|  | 
 | ||
|  | class BloomPass extends Pass { | ||
|  | 
 | ||
|  | 	constructor( strength = 1, kernelSize = 25, sigma = 4 ) { | ||
|  | 
 | ||
|  | 		super(); | ||
|  | 
 | ||
|  | 		// render targets
 | ||
|  | 
 | ||
|  | 		this.renderTargetX = new WebGLRenderTarget( 1, 1, { type: HalfFloatType } ); // will be resized later
 | ||
|  | 		this.renderTargetX.texture.name = 'BloomPass.x'; | ||
|  | 		this.renderTargetY = new WebGLRenderTarget( 1, 1, { type: HalfFloatType } ); // will be resized later
 | ||
|  | 		this.renderTargetY.texture.name = 'BloomPass.y'; | ||
|  | 
 | ||
|  | 		// combine material
 | ||
|  | 
 | ||
|  | 		this.combineUniforms = UniformsUtils.clone( CombineShader.uniforms ); | ||
|  | 
 | ||
|  | 		this.combineUniforms[ 'strength' ].value = strength; | ||
|  | 
 | ||
|  | 		this.materialCombine = new ShaderMaterial( { | ||
|  | 
 | ||
|  | 			name: CombineShader.name, | ||
|  | 			uniforms: this.combineUniforms, | ||
|  | 			vertexShader: CombineShader.vertexShader, | ||
|  | 			fragmentShader: CombineShader.fragmentShader, | ||
|  | 			blending: AdditiveBlending, | ||
|  | 			transparent: true | ||
|  | 
 | ||
|  | 		} ); | ||
|  | 
 | ||
|  | 		// convolution material
 | ||
|  | 
 | ||
|  | 		const convolutionShader = ConvolutionShader; | ||
|  | 
 | ||
|  | 		this.convolutionUniforms = UniformsUtils.clone( convolutionShader.uniforms ); | ||
|  | 
 | ||
|  | 		this.convolutionUniforms[ 'uImageIncrement' ].value = BloomPass.blurX; | ||
|  | 		this.convolutionUniforms[ 'cKernel' ].value = ConvolutionShader.buildKernel( sigma ); | ||
|  | 
 | ||
|  | 		this.materialConvolution = new ShaderMaterial( { | ||
|  | 
 | ||
|  | 			name: convolutionShader.name, | ||
|  | 			uniforms: this.convolutionUniforms, | ||
|  | 			vertexShader: convolutionShader.vertexShader, | ||
|  | 			fragmentShader: convolutionShader.fragmentShader, | ||
|  | 			defines: { | ||
|  | 				'KERNEL_SIZE_FLOAT': kernelSize.toFixed( 1 ), | ||
|  | 				'KERNEL_SIZE_INT': kernelSize.toFixed( 0 ) | ||
|  | 			} | ||
|  | 
 | ||
|  | 		} ); | ||
|  | 
 | ||
|  | 		this.needsSwap = false; | ||
|  | 
 | ||
|  | 		this.fsQuad = new FullScreenQuad( null ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	render( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) { | ||
|  | 
 | ||
|  | 		if ( maskActive ) renderer.state.buffers.stencil.setTest( false ); | ||
|  | 
 | ||
|  | 		// Render quad with blured scene into texture (convolution pass 1)
 | ||
|  | 
 | ||
|  | 		this.fsQuad.material = this.materialConvolution; | ||
|  | 
 | ||
|  | 		this.convolutionUniforms[ 'tDiffuse' ].value = readBuffer.texture; | ||
|  | 		this.convolutionUniforms[ 'uImageIncrement' ].value = BloomPass.blurX; | ||
|  | 
 | ||
|  | 		renderer.setRenderTarget( this.renderTargetX ); | ||
|  | 		renderer.clear(); | ||
|  | 		this.fsQuad.render( renderer ); | ||
|  | 
 | ||
|  | 
 | ||
|  | 		// Render quad with blured scene into texture (convolution pass 2)
 | ||
|  | 
 | ||
|  | 		this.convolutionUniforms[ 'tDiffuse' ].value = this.renderTargetX.texture; | ||
|  | 		this.convolutionUniforms[ 'uImageIncrement' ].value = BloomPass.blurY; | ||
|  | 
 | ||
|  | 		renderer.setRenderTarget( this.renderTargetY ); | ||
|  | 		renderer.clear(); | ||
|  | 		this.fsQuad.render( renderer ); | ||
|  | 
 | ||
|  | 		// Render original scene with superimposed blur to texture
 | ||
|  | 
 | ||
|  | 		this.fsQuad.material = this.materialCombine; | ||
|  | 
 | ||
|  | 		this.combineUniforms[ 'tDiffuse' ].value = this.renderTargetY.texture; | ||
|  | 
 | ||
|  | 		if ( maskActive ) renderer.state.buffers.stencil.setTest( true ); | ||
|  | 
 | ||
|  | 		renderer.setRenderTarget( readBuffer ); | ||
|  | 		if ( this.clear ) renderer.clear(); | ||
|  | 		this.fsQuad.render( renderer ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	setSize( width, height ) { | ||
|  | 
 | ||
|  | 		this.renderTargetX.setSize( width, height ); | ||
|  | 		this.renderTargetY.setSize( width, height ); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 	dispose() { | ||
|  | 
 | ||
|  | 		this.renderTargetX.dispose(); | ||
|  | 		this.renderTargetY.dispose(); | ||
|  | 
 | ||
|  | 		this.materialCombine.dispose(); | ||
|  | 		this.materialConvolution.dispose(); | ||
|  | 
 | ||
|  | 		this.fsQuad.dispose(); | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | const CombineShader = { | ||
|  | 
 | ||
|  | 	name: 'CombineShader', | ||
|  | 
 | ||
|  | 	uniforms: { | ||
|  | 
 | ||
|  | 		'tDiffuse': { value: null }, | ||
|  | 		'strength': { value: 1.0 } | ||
|  | 
 | ||
|  | 	}, | ||
|  | 
 | ||
|  | 	vertexShader: /* glsl */`
 | ||
|  | 
 | ||
|  | 		varying vec2 vUv; | ||
|  | 
 | ||
|  | 		void main() { | ||
|  | 
 | ||
|  | 			vUv = uv; | ||
|  | 			gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); | ||
|  | 
 | ||
|  | 		}`,
 | ||
|  | 
 | ||
|  | 	fragmentShader: /* glsl */`
 | ||
|  | 
 | ||
|  | 		uniform float strength; | ||
|  | 
 | ||
|  | 		uniform sampler2D tDiffuse; | ||
|  | 
 | ||
|  | 		varying vec2 vUv; | ||
|  | 
 | ||
|  | 		void main() { | ||
|  | 
 | ||
|  | 			vec4 texel = texture2D( tDiffuse, vUv ); | ||
|  | 			gl_FragColor = strength * texel; | ||
|  | 
 | ||
|  | 		}`
 | ||
|  | 
 | ||
|  | }; | ||
|  | 
 | ||
|  | BloomPass.blurX = new Vector2( 0.001953125, 0.0 ); | ||
|  | BloomPass.blurY = new Vector2( 0.0, 0.001953125 ); | ||
|  | 
 | ||
|  | export { BloomPass }; |