Skip to content

Commit

Permalink
Update Glow Filter
Browse files Browse the repository at this point in the history
  • Loading branch information
bbazukun123 committed Dec 30, 2023
1 parent a287d90 commit 194450d
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 139 deletions.
225 changes: 126 additions & 99 deletions filters/glow/src/GlowFilter.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,50 @@
import { vertex } from '@tools/fragments';
import { vertex, wgslVertex } from '@tools/fragments';
import fragment from './glow.frag';
import { Filter, GlProgram } from 'pixi.js';
import source from './glow.wgsl';
import { Color, ColorSource, Filter, GlProgram, GpuProgram, UniformGroup } from 'pixi.js';

interface GlowFilterOptions
/**
* This WebGPU filter has been ported from the WebGL renderer that was originally created by mishaa
* http://codepen.io/mishaa/pen/raKzrm
*/

export interface GlowFilterOptions
{
distance: number;
outerStrength: number;
innerStrength: number;
color: number;
quality: number;
knockout: boolean;
alpha: number;
/**
* The distance of the glow
* @default 10
*/
distance?: number;
/**
* The strength of the glow outward from the edge of the sprite
* @default 4
*/
outerStrength?: number;
/**
* The strength of the glow inward from the edge of the sprite
* @default 0
*/
innerStrength?: number;
/**
* The color of the glow
* @default 0xffffff
*/
color?: ColorSource;
/**
* The alpha of the glow
* @default 1
*/
alpha?: number;
/**
* A number between 0 and 1 that describes the quality of the glow. The higher the number the less performant
* @default 0.1
*/
quality?: number;
/**
* Toggle to hide the contents and only show glow
* @default false
*/
knockout?: boolean;
}

