@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
192 lines (147 loc) • 6 kB
JavaScript
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();
}
}