From 8cdb31d46880ddc6424e20000c21693c6ebbf752 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 22 Feb 2024 12:21:26 +0100 Subject: [PATCH 1/7] Add backdrop blur filter --- src/backdrop-blur/BackdropBlurFilter.ts | 128 ++++++++++++++++++++++++ src/backdrop-blur/index.ts | 1 + src/index.ts | 1 + 3 files changed, 130 insertions(+) create mode 100644 src/backdrop-blur/BackdropBlurFilter.ts create mode 100644 src/backdrop-blur/index.ts diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts new file mode 100644 index 000000000..17af4da43 --- /dev/null +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -0,0 +1,128 @@ +import { + BlurFilter, + BlurFilterOptions, + Filter, + FilterSystem, + GlProgram, + GpuProgram, + RenderSurface, + Texture, + TexturePool, +} from 'pixi.js'; +import { vertex, wgslVertex } from '../defaults'; + +export type BackdropBlurFilterOptions = BlurFilterOptions; + +export class BackdropBlurFilter extends BlurFilter +{ + private _basePass: 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); + /** @deprecated since 8.0.0 */ + constructor(strength?: number, quality?: number, resolution?: number, kernelSize?: number); + constructor(...args: [BackdropBlurFilterOptions?] | [number?, number?, number?, number?]) + { + super(...(args as ConstructorParameters)); + + this.blendRequired = true; + this.padding = 0; + + this._basePass = new Filter({ + gpuProgram: GpuProgram.from({ + vertex: { + source: wgslVertex, + entryPoint: 'mainVertex', + }, + fragment: { + source: ` + @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); + } + `, + entryPoint: 'mainFragment', + }, + }), + glProgram: GlProgram.from({ + vertex, + fragment: ` + 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); + } + `, + name: 'drop-shadow-filter', + }), + resources: { + uBackground: Texture.EMPTY, + }, + }); + } + + /** + * Applies the filter. + * @param filterManager - The manager. + * @param input - The input target. + * @param output - The output target. + * @param clearMode - How to clear + */ + 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._basePass.resources.uBackground = blurredBackground.source; + this._basePass.apply(filterManager, input, output, clearMode); + + TexturePool.returnTexture(blurredBackground); + } + + protected updatePadding(): void + { + this.padding = 0; + } +} 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'; From 383de2d5f4844dbebb9cb776da0ab9bf1b5c4e66 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 22 Feb 2024 12:22:27 +0100 Subject: [PATCH 2/7] Add demo for backdrop blur filter --- examples/src/DemoApplication.mjs | 1 + examples/src/filters/backdropBlur.mjs | 11 +++++++++++ examples/src/filters/index.mjs | 1 + 3 files changed, 13 insertions(+) create mode 100644 examples/src/filters/backdropBlur.mjs 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'; From ea46220635630ba6a3601ace33ca293b85873725 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 22 Feb 2024 12:23:12 +0100 Subject: [PATCH 3/7] Rename backdrop filter `_basePass` to `_blendPass` --- src/backdrop-blur/BackdropBlurFilter.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts index 17af4da43..13623012a 100644 --- a/src/backdrop-blur/BackdropBlurFilter.ts +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -15,7 +15,7 @@ export type BackdropBlurFilterOptions = BlurFilterOptions; export class BackdropBlurFilter extends BlurFilter { - private _basePass: Filter; + private _blendPass: Filter; /** * @param options - The options of the blur filter. @@ -33,7 +33,7 @@ export class BackdropBlurFilter extends BlurFilter this.blendRequired = true; this.padding = 0; - this._basePass = new Filter({ + this._blendPass = new Filter({ gpuProgram: GpuProgram.from({ vertex: { source: wgslVertex, @@ -115,8 +115,8 @@ export class BackdropBlurFilter extends BlurFilter super.apply(filterManager, backTexture, blurredBackground, true); - this._basePass.resources.uBackground = blurredBackground.source; - this._basePass.apply(filterManager, input, output, clearMode); + this._blendPass.resources.uBackground = blurredBackground.source; + this._blendPass.apply(filterManager, input, output, clearMode); TexturePool.returnTexture(blurredBackground); } From 5c965671de23b9f3d12079c078b7c3315ccaaf27 Mon Sep 17 00:00:00 2001 From: Marvin Date: Thu, 22 Feb 2024 12:47:24 +0100 Subject: [PATCH 4/7] Add docs for BackdropBlurFilter class --- src/backdrop-blur/BackdropBlurFilter.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts index 13623012a..e15aae1e6 100644 --- a/src/backdrop-blur/BackdropBlurFilter.ts +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -13,6 +13,13 @@ import { vertex, wgslVertex } from '../defaults'; 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; From 06bbdb36810f2c8af6547f8a5317c3416aad27cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Thu, 22 Feb 2024 23:53:10 +0100 Subject: [PATCH 5/7] Remove deprecated constructor from `BackdropBlurFilter` --- src/backdrop-blur/BackdropBlurFilter.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts index e15aae1e6..256192f88 100644 --- a/src/backdrop-blur/BackdropBlurFilter.ts +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -30,12 +30,9 @@ export class BackdropBlurFilter extends BlurFilter * @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); - /** @deprecated since 8.0.0 */ - constructor(strength?: number, quality?: number, resolution?: number, kernelSize?: number); - constructor(...args: [BackdropBlurFilterOptions?] | [number?, number?, number?, number?]) + constructor(options?: BackdropBlurFilterOptions) { - super(...(args as ConstructorParameters)); + super(options); this.blendRequired = true; this.padding = 0; From 562327f05c5cf9db3df5ab5ff87582bec4089a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Thu, 22 Feb 2024 23:55:03 +0100 Subject: [PATCH 6/7] Fix up doc comment for `BackdropBlurFilter.apply` --- src/backdrop-blur/BackdropBlurFilter.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts index 256192f88..735888387 100644 --- a/src/backdrop-blur/BackdropBlurFilter.ts +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -99,12 +99,10 @@ export class BackdropBlurFilter extends BlurFilter } /** - * Applies the filter. - * @param filterManager - The manager. - * @param input - The input target. - * @param output - The output target. - * @param clearMode - How to clear - */ + * Override existing apply method in `Filter` + * @override + * @ignore + */ public apply( filterManager: FilterSystem, input: Texture, From 2f0f309016bf607ca833e191a5dbe1ec37afdc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Fri, 23 Feb 2024 00:06:02 +0100 Subject: [PATCH 7/7] Extract blend filters into separate files for `BackdropBlurFilter` --- src/backdrop-blur/BackdropBlurFilter.ts | 45 ++-------------------- src/backdrop-blur/backdrop-blur-blend.frag | 19 +++++++++ src/backdrop-blur/backdrop-blur-blend.wgsl | 20 ++++++++++ 3 files changed, 43 insertions(+), 41 deletions(-) create mode 100644 src/backdrop-blur/backdrop-blur-blend.frag create mode 100644 src/backdrop-blur/backdrop-blur-blend.wgsl diff --git a/src/backdrop-blur/BackdropBlurFilter.ts b/src/backdrop-blur/BackdropBlurFilter.ts index 735888387..4997433df 100644 --- a/src/backdrop-blur/BackdropBlurFilter.ts +++ b/src/backdrop-blur/BackdropBlurFilter.ts @@ -10,6 +10,8 @@ import { 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; @@ -44,52 +46,13 @@ export class BackdropBlurFilter extends BlurFilter entryPoint: 'mainVertex', }, fragment: { - source: ` - @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); - } - `, + source: wgslFragment, entryPoint: 'mainFragment', }, }), glProgram: GlProgram.from({ vertex, - fragment: ` - 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); - } - `, + fragment, name: 'drop-shadow-filter', }), resources: { 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