Restructured library.
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* A Gaussian blur filter. With this filter, you can blur an area of a PIXI.DisplayObject. This cannot
|
||||
* be done with the PIXI.filters.BlurFilter (when you use the PIXI.filters.BlurFilter with
|
||||
* an filter area, all pixels outside of the area are not displayed). Attention: The area of
|
||||
* the filter is always in global scope, NOT relative to the PIXI.DisplayObject the filter
|
||||
* is assigned to!
|
||||
*
|
||||
* @example
|
||||
* // Create the app
|
||||
* const app = new PIXIApp({
|
||||
* view: canvas,
|
||||
* width: 480,
|
||||
* height: 270,
|
||||
* transparent: false
|
||||
* }).setup().run()
|
||||
*
|
||||
* // Add a video sprite
|
||||
* const sprite = new PIXI.Sprite(PIXI.Texture.fromVideo("assets/blurfilter.mp4"))
|
||||
* sprite.width = app.size.width
|
||||
* sprite.height = app.size.height
|
||||
* app.scene.addChild(sprite)
|
||||
*
|
||||
* // Create the filter and assign it to the scene
|
||||
* const blurFilter = new BlurFilter(new PIXI.Rectangle(20, 20, 80, 60))
|
||||
* app.scene.filters = [blurFilter]
|
||||
*
|
||||
* @class
|
||||
* @extends PIXI.Filter
|
||||
* @param {PIXI.Rectangle|PIXI.Circle|PIXI.DisplayObject} shape The area where the blur effect should be applied to. Relative to the
|
||||
* canvas, NOT relative to the PIXI.DisplayObject where the blur effect is assigned to!
|
||||
* @param {number} [blur=50] The strength of the blur.
|
||||
*/
|
||||
export default class BlurFilter extends PIXI.Filter {
|
||||
|
||||
constructor(shape, blur = 50) {
|
||||
super()
|
||||
|
||||
const normalized = this.normalize(shape)
|
||||
|
||||
this.tiltShiftXFilter = new TiltShiftXFilter(normalized, blur)
|
||||
this.tiltShiftYFilter = new TiltShiftYFilter(normalized, blur)
|
||||
}
|
||||
|
||||
apply(filterManager, input, output) {
|
||||
let renderTarget = filterManager.getRenderTarget(true)
|
||||
this.tiltShiftXFilter.apply(filterManager, input, renderTarget)
|
||||
this.tiltShiftYFilter.apply(filterManager, renderTarget, output)
|
||||
filterManager.returnRenderTarget(renderTarget)
|
||||
}
|
||||
|
||||
/**
|
||||
* The strength of the blur.
|
||||
*
|
||||
* @member {number}
|
||||
*/
|
||||
get blur() {
|
||||
return this.tiltShiftXFilter.blur
|
||||
}
|
||||
set blur(value) {
|
||||
this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The blur shape.
|
||||
*
|
||||
* @member {PIXI.Rectangle|PIXI.Circle|PIXI.DisplayObject}
|
||||
*/
|
||||
get shape() {
|
||||
return this.tiltShiftXFilter.shape
|
||||
}
|
||||
set shape(value) {
|
||||
this.tiltShiftXFilter.shape = this.tiltShiftYFilter.shape = this.normalize(value)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
* @param {PIXI.Rectangle|PIXI.Circle|PIXI.DisplayObject} value
|
||||
* @returns {Object}
|
||||
*/
|
||||
normalize(value) {
|
||||
|
||||
let shape = null
|
||||
|
||||
if (value instanceof PIXI.Circle) {
|
||||
shape = {type: 'circle', x: value.x, y: value.y, r: value.radius}
|
||||
} else if (value instanceof PIXI.Rectangle) {
|
||||
shape = {type: 'rectangle', x: value.x, y: value.y, width: value.width, height: value.height}
|
||||
} else {
|
||||
const bounds = value.getBounds()
|
||||
shape = {type: 'rectangle', x: bounds.x, y: bounds.y, width: bounds.width, height: bounds.height}
|
||||
}
|
||||
|
||||
return shape
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A TiltShiftAxisFilter.
|
||||
*
|
||||
* @class
|
||||
* @extends PIXI.Filter
|
||||
* @abstract
|
||||
* @private
|
||||
*/
|
||||
class TiltShiftAxisFilter extends PIXI.Filter {
|
||||
|
||||
constructor(shape, blur){
|
||||
|
||||
const vertex = `
|
||||
attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
varying vec2 vTextureCoord;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vTextureCoord = aTextureCoord;
|
||||
}
|
||||
`
|
||||
|
||||
const fragment = `
|
||||
varying vec2 vTextureCoord;
|
||||
|
||||
uniform vec4 filterArea;
|
||||
uniform sampler2D uSampler;
|
||||
uniform int shape;
|
||||
uniform vec4 rectangle;
|
||||
uniform vec3 circle;
|
||||
uniform float blur;
|
||||
uniform vec2 delta;
|
||||
uniform vec2 texSize;
|
||||
|
||||
float random(vec3 scale, float seed) {
|
||||
return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// textureCoord to pixelCoord
|
||||
vec2 pixelCoord = vTextureCoord * filterArea.xy - vec2(4.0, 4.0); // FIXME: There's a shift of 4 * 4 pixels, don't know why...
|
||||
|
||||
bool inside = false;
|
||||
|
||||
if (shape == 1) {
|
||||
inside = distance(pixelCoord, circle.xy) <= circle.z;
|
||||
} else if (shape == 2) {
|
||||
inside = pixelCoord.x >= rectangle.x && pixelCoord.x <= rectangle.z && pixelCoord.y >= rectangle.y && pixelCoord.y <= rectangle.w;
|
||||
}
|
||||
|
||||
if (inside) {
|
||||
vec4 color = vec4(0.0);
|
||||
float total = 0.0;
|
||||
|
||||
float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);
|
||||
|
||||
for (float t = -30.0; t <= 30.0; t++) {
|
||||
float percent = (t + offset - 0.5) / 30.0;
|
||||
float weight = 1.0 - abs(percent);
|
||||
vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * blur);
|
||||
sample.rgb *= sample.a;
|
||||
color += sample * weight;
|
||||
total += weight;
|
||||
}
|
||||
|
||||
gl_FragColor = color / total;
|
||||
gl_FragColor.rgb /= gl_FragColor.a + 0.00001;
|
||||
} else {
|
||||
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
super(vertex, fragment)
|
||||
|
||||
if (shape.type === 'circle') {
|
||||
this.uniforms.shape = 1
|
||||
this.uniforms.circle = [shape.x, shape.y, shape.r]
|
||||
} else {
|
||||
this.uniforms.shape = 2
|
||||
this.uniforms.rectangle = [shape.x, shape.y, shape.x + shape.width, shape.y + shape.height]
|
||||
}
|
||||
this.uniforms.blur = blur
|
||||
this.uniforms.delta = new PIXI.Point(0, 0)
|
||||
this.uniforms.texSize = new PIXI.Point(480, 270)
|
||||
|
||||
this.updateDelta()
|
||||
}
|
||||
|
||||
/**
|
||||
* The strength of the blur.
|
||||
*
|
||||
* @member {number}
|
||||
* @memberof PIXI.filters.TiltShiftAxisFilter#
|
||||
*/
|
||||
get blur() {
|
||||
return this.uniforms.blur
|
||||
}
|
||||
set blur(value) {
|
||||
this.uniforms.blur = value
|
||||
}
|
||||
|
||||
/**
|
||||
* The blur shape.
|
||||
*
|
||||
* @member {PIXI.Rectangle}
|
||||
* @memberof PIXI.filters.TiltShiftAxisFilter#
|
||||
*/
|
||||
get shape() {
|
||||
if (this.uniforms.shape === 1) {
|
||||
const circle = this.uniforms.circle
|
||||
return new PIXI.Circle(circle[0], circle[1], circle[2])
|
||||
} else {
|
||||
const rectangle = this.uniforms.rectangle
|
||||
return new PIXI.Rectangle(rectangle[0], rectangle[1], rectangle[2], rectangle[3])
|
||||
}
|
||||
}
|
||||
set shape(value) {
|
||||
if (value.type === 'circle') {
|
||||
this.uniforms.shape = 1
|
||||
this.uniforms.circle = [value.x, value.y, value.r]
|
||||
} else {
|
||||
this.uniforms.shape = 2
|
||||
this.uniforms.rectangle = [value.x, value.y, value.x + value.width, value.y + value.height]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A TiltShiftXFilter.
|
||||
*
|
||||
* @class
|
||||
* @extends PIXI.TiltShiftAxisFilter
|
||||
* @private
|
||||
*/
|
||||
class TiltShiftXFilter extends TiltShiftAxisFilter {
|
||||
/**
|
||||
* Updates the filter delta values.
|
||||
*/
|
||||
updateDelta() {
|
||||
this.uniforms.delta.x = 0.1
|
||||
this.uniforms.delta.y = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A TiltShiftYFilter.
|
||||
*
|
||||
* @class
|
||||
* @extends PIXI.TiltShiftAxisFilter
|
||||
* @private
|
||||
*/
|
||||
class TiltShiftYFilter extends TiltShiftAxisFilter {
|
||||
/**
|
||||
* Updates the filter delta values.
|
||||
*/
|
||||
updateDelta() {
|
||||
this.uniforms.delta.x = 0
|
||||
this.uniforms.delta.y = 0.1
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user