UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

192 lines (147 loc) 6 kB
import { Color, NoBlending, RGBAFormat, ShaderMaterial, UniformsUtils, Vector2, WebGLMultisampleRenderTarget } from "three"; import { BlurShaderUtils, DepthLimitedBlurShader } from "three/examples/jsm/shaders/DepthLimitedBlurShader.js"; import { renderScreenSpace } from "../../utils/renderScreenSpace.js"; const scratch_color = new Color(); export class DepthLimitedBlur { constructor({ format = RGBAFormat, radius = 8, clear_color = 0, clear_alpha = 1 }) { /** * * @type {WebGLRenderTarget|null} * @private */ this.__rt_input = null; /** * * @type {WebGLRenderTarget|null} * @private */ this.__rt_output = null; this.__intermediate = new WebGLMultisampleRenderTarget({ format }); this.__material_blur_x = new ShaderMaterial({ uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms), defines: Object.assign({}, DepthLimitedBlurShader.defines), vertexShader: DepthLimitedBlurShader.vertexShader, fragmentShader: DepthLimitedBlurShader.fragmentShader, blending: NoBlending }); this.__material_blur_y = new ShaderMaterial({ uniforms: UniformsUtils.clone(DepthLimitedBlurShader.uniforms), defines: Object.assign({}, DepthLimitedBlurShader.defines), vertexShader: DepthLimitedBlurShader.vertexShader, fragmentShader: DepthLimitedBlurShader.fragmentShader, blending: NoBlending }); this.__depth_cutoff = 0.01; this.__blur_radius = radius; this.__blur_std_dev = 4; this.__clear_color = new Color(clear_color); this.__clear_alpha = clear_alpha; } configureMaterials() { const mx = this.__material_blur_x; const my = this.__material_blur_y; mx.defines.DEPTH_PACKING = my.defines.DEPTH_PACKING = 0; mx.defines.PERSPECTIVE_CAMERA = my.defines.PERSPECTIVE_CAMERA = 1; mx.blending = my.blending = NoBlending; BlurShaderUtils.configure(mx, this.__blur_radius, this.__blur_std_dev, new Vector2(1, 0)); BlurShaderUtils.configure(my, this.__blur_radius, this.__blur_std_dev, new Vector2(0, 1)); this.__material_blur_y.uniforms.tDiffuse.value = this.__intermediate.texture; } /** * * @param {Camera} camera */ setRenderCamera(camera) { const mx = this.__material_blur_x; const my = this.__material_blur_y; if (camera.isPerspectiveCamera === true && mx.defines.PERSPECTIVE_CAMERA !== 1) { mx.defines.PERSPECTIVE_CAMERA = 1; my.defines.PERSPECTIVE_CAMERA = 1; mx.needsUpdate = true; my.needsUpdate = true; } else if (camera.isPerspectiveCamera !== true && mx.defines.PERSPECTIVE_CAMERA !== 0) { mx.defines.PERSPECTIVE_CAMERA = 0; my.defines.PERSPECTIVE_CAMERA = 0; mx.needsUpdate = true; my.needsUpdate = true; } const depthCutoff = this.__depth_cutoff * (camera.far - camera.near); mx.uniforms.depthCutoff.value = depthCutoff; my.uniforms.depthCutoff.value = depthCutoff; mx.uniforms.cameraNear.value = my.uniforms.cameraNear.value = camera.near; mx.uniforms.cameraFar.value = my.uniforms.cameraFar.value = camera.far; } /** * * @param {WebGLRenderer} renderer */ execute(renderer) { // update intermediate buffer size based on input size if ( this.__intermediate.width !== this.__rt_output.width || this.__intermediate.height !== this.__rt_output.height ) { this.__intermediate.setSize(this.__rt_output.width, this.__rt_output.height); } const mx = this.__material_blur_x; const my = this.__material_blur_y; // set resolution parameter for each shader mx.uniforms.size.value.set(this.__rt_output.width, this.__rt_output.height); my.uniforms.size.value.set(this.__rt_output.width, this.__rt_output.height); // remember renderer state const __old_state_rt = renderer.getRenderTarget(); const __old_clear_color = scratch_color; renderer.getClearColor(__old_clear_color); const __old_clear_alpha = renderer.getClearAlpha(); const __old_auto_clear = renderer.autoClear; // renderer.autoClear = false; renderer.setClearColor(this.__clear_color); renderer.setRenderTarget(this.__intermediate); renderer.clearColor(); renderScreenSpace(renderer, mx); renderer.setRenderTarget(this.__rt_output); renderer.clearColor(); renderScreenSpace(renderer, my); // restore state renderer.setRenderTarget(__old_state_rt); renderer.setClearColor(__old_clear_color, __old_clear_alpha); renderer.autoClear = __old_auto_clear; } /** * * @param {Texture} texture */ setDepthBuffer(texture) { const mx = this.__material_blur_x; const my = this.__material_blur_y; mx.uniforms.tDepth.value = my.uniforms.tDepth.value = texture; } /** * * @param {WebGLRenderTarget|WebGLMultisampleRenderTarget} render_target */ setInput(render_target) { this.__rt_input = render_target; // bind input this.__material_blur_x.uniforms.tDiffuse.value = render_target.texture; } /** * * @param {WebGLRenderTarget|WebGLMultisampleRenderTarget} render_target */ setOutput(render_target) { this.__rt_output = render_target; } dispose() { this.__intermediate.dispose(); } }