/**
Expand All @@ -31,40 +65,50 @@ interface GlowFilterOptions
export class GlowFilter extends Filter
{
/** Default values for options. */
static readonly defaults: GlowFilterOptions = {
public static readonly DEFAULT_OPTIONS: GlowFilterOptions = {
distance: 10,
outerStrength: 4,
innerStrength: 0,
color: 0xffffff,
alpha: 1,
quality: 0.1,
knockout: false,
alpha: 1,
};

/**
* @param {number} [options] - Options for glow.
* @param {number} [options.distance=10] - The distance of the glow. Make it 2 times more for resolution=2.
* It can't be changed after filter creation.
* @param {number} [options.outerStrength=4] - The strength of the glow outward from the edge of the sprite.
* @param {number} [options.innerStrength=0] - The strength of the glow inward from the edge of the sprite.
* @param {number} [options.color=0xffffff] - The color of the glow.
* @param {number} [options.quality=0.1] - A number between 0 and 1 that describes the quality of the glow.
* The higher the number the less performant.
* @param {boolean} [options.knockout=false] - Toggle to hide the contents and only show glow.
*/
constructor(options?: Partial<GlowFilterOptions>)
private _color: Color;

constructor(options?: GlowFilterOptions)
{
const opts: GlowFilterOptions = Object.assign({}, GlowFilter.defaults, options);
const {
outerStrength,
innerStrength,
color,
knockout,
quality,
alpha } = opts;
options = { ...GlowFilter.DEFAULT_OPTIONS, ...options };

const distance = Math.round(opts.distance);
const distance = options.distance ?? 10;
const quality = options.quality ?? 0.1;

const glowUniforms = new UniformGroup({
uDistance: { value: distance, type: 'f32' },
uStrength: { value: [options.innerStrength, options.outerStrength], type: 'vec2<f32>' },
uColor: { value: new Float32Array(3), type: 'vec3<f32>' },
uAlpha: { value: options.alpha, type: 'f32' },
uQuality: { value: quality, type: 'f32' },
uKnockout: { value: (options?.knockout ?? false) ? 1 : 0, type: 'f32' },
});

const gpuProgram = new GpuProgram({
vertex: {
source: wgslVertex,
entryPoint: 'mainVertex',
},
fragment: {
source,
entryPoint: 'mainFragment',
},
});

/**
* Altering uDistance and uQuality won't have any affect on WebGL
* since we hard-assign them during creation to allow
* for the values to be used in GLSL loops
*/
const glProgram = new GlProgram({
vertex,
fragment: fragment
Expand All @@ -74,85 +118,68 @@ export class GlowFilter extends Filter
});

super({
gpuProgram,
glProgram,
resources: {},
});

// this.uniforms.glowColor = new Float32Array([0, 0, 0, 1]);
// this.uniforms.alpha = 1;

Object.assign(this, {
color,
outerStrength,
innerStrength,
resources: {
glowUniforms
},
padding: distance,
knockout,
alpha,
});

this._color = new Color();
this.color = options.color ?? 0xffffff;
}

/**
* The color of the glow.
* @default 0xFFFFFF
* Only draw the glow, not the texture itself
* @default false
*/
// get color(): number
// {
// return utils.rgb2hex(this.uniforms.glowColor);
// }
// set color(value: number)
// {
// utils.hex2rgb(value, this.uniforms.glowColor);
// }
get distance(): number { return this.resources.glowUniforms.uniforms.uDistance; }
set distance(value: number) { this.resources.glowUniforms.uniforms.uDistance = this.padding = value; }

/**
* The strength of the glow outward from the edge of the sprite.
* @default 4
*/
// get outerStrength(): number
// {
// return this.uniforms.outerStrength;
// }
// set outerStrength(value: number)
// {
// this.uniforms.outerStrength = value;
// }
* The strength of the glow inward from the edge of the sprite.
* @default 0
*/
get innerStrength(): number { return this.resources.glowUniforms.uniforms.uStrength[0]; }
set innerStrength(value: number) { this.resources.glowUniforms.uniforms.uStrength[0] = value; }

/**
* The strength of the glow inward from the edge of the sprite.
* @default 0
*/
// get innerStrength(): number
// {
// return this.uniforms.innerStrength;
// }
// set innerStrength(value: number)
// {
// this.uniforms.innerStrength = value;
// }
* The strength of the glow outward from the edge of the sprite.
* @default 4
*/
get outerStrength(): number { return this.resources.glowUniforms.uniforms.uStrength[1]; }
set outerStrength(value: number) { this.resources.glowUniforms.uniforms.uStrength[1] = value; }

/**
* Only draw the glow, not the texture itself
* @default false
*/
// get knockout(): boolean
// {
// return this.uniforms.knockout;
// }
// set knockout(value: boolean)
// {
// this.uniforms.knockout = value;
// }
* The color of the glow.
* @default 0xFFFFFF
*/
get color(): ColorSource { return this._color.value as ColorSource; }
set color(value: ColorSource)
{
this._color.setValue(value);
this.resources.glowUniforms.uniforms.uColor = this._color.toArray().slice(0, 3);
}

/**
* The alpha value of the glow
* @default 1
*/
// get alpha(): number
// {
// return this.uniforms.alpha;
// }
// set alpha(value: number)
// {
// this.uniforms.alpha = value;
// }
* The alpha of the glow
* @default 1
*/
get alpha(): number { return this.resources.glowUniforms.uniforms.uAlpha; }
set alpha(value: number) { this.resources.glowUniforms.uniforms.uAlpha = value; }

/**
* A number between 0 and 1 that describes the quality of the glow. The higher the number the less performant
* @default 0.1
*/
get quality(): number { return this.resources.glowUniforms.uniforms.uQuality; }
set quality(value: number) { this.resources.glowUniforms.uniforms.uQuality = value; }

/**
* Only draw the glow, not the texture itself
* @default false
*/
get knockout(): boolean { return this.resources.glowUniforms.uniforms.uKnockout === 1; }
set knockout(value: boolean) { this.resources.glowUniforms.uniforms.uKnockout = value ? 1 : 0; }
}
74 changes: 36 additions & 38 deletions filters/glow/src/glow.frag
Original file line number Diff line number Diff line change
@@ -1,66 +1,64 @@
varying vec2 vTextureCoord;
varying vec4 vColor;
precision highp float;
in vec2 vTextureCoord;
out vec4 finalColor;

uniform sampler2D uSampler;
uniform vec2 uStrength;
uniform vec3 uColor;
uniform float uKnockout;
uniform float uAlpha;

uniform float outerStrength;
uniform float innerStrength;

uniform vec4 glowColor;

