/** * @author alteredq / http://alteredqualia.com/ */ import { ShaderMaterial, LinearFilter, RGBAFormat, Vector2, WebGLRenderTarget, UniformsUtils, } from "three"; import { Pass } from "../postprocessing/Pass.js"; import { BlurShader } from "../shaders/BlurShader.js"; import { CopyShader } from "../shaders/CopyShader.js"; var BlurPass = function (blur, resolution) { Pass.call(this); this.downSampleRatio = 2; this.blur = blur !== undefined ? blur : 0.8; this.resolution = resolution !== undefined ? new Vector2(resolution.x, resolution.y) : new Vector2(256, 256); var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat, }; var resx = Math.round(this.resolution.x / this.downSampleRatio); var resy = Math.round(this.resolution.y / this.downSampleRatio); this.renderTargetBlurBuffer1 = new WebGLRenderTarget(resx, resy, pars); this.renderTargetBlurBuffer1.texture.name = "BlurPass.blur1"; this.renderTargetBlurBuffer1.texture.generateMipmaps = false; this.renderTargetBlurBuffer2 = new WebGLRenderTarget( Math.round(resx / 2), Math.round(resy / 2), pars ); this.renderTargetBlurBuffer2.texture.name = "BlurPass.blur2"; this.renderTargetBlurBuffer2.texture.generateMipmaps = false; this.separableBlurMaterial1 = this.getSeperableBlurMaterial(16); this.separableBlurMaterial1.uniforms["texSize"].value = new Vector2( resx, resy ); this.separableBlurMaterial1.uniforms["kernelRadius"].value = 1; this.separableBlurMaterial2 = this.getSeperableBlurMaterial(16); this.separableBlurMaterial2.uniforms["texSize"].value = new Vector2( Math.round(resx / 2), Math.round(resy / 2) ); this.separableBlurMaterial2.uniforms["kernelRadius"].value = 1; var copyShader = CopyShader; this.copyUniforms = UniformsUtils.clone(copyShader.uniforms); this.materialCopy = new ShaderMaterial({ uniforms: this.copyUniforms, vertexShader: copyShader.vertexShader, fragmentShader: copyShader.fragmentShader, depthTest: false, depthWrite: false, transparent: true, }); //this.needsSwap = false; this.fsQuad = new Pass.FullScreenQuad(null); }; BlurPass.prototype = Object.assign(Object.create(Pass.prototype), { constructor: BlurPass, render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) { if (this.blur > 0) { // 4. Apply Blur on Half res this.fsQuad.material = this.separableBlurMaterial1; this.separableBlurMaterial1.uniforms[ "kernelRadius" ].value = this.blur; this.separableBlurMaterial1.uniforms["colorTexture"].value = readBuffer.texture; this.separableBlurMaterial1.uniforms["direction"].value = BlurPass.BlurDirectionX; renderer.setRenderTarget(this.renderTargetBlurBuffer1); if (this.clear) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); this.fsQuad.render(renderer); // Apply Blur on quarter res this.fsQuad.material = this.separableBlurMaterial2; this.separableBlurMaterial2.uniforms[ "kernelRadius" ].value = this.blur; this.separableBlurMaterial2.uniforms[ "colorTexture" ].value = this.renderTargetBlurBuffer1.texture; this.separableBlurMaterial2.uniforms["direction"].value = BlurPass.BlurDirectionY; renderer.setRenderTarget(writeBuffer); if (this.clear) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); this.fsQuad.render(renderer); } else { this.fsQuad.material = this.materialCopy; this.copyUniforms["tDiffuse"].value = readBuffer.texture; renderer.setRenderTarget(writeBuffer); this.fsQuad.render(renderer); } }, getSeperableBlurMaterial: function (maxRadius) { return new ShaderMaterial({ depthTest: false, depthWrite: false, transparent: true, defines: { MAX_RADIUS: maxRadius, }, uniforms: { colorTexture: { value: null }, texSize: { value: new Vector2(0.5, 0.5) }, direction: { value: new Vector2(0.5, 0.5) }, kernelRadius: { value: 5.0 }, }, vertexShader: "varying vec2 vUv;\n\ void main() {\n\ vUv = uv;\n\ gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ }", fragmentShader: "#include <common>\ varying vec2 vUv;\ uniform sampler2D colorTexture;\ uniform vec2 texSize;\ uniform vec2 direction;\ uniform float kernelRadius;\ \ float gaussianPdf(in float x, in float sigma) {\ return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\ }\ void main() {\ vec2 invSize = 1.0 / texSize;\ float weightSum = gaussianPdf(0.0, kernelRadius);\ vec4 diffuseSum = texture2D( colorTexture, vUv) * weightSum;\ vec2 delta = direction * invSize * kernelRadius/float(MAX_RADIUS);\ vec2 uvOffset = delta;\ for( int i = 1; i <= MAX_RADIUS; i ++ ) {\ float w = gaussianPdf(uvOffset.x, kernelRadius);\ vec4 sample1 = texture2D( colorTexture, vUv + uvOffset);\ vec4 sample2 = texture2D( colorTexture, vUv - uvOffset);\ diffuseSum += ((sample1 + sample2) * w);\ weightSum += (2.0 * w);\ uvOffset += delta;\ }\ gl_FragColor = diffuseSum/weightSum;\ }", }); }, }); BlurPass.BlurDirectionX = new Vector2(1.0, 0.0); BlurPass.BlurDirectionY = new Vector2(0.0, 1.0); export { BlurPass };