Skip to content

Commit

Permalink
Update Reflection Filter
Browse files Browse the repository at this point in the history
  • Loading branch information
bbazukun123 committed Jan 3, 2024
1 parent f4b0691 commit 0076c3f
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 117 deletions.
246 changes: 160 additions & 86 deletions filters/reflection/src/ReflectionFilter.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
import { vertex } from '@tools/fragments';
import { vertex, wgslVertex } from '@tools/fragments';
import fragment from './reflection.frag';
import { Filter, GlProgram } from 'pixi.js';
import source from './reflection.wgsl';
import { Filter, GlProgram, GpuProgram } from 'pixi.js';
import type { FilterSystem, RenderSurface, Texture } from 'pixi.js';

type Range = number[] | Float32Array;
/** [MIN, MAX] */
type Range = [number, number];

export interface ReflectionFilterOptions
{
mirror: boolean;
boundary: number;
amplitude: Range;
waveLength: Range;
alpha: Range;
time: number;
/**
* `true` to reflect the image, `false` for waves-only
* @default true
*/
mirror?: boolean;
/**
* Vertical position of the reflection point, `0.5` equates to the middle
* smaller numbers produce a larger reflection, larger numbers produce a smaller reflection
* @default 0.5
*/
boundary?: number;
/**
* Starting and ending amplitude of waves
* @default [0,20]
*/
amplitude?: Range;
/**
* Starting and ending length of waves
* @default [30,100]
*/
waveLength?: Range;
/**
* Starting and ending alpha values
* @default [1,1]
*/
alpha?: Range;
/**
* Time for animating position of waves
* @default 0
*/
time?: number;
}