uniform vec4 filterArea;
uniform vec4 filterClamp;
uniform bool knockout;
uniform float alpha;
uniform vec4 uInputSize;
uniform vec4 uInputClamp;

const float PI = 3.14159265358979323846264;

// Hard-assignment of DIST and ANGLE_STEP_SIZE instead of using uDistance and uQuality to allow them to be use on GLSL loop conditions
const float DIST = __DIST__;
const float ANGLE_STEP_SIZE = min(__ANGLE_STEP_SIZE__, PI * 2.0);
const float ANGLE_STEP_NUM = ceil(PI * 2.0 / ANGLE_STEP_SIZE);

const float MAX_TOTAL_ALPHA = ANGLE_STEP_NUM * DIST * (DIST + 1.0) / 2.0;
const float ANGLE_STEP_SIZE = min(__ANGLE_STEP_SIZE__, PI * 2.);
const float ANGLE_STEP_NUM = ceil(PI * 2. / ANGLE_STEP_SIZE);
const float MAX_TOTAL_ALPHA = ANGLE_STEP_NUM * DIST * (DIST + 1.) / 2.;

void main(void) {
vec2 px = vec2(1.0 / filterArea.x, 1.0 / filterArea.y);
vec2 px = vec2(1.) / uInputSize.xy;

float totalAlpha = 0.0;
float totalAlpha = 0.;

vec2 direction;
vec2 displaced;
vec4 curColor;

for (float angle = 0.0; angle < PI * 2.0; angle += ANGLE_STEP_SIZE) {
direction = vec2(cos(angle), sin(angle)) * px;
for (float angle = 0.; angle < PI * 2.; angle += ANGLE_STEP_SIZE) {
direction = vec2(cos(angle), sin(angle)) * px;

for (float curDistance = 0.0; curDistance < DIST; curDistance++) {
displaced = clamp(vTextureCoord + direction *
(curDistance + 1.0), filterClamp.xy, filterClamp.zw);

curColor = texture2D(uSampler, displaced);

totalAlpha += (DIST - curDistance) * curColor.a;
}
for (float curDistance = 0.; curDistance < DIST; curDistance++) {
displaced = clamp(vTextureCoord + direction * (curDistance + 1.), uInputClamp.xy, uInputClamp.zw);
curColor = texture(uSampler, displaced);
totalAlpha += (DIST - curDistance) * curColor.a;
}
}

curColor = texture2D(uSampler, vTextureCoord);
curColor = texture(uSampler, vTextureCoord);

float alphaRatio = (totalAlpha / MAX_TOTAL_ALPHA);
vec4 glowColor = vec4(uColor, uAlpha);
bool knockout = uKnockout > .5;
float innerStrength = uStrength[0];
float outerStrength = uStrength[1];

float innerGlowAlpha = (1.0 - alphaRatio) * innerStrength * curColor.a;
float innerGlowStrength = min(1.0, innerGlowAlpha);
float alphaRatio = totalAlpha / MAX_TOTAL_ALPHA;
float innerGlowAlpha = (1. - alphaRatio) * innerStrength * curColor.a * uAlpha;
float innerGlowStrength = min(1., innerGlowAlpha);

vec4 innerColor = mix(curColor, glowColor, innerGlowStrength);

float outerGlowAlpha = alphaRatio * outerStrength * (1. - curColor.a);
float outerGlowStrength = min(1.0 - innerColor.a, outerGlowAlpha);
float outerGlowAlpha = alphaRatio * outerStrength * (1. - curColor.a) * uAlpha;
float outerGlowStrength = min(1. - innerColor.a, outerGlowAlpha);
vec4 outerGlowColor = outerGlowStrength * glowColor.rgba;

if (knockout) {
float resultAlpha = (outerGlowAlpha + innerGlowAlpha) * alpha;
gl_FragColor = vec4(glowColor.rgb * resultAlpha, resultAlpha);
float resultAlpha = outerGlowAlpha + innerGlowAlpha;
finalColor = vec4(glowColor.rgb * resultAlpha, resultAlpha);
}
else {
vec4 outerGlowColor = outerGlowStrength * glowColor.rgba * alpha;
gl_FragColor = innerColor + outerGlowColor;
finalColor = innerColor + outerGlowColor;
}
}
Loading

0 comments on commit 194450d

Please sign in to comment.