src/materials/ConvolutionMaterial.js
import { ShaderMaterial, Uniform, Vector2 } from "three";
import fragmentShader from "./glsl/convolution/shader.frag";
import vertexShader from "./glsl/convolution/shader.vert";
/**
* An optimised convolution shader material.
*
* This material supports dithering.
*
* Based on the GDC2003 Presentation by Masaki Kawase, Bunkasha Games:
* Frame Buffer Postprocessing Effects in DOUBLE-S.T.E.A.L (Wreckless)
* and an article by Filip Strugar, Intel:
* An investigation of fast real-time GPU-based image blur algorithms
*
* Further modified according to Apple's
* [Best Practices for Shaders](https://goo.gl/lmRoM5).
*
* @todo Remove dithering code from fragment shader.
*/
export class ConvolutionMaterial extends ShaderMaterial {
/**
* Constructs a new convolution material.
*
* @param {Vector2} [texelSize] - The absolute screen texel size.
*/
constructor(texelSize = new Vector2()) {
super({
type: "ConvolutionMaterial",
uniforms: {
inputBuffer: new Uniform(null),
texelSize: new Uniform(new Vector2()),
halfTexelSize: new Uniform(new Vector2()),
kernel: new Uniform(0.0),
scale: new Uniform(1.0)
},
fragmentShader,
vertexShader,
depthWrite: false,
depthTest: false
});
/** @ignore */
this.toneMapped = false;
this.setTexelSize(texelSize.x, texelSize.y);
/**
* The current kernel size.
*
* @type {KernelSize}
*/
this.kernelSize = KernelSize.LARGE;
}
/**
* Returns the kernel.
*
* @return {Float32Array} The kernel.
*/
getKernel() {
return kernelPresets[this.kernelSize];
}
/**
* Sets the texel size.
*
* @param {Number} x - The texel width.
* @param {Number} y - The texel height.
*/
setTexelSize(x, y) {
this.uniforms.texelSize.value.set(x, y);
this.uniforms.halfTexelSize.value.set(x, y).multiplyScalar(0.5);
}
}
/**
* The Kawase blur kernel presets.
*
* @type {Float32Array[]}
* @private
*/
const kernelPresets = [
new Float32Array([0.0, 0.0]),
new Float32Array([0.0, 1.0, 1.0]),
new Float32Array([0.0, 1.0, 1.0, 2.0]),
new Float32Array([0.0, 1.0, 2.0, 2.0, 3.0]),
new Float32Array([0.0, 1.0, 2.0, 3.0, 4.0, 4.0, 5.0]),
new Float32Array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 8.0, 9.0, 10.0])
];
/**
* A kernel size enumeration.
*
* @type {Object}
* @property {Number} VERY_SMALL - A very small kernel that matches a 7x7 Gauss blur kernel.
* @property {Number} SMALL - A small kernel that matches a 15x15 Gauss blur kernel.
* @property {Number} MEDIUM - A medium sized kernel that matches a 23x23 Gauss blur kernel.
* @property {Number} LARGE - A large kernel that matches a 35x35 Gauss blur kernel.
* @property {Number} VERY_LARGE - A very large kernel that matches a 63x63 Gauss blur kernel.
* @property {Number} HUGE - A huge kernel that matches a 127x127 Gauss blur kernel.
*/
export const KernelSize = {
VERY_SMALL: 0,
SMALL: 1,
MEDIUM: 2,
LARGE: 3,
VERY_LARGE: 4,
HUGE: 5
};