From bc896d2ed21f92ca6c36f6661b51bec5bcba38b1 Mon Sep 17 00:00:00 2001 From: Baz Utsahajit Date: Sat, 30 Dec 2023 16:25:02 +0000 Subject: [PATCH] Update Twist Filterr --- filters/adjustment/src/AdjustmentFilter.ts | 11 -- filters/twist/src/TwistFilter.ts | 126 +++++++++++++-------- filters/twist/src/twist.frag | 38 +++---- filters/twist/src/twist.wgsl | 47 ++++++++ tools/demo/src/filters/twist.js | 9 +- tools/demo/src/index.js | 1 + 6 files changed, 147 insertions(+), 85 deletions(-) create mode 100644 filters/twist/src/twist.wgsl diff --git a/filters/adjustment/src/AdjustmentFilter.ts b/filters/adjustment/src/AdjustmentFilter.ts index bd7ccf5a9..cad085fe0 100644 --- a/filters/adjustment/src/AdjustmentFilter.ts +++ b/filters/adjustment/src/AdjustmentFilter.ts @@ -73,17 +73,6 @@ export class AdjustmentFilter extends Filter alpha: 1, }; - /** - * @param {object|number} [options] - The optional parameters of the filter. - * @param {number} [options.gamma=1] - The amount of luminance - * @param {number} [options.saturation=1] - The amount of color saturation - * @param {number} [options.contrast=1] - The amount of contrast - * @param {number} [options.brightness=1] - The overall brightness - * @param {number} [options.red=1] - The multipled red channel - * @param {number} [options.green=1] - The multipled green channel - * @param {number} [options.blue=1] - The multipled blue channel - * @param {number} [options.alpha=1] - The overall alpha amount - */ constructor(options?: AdjustmentFilterOptions) { options = { ...AdjustmentFilter.DEFAULT_OPTIONS, ...options }; diff --git a/filters/twist/src/TwistFilter.ts b/filters/twist/src/TwistFilter.ts index 352abfda9..d64fcd294 100644 --- a/filters/twist/src/TwistFilter.ts +++ b/filters/twist/src/TwistFilter.ts @@ -1,13 +1,32 @@ -import { vertex } from '@tools/fragments'; +import { vertex, wgslVertex } from '@tools/fragments'; import fragment from './twist.frag'; -import { Filter, GlProgram, Point } from 'pixi.js'; +import source from './twist.wgsl'; +import { Filter, GlProgram, GpuProgram, Point, UniformGroup } from 'pixi.js'; -interface TwistFilterOptions +export interface TwistFilterOptions { - radius: number; - angle: number; - padding: number; - offset: Point; + /** + * Padding for the filter area + * @default 20 + */ + padding?: number; + /** + * The radius of the twist + * @default 200 + */ + radius?: number; + /** + * The angle of the twist + * @default 4 + */ + angle?: number; + /** + * The `x` and `y` offset coordinates to change the position of the center of the circle of effect. + * This should be a size 2 array or an object containing `x` and `y` values, you cannot change types + * once defined in the constructor + * @default { x: 0, y: 0} + */ + offset?: Point; } /** @@ -21,23 +40,40 @@ interface TwistFilterOptions */ export class TwistFilter extends Filter { - /** Default constructor options. */ - public static readonly defaults: TwistFilterOptions = { + /** Default values for options. */ + public static readonly DEFAULT_OPTIONS: TwistFilterOptions = { + padding: 20, radius: 200, angle: 4, - padding: 20, offset: new Point(), }; - /** - * @param {object} [options] - Object object to use. - * @param {number} [options.radius=200] - The radius of the twist. - * @param {number} [options.angle=4] - The angle of the twist. - * @param {number} [options.padding=20] - Padding for filter area. - * @param {Point} [options.offset] - Center of twist, in local, pixel coordinates. - */ constructor(options?: Partial) { + options = { ...TwistFilter.DEFAULT_OPTIONS, ...options }; + + const twistUniforms = new UniformGroup({ + uTwist: { + value: [options.radius ?? 0, options.angle ?? 0], + type: 'vec2' + }, + uOffset: { + value: [options.offset?.x ?? 0, options.offset?.y ?? 0], + type: 'vec2' + }, + }); + + const gpuProgram = new GpuProgram({ + vertex: { + source: wgslVertex, + entryPoint: 'mainVertex', + }, + fragment: { + source, + entryPoint: 'mainFragment', + }, + }); + const glProgram = new GlProgram({ vertex, fragment, @@ -45,48 +81,40 @@ export class TwistFilter extends Filter }); super({ + gpuProgram, glProgram, - resources: {}, + resources: { + twistUniforms + }, + ...options, }); - - Object.assign(this, TwistFilter.defaults, options); } /** - * This point describes the the offset of the twist. - * - * @member {Point} + * The radius of the twist + * @default 200 + */ + get radius(): number { return this.resources.twistUniforms.uniforms.uTwist[0]; } + set radius(value: number) { this.resources.twistUniforms.uniforms.uTwist[0] = value; } + + /** + * The angle of the twist + * @default 4 */ - // get offset(): Point - // { - // return this.uniforms.offset; - // } - // set offset(value: Point) - // { - // this.uniforms.offset = value; - // } + get angle(): number { return this.resources.twistUniforms.uniforms.uTwist[1]; } + set angle(value: number) { this.resources.twistUniforms.uniforms.uTwist[1] = value; } /** - * The radius of the twist. + * The `x` offset coordinate to change the position of the center of the circle of effect + * @default 0 */ - // get radius(): number - // { - // return this.uniforms.radius; - // } - // set radius(value: number) - // { - // this.uniforms.radius = value; - // } + get offsetX(): number { return this.resources.twistUniforms.uniforms.uOffset[0]; } + set offsetX(value: number) { this.resources.twistUniforms.uniforms.uOffset[0] = value; } /** - * The angle of the twist. + * The `y` offset coordinate to change the position of the center of the circle of effect + * @default 0 */ - // get angle(): number - // { - // return this.uniforms.angle; - // } - // set angle(value: number) - // { - // this.uniforms.angle = value; - // } + get offsetY(): number { return this.resources.twistUniforms.uniforms.uOffset[1]; } + set offsetY(value: number) { this.resources.twistUniforms.uniforms.uOffset[1] = value; } } diff --git a/filters/twist/src/twist.frag b/filters/twist/src/twist.frag index 22e1b005f..cfaf71cf7 100644 --- a/filters/twist/src/twist.frag +++ b/filters/twist/src/twist.frag @@ -1,56 +1,54 @@ -varying vec2 vTextureCoord; +precision highp float; +in vec2 vTextureCoord; +out vec4 finalColor; uniform sampler2D uSampler; -uniform float radius; -uniform float angle; -uniform vec2 offset; -uniform vec4 filterArea; +uniform vec2 uTwist; +uniform vec2 uOffset; +uniform vec4 uInputSize; vec2 mapCoord( vec2 coord ) { - coord *= filterArea.xy; - coord += filterArea.zw; + coord *= uInputSize.xy; + coord += uInputSize.zw; return coord; } vec2 unmapCoord( vec2 coord ) { - coord -= filterArea.zw; - coord /= filterArea.xy; + coord -= uInputSize.zw; + coord /= uInputSize.xy; return coord; } vec2 twist(vec2 coord) { - coord -= offset; + coord -= uOffset; float dist = length(coord); + float uRadius = uTwist[0]; + float uAngle = uTwist[1]; - if (dist < radius) + if (dist < uRadius) { - float ratioDist = (radius - dist) / radius; - float angleMod = ratioDist * ratioDist * angle; + float ratioDist = (uRadius - dist) / uRadius; + float angleMod = ratioDist * ratioDist * uAngle; float s = sin(angleMod); float c = cos(angleMod); coord = vec2(coord.x * c - coord.y * s, coord.x * s + coord.y * c); } - coord += offset; + coord += uOffset; return coord; } void main(void) { - vec2 coord = mapCoord(vTextureCoord); - coord = twist(coord); - coord = unmapCoord(coord); - - gl_FragColor = texture2D(uSampler, coord ); - + finalColor = texture(uSampler, coord); } diff --git a/filters/twist/src/twist.wgsl b/filters/twist/src/twist.wgsl new file mode 100644 index 000000000..1da9102fd --- /dev/null +++ b/filters/twist/src/twist.wgsl @@ -0,0 +1,47 @@ +struct TwistUniforms { + uTwist:vec2, + uOffset:vec2, +}; + +@group(0) @binding(1) var uSampler: texture_2d; +@group(1) @binding(0) var twistUniforms : TwistUniforms; + +@fragment +fn mainFragment( + @location(0) uv: vec2, + @builtin(position) position: vec4 +) -> @location(0) vec4 { + return textureSample(uSampler, uSampler, unmapCoord(twist(mapCoord(uv)))); +} + +fn unmapCoord(coord: vec2 ) -> vec2 +{ + var mappedCoord: vec2 = coord; + mappedCoord -= gfu.outputFrame.xy; + mappedCoord /= gfu.inputSize.xy; + return mappedCoord; +} + +fn twist(coord: vec2) -> vec2 +{ + var twistedCoord: vec2 = coord; + let uRadius = twistUniforms.uTwist[0]; + let uAngle = twistUniforms.uTwist[1]; + let uOffset = twistUniforms.uOffset; + + twistedCoord -= uOffset; + + let dist = length(twistedCoord); + + if (dist < uRadius) + { + let ratioDist: f32 = (uRadius - dist) / uRadius; + let angleMod: f32 = ratioDist * ratioDist * uAngle; + let s: f32 = sin(angleMod); + let c: f32 = cos(angleMod); + twistedCoord = vec2(twistedCoord.x * c - twistedCoord.y * s, twistedCoord.x * s + twistedCoord.y * c); + } + + twistedCoord += uOffset; + return twistedCoord; +} diff --git a/tools/demo/src/filters/twist.js b/tools/demo/src/filters/twist.js index e7fbe0a17..d4efada34 100644 --- a/tools/demo/src/filters/twist.js +++ b/tools/demo/src/filters/twist.js @@ -1,15 +1,14 @@ -import { Point } from 'pixi.js'; - export default function () { const app = this; this.addFilter('TwistFilter', function (folder) { - this.offset = new Point(app.initWidth / 2, app.initHeight / 2); + this.offsetX = app.initWidth / 2; + this.offsetY = app.initHeight / 2; folder.add(this, 'angle', -10, 10); folder.add(this, 'radius', 0, app.initWidth); - folder.add(this.offset, 'x', 0, app.initWidth); - folder.add(this.offset, 'y', 0, app.initHeight); + folder.add(this, 'offsetX', 0, app.initWidth); + folder.add(this, 'offsetY', 0, app.initHeight); }); } diff --git a/tools/demo/src/index.js b/tools/demo/src/index.js index 24cd98613..b4c2a112c 100644 --- a/tools/demo/src/index.js +++ b/tools/demo/src/index.js @@ -35,6 +35,7 @@ const main = async () => filters.adjustment.call(app); filters.bloom.call(app); filters.grayscale.call(app); + filters.twist.call(app); // filters.kawaseBlur.call(app); // TODO: Re-enable this in place of the above once v8 conversion is complete