diff --git a/examples/src/DemoApplication.mjs b/examples/src/DemoApplication.mjs index 7f9bde4c4..1ca682474 100644 --- a/examples/src/DemoApplication.mjs +++ b/examples/src/DemoApplication.mjs @@ -71,6 +71,7 @@ export default class DemoApplication extends PIXI.Application height: this.initHeight, autoStart: false, preference, + useBackBuffer: true, }); } diff --git a/examples/src/filters/backdropBlur.mjs b/examples/src/filters/backdropBlur.mjs new file mode 100644 index 000000000..14f9ec6ad --- /dev/null +++ b/examples/src/filters/backdropBlur.mjs @@ -0,0 +1,11 @@ +export default function () +{ + this.addFilter('BackdropBlurFilter', { + fishOnly: true, + oncreate(folder) + { + folder.add(this, 'blur', 0, 100); + folder.add(this, 'quality', 1, 10); + }, + }); +} diff --git a/examples/src/filters/index.mjs b/examples/src/filters/index.mjs index 393d09410..e294af188 100644 --- a/examples/src/filters/index.mjs +++ b/examples/src/filters/index.mjs @@ -4,6 +4,7 @@ export { default as adjustment } from './adjustment.mjs'; export { default as advancedBloom } from './advanced-bloom.mjs'; export { default as alpha } from './alpha.mjs'; export { default as ascii } from './ascii.mjs'; +export { default as backdropBlur } from './backdropBlur.mjs'; export { default as bevel } from './bevel.mjs'; export { default as bloom } from './bloom.mjs'; export { default as blur } from './blur.mjs'; diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts new file mode 100644 index 000000000..4997433df --- /dev/null +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -0,0 +1,93 @@ +import { + BlurFilter, + BlurFilterOptions, + Filter, + FilterSystem, + GlProgram, + GpuProgram, + RenderSurface, + Texture, + TexturePool, +} from 'pixi.js'; +import { vertex, wgslVertex } from '../defaults'; +import fragment from './backdrop-blur-blend.frag'; +import wgslFragment from './backdrop-blur-blend.wgsl'; + +export type BackdropBlurFilterOptions = BlurFilterOptions; + +/** + * The BackdropBlurFilter applies a Gaussian blur to everything behind an object, and then draws the object on top of it. + * + * @class + * @extends BlurFilter + * @see {@link https://www.npmjs.com/package/pixi-filters|pixi-filters} + */ +export class BackdropBlurFilter extends BlurFilter +{ + private _blendPass: Filter; + + /** + * @param options - The options of the blur filter. + * @param options.strength - The strength of the blur filter. + * @param options.quality - The quality of the blur filter. + * @param options.kernelSize - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. + */ + constructor(options?: BackdropBlurFilterOptions) + { + super(options); + + this.blendRequired = true; + this.padding = 0; + + this._blendPass = new Filter({ + gpuProgram: GpuProgram.from({ + vertex: { + source: wgslVertex, + entryPoint: 'mainVertex', + }, + fragment: { + source: wgslFragment, + entryPoint: 'mainFragment', + }, + }), + glProgram: GlProgram.from({ + vertex, + fragment, + name: 'drop-shadow-filter', + }), + resources: { + uBackground: Texture.EMPTY, + }, + }); + } + + /** + * Override existing apply method in `Filter` + * @override + * @ignore + */ + public apply( + filterManager: FilterSystem, + input: Texture, + output: RenderSurface, + clearMode: boolean + ): void + { + // @ts-expect-error - this should probably not be grabbed from a private property + const backTexture = filterManager._activeFilterData.backTexture; + + const blurredBackground = TexturePool.getSameSizeTexture(input); + + super.apply(filterManager, backTexture, blurredBackground, true); + + this._blendPass.resources.uBackground = blurredBackground.source; + this._blendPass.apply(filterManager, input, output, clearMode); + + TexturePool.returnTexture(blurredBackground); + } + + protected updatePadding(): void + { + this.padding = 0; + } +} diff --git a/src/backdrop-blur/backdrop-blur-blend.frag b/src/backdrop-blur/backdrop-blur-blend.frag new file mode 100644 index 000000000..675e13d5e --- /dev/null +++ b/src/backdrop-blur/backdrop-blur-blend.frag @@ -0,0 +1,19 @@ +precision highp float; +in vec2 vTextureCoord; +out vec4 finalColor; + +uniform sampler2D uTexture; +uniform sampler2D uBackground; + +void main(void){ + vec4 front = texture(uTexture, vTextureCoord); + vec4 back = texture(uBackground, vTextureCoord); + + if (front.a == 0.0) { + discard; + } + + vec3 color = mix(back.rgb, front.rgb / front.a, front.a); + + finalColor = vec4(color, 1.0); +} \ No newline at end of file diff --git a/src/backdrop-blur/backdrop-blur-blend.wgsl b/src/backdrop-blur/backdrop-blur-blend.wgsl new file mode 100644 index 000000000..8e3cfa931 --- /dev/null +++ b/src/backdrop-blur/backdrop-blur-blend.wgsl @@ -0,0 +1,20 @@ +@group(0) @binding(1) var uTexture: texture_2d; +@group(0) @binding(2) var uSampler: sampler; +@group(1) @binding(0) var uBackground: texture_2d; + +@fragment +fn mainFragment( + @builtin(position) position: vec4, + @location(0) uv : vec2 +) -> @location(0) vec4 { + var front: vec4 = textureSample(uTexture, uSampler, uv); + var back: vec4 = textureSample(uBackground, uSampler, uv); + + if (front.a == 0.0) { + discard; + } + + var color: vec3 = mix(back.rgb, front.rgb / front.a, front.a); + + return vec4(color, 1.0); +} \ No newline at end of file diff --git a/src/backdrop-blur/index.ts b/src/backdrop-blur/index.ts new file mode 100644 index 000000000..b075a9ded --- /dev/null +++ b/src/backdrop-blur/index.ts @@ -0,0 +1 @@ +export * from './BackdropBlurFilter'; diff --git a/src/index.ts b/src/index.ts index a2e85313e..3a96e4b4a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,7 @@ export * from './adjustment'; export * from './advanced-bloom'; export * from './ascii'; +export * from './backdrop-blur'; export * from './bevel'; export * from './bloom'; export * from './bulge-pinch';