/**
Expand All @@ -26,8 +53,8 @@ export interface ReflectionFilterOptions
*/
export class ReflectionFilter extends Filter
{
/** Default constructor options */
public static readonly defaults: ReflectionFilterOptions = {
/** Default values for options. */
public static readonly DEFAULT_OPTIONS: ReflectionFilterOptions = {
mirror: true,
boundary: 0.5,
amplitude: [0, 20],
Expand All @@ -36,123 +63,170 @@ export class ReflectionFilter extends Filter
time: 0,
};

/** Time for animating position of waves */
public time = 0;
public uniforms: {
uMirror: number;
uBoundary: number;
uAmplitude: Float32Array;
uWavelength: Float32Array;
uAlpha: Float32Array;
uTime: number;
uDimensions: Float32Array;
};

/**
* @param {object} [options] - The optional parameters of Reflection effect.
* @param {number} [options.mirror=true] - `true` to reflect the image, `false` for waves-only
* @param {number} [options.boundary=0.5] - Vertical position of the reflection point, default is 50% (middle)
* smaller numbers produce a larger reflection, larger numbers produce a smaller reflection.
* @param {number} [options.amplitude=[0, 20]] - Starting and ending amplitude of waves
* @param {number} [options.waveLength=[30, 100]] - Starting and ending length of waves
* @param {number} [options.alpha=[1, 1]] - Starting and ending alpha values
* @param {number} [options.time=0] - Time for animating position of waves
*/
constructor(options?: Partial<ReflectionFilterOptions>)
* Time for animating position of waves
* @default 0
*/
public time = 0;

constructor(options?: ReflectionFilterOptions)
{
options = { ...ReflectionFilter.DEFAULT_OPTIONS, ...options };

const gpuProgram = new GpuProgram({
vertex: {
source: wgslVertex,
entryPoint: 'mainVertex',
},
fragment: {
source,
entryPoint: 'mainFragment',
},
});
const glProgram = new GlProgram({
vertex,
fragment,
name: 'reflection-filter',
});

super({
gpuProgram,
glProgram,
resources: {},
resources: {
reflectionUniforms: {
uMirror: { value: options.mirror ? 1 : 0, type: 'f32' },
uBoundary: { value: options.boundary, type: 'f32' },
uAmplitude: { value: options.amplitude, type: 'vec2<f32>' },
uWavelength: { value: options.waveLength, type: 'vec2<f32>' },
uAlpha: { value: options.alpha, type: 'vec2<f32>' },
uTime: { value: options.time, type: 'f32' },
uDimensions: { value: new Float32Array(2), type: 'vec2<f32>' },
}
},
});

// this.uniforms.amplitude = new Float32Array(2);
// this.uniforms.waveLength = new Float32Array(2);
// this.uniforms.alpha = new Float32Array(2);
// this.uniforms.dimensions = new Float32Array(2);
this.uniforms = this.resources.reflectionUniforms.uniforms;

Object.assign(this, ReflectionFilter.defaults, options);
Object.assign(this, options);
}

/**
* Override existing apply method in Filter
* @private
* Override existing apply method in `Filter`
* @override
* @ignore
*/
apply(filterManager: FilterSystem, input: Texture, output: RenderSurface, clear: boolean): void
public override apply(
filterManager: FilterSystem,
input: Texture,
output: RenderSurface,
clearMode: boolean
): void
{
// this.uniforms.dimensions[0] = input.filterFrame?.width;
// this.uniforms.dimensions[1] = input.filterFrame?.height;
this.uniforms.uDimensions[0] = input.frame.width;
this.uniforms.uDimensions[1] = input.frame.height;

// this.uniforms.time = this.time;
this.uniforms.uTime = this.time;

// filterManager.applyFilter(this, input, output, clear);
filterManager.applyFilter(this, input, output, clearMode);
}

/**
* `true` to reflect the image, `false` for waves-only
* @default true
*/
// set mirror(value: boolean)
// {
// this.uniforms.mirror = value;
// }
// get mirror(): boolean
// {
// return this.uniforms.mirror;
// }
get mirror(): boolean { return this.uniforms.uMirror > 0.5; }
set mirror(value: boolean) { this.uniforms.uMirror = value ? 1 : 0; }

/**
* Vertical position of the reflection point, default is 50% (middle)
* smaller numbers produce a larger reflection, larger numbers produce a smaller reflection.
* @default 0.5
*/
// set boundary(value: number)
// {
// this.uniforms.boundary = value;
// }
// get boundary(): number
// {
// return this.uniforms.boundary;
// }
get boundary(): number { return this.uniforms.uBoundary; }
set boundary(value: number) { this.uniforms.uBoundary = value; }

/**
* Starting and ending amplitude of waves
* @member {number[]}
* @default [0, 20]
* @default [0,20]
*/
// set amplitude(value: Range)
// {
// this.uniforms.amplitude[0] = value[0];
// this.uniforms.amplitude[1] = value[1];
// }
// get amplitude(): Range
// {
// return this.uniforms.amplitude;
// }
get amplitude(): Range { return Array.from(this.uniforms.uAmplitude) as Range; }
set amplitude(value: Range)
{
this.uniforms.uAmplitude[0] = value[0];
this.uniforms.uAmplitude[1] = value[1];
}

/**
* Starting amplitude of waves
* @default 0
*/
get amplitudeStart(): number { return this.uniforms.uAmplitude[0]; }
set amplitudeStart(value: number) { this.uniforms.uAmplitude[0] = value; }

/**
* Starting amplitude of waves
* @default 20
*/
get amplitudeEnd(): number { return this.uniforms.uAmplitude[1]; }
set amplitudeEnd(value: number) { this.uniforms.uAmplitude[1] = value; }

/**
* Starting and ending length of waves
* @member {number[]}
* @default [30, 100]
* @default [30,100]
*/
get waveLength(): Range { return Array.from(this.uniforms.uWavelength) as Range; }
set waveLength(value: Range)
{
this.uniforms.uWavelength[0] = value[0];
this.uniforms.uWavelength[1] = value[1];
}

/**
* Starting wavelength of waves
* @default 30
*/
// set waveLength(value: Range)
// {
// this.uniforms.waveLength[0] = value[0];
// this.uniforms.waveLength[1] = value[1];
// }
// get waveLength(): Range
// {
// return this.uniforms.waveLength;
// }
get wavelengthStart(): number { return this.uniforms.uWavelength[0]; }
set wavelengthStart(value: number) { this.uniforms.uWavelength[0] = value; }

/**
* Starting wavelength of waves
* @default 100
*/
get wavelengthEnd(): number { return this.uniforms.uWavelength[1]; }
set wavelengthEnd(value: number) { this.uniforms.uWavelength[1] = value; }

/**
* Starting and ending alpha values
* @member {number[]}
* @default [1, 1]
*/
// set alpha(value: Range)
// {
// this.uniforms.alpha[0] = value[0];
// this.uniforms.alpha[1] = value[1];
// }
// get alpha(): Range
// {
// return this.uniforms.alpha;
// }
* @default [1,1]
*/
get alpha(): Range { return Array.from(this.uniforms.uAlpha) as Range; }
set alpha(value: Range)
{
this.uniforms.uAlpha[0] = value[0];
this.uniforms.uAlpha[1] = value[1];
}

/**
* Starting wavelength of waves
* @default 1
*/
get alphaStart(): number { return this.uniforms.uAlpha[0]; }
set alphaStart(value: number) { this.uniforms.uAlpha[0] = value; }

/**
* Starting wavelength of waves
* @default 1
*/
get alphaEnd(): number { return this.uniforms.uAlpha[1]; }
set alphaEnd(value: number) { this.uniforms.uAlpha[1] = value; }
}
52 changes: 27 additions & 25 deletions filters/reflection/src/reflection.frag
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
precision highp float;
in vec2 vTextureCoord;
out vec4 finalColor;

uniform vec4 filterArea;
uniform vec4 filterClamp;
uniform vec2 dimensions;
uniform sampler2D uSampler;
uniform float uMirror;
uniform float uBoundary;
uniform vec2 uAmplitude;
uniform vec2 uWavelength;
uniform vec2 uAlpha;
uniform float uTime;
uniform vec2 uDimensions;

uniform bool mirror;
uniform float boundary;
uniform vec2 amplitude;
uniform vec2 waveLength;
uniform vec2 alpha;
uniform float time;
uniform vec4 uInputSize;
uniform vec4 uInputClamp;

float rand(vec2 co) {
return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
}

void main(void)
{
vec2 pixelCoord = vTextureCoord.xy * filterArea.xy;
vec2 coord = pixelCoord / dimensions;
vec2 pixelCoord = vTextureCoord.xy * uInputSize.xy;
vec2 coord = pixelCoord / uDimensions;

if (coord.y < boundary) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
if (coord.y < uBoundary) {
finalColor = texture(uSampler, vTextureCoord);
return;
}

float k = (coord.y - boundary) / (1. - boundary + 0.0001);
float areaY = boundary * dimensions.y / filterArea.y;
float k = (coord.y - uBoundary) / (1. - uBoundary + 0.0001);
float areaY = uBoundary * uDimensions.y / uInputSize.y;
float v = areaY + areaY - vTextureCoord.y;
float y = mirror ? v : vTextureCoord.y;
float y = uMirror > 0.5 ? v : vTextureCoord.y;

float _amplitude = ((amplitude.y - amplitude.x) * k + amplitude.x ) / filterArea.x;
float _waveLength = ((waveLength.y - waveLength.x) * k + waveLength.x) / filterArea.y;
float _alpha = (alpha.y - alpha.x) * k + alpha.x;
float _amplitude = ((uAmplitude.y - uAmplitude.x) * k + uAmplitude.x ) / uInputSize.x;
float _waveLength = ((uWavelength.y - uWavelength.x) * k + uWavelength.x) / uInputSize.y;
float _alpha = (uAlpha.y - uAlpha.x) * k + uAlpha.x;

float x = vTextureCoord.x + cos(v * 6.28 / _waveLength - time) * _amplitude;
x = clamp(x, filterClamp.x, filterClamp.z);
float x = vTextureCoord.x + cos(v * 6.28 / _waveLength - uTime) * _amplitude;
x = clamp(x, uInputClamp.x, uInputClamp.z);

vec4 color = texture2D(uSampler, vec2(x, y));
vec4 color = texture(uSampler, vec2(x, y));

gl_FragColor = color * _alpha;
finalColor = color * _alpha;
}
Loading

0 comments on commit 0076c3f

Please sign in to comment.