Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Simplex Noise Filter #482

Merged
merged 5 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ If all else failes, you can manually download the bundled file from the [release
| **RGBSplitFilter**<br>_pixi-filters/rgb-split_<br>[View demo][RGBSplit_demo] | ![rgb split](https://filters.pixijs.download/main/screenshots/rgb.png?v=3) | |
| **ShockwaveFilter**<br>_pixi-filters/shockwave_<br>[View demo][Shockwave_demo] | ![shockwave](https://filters.pixijs.download/main/screenshots/shockwave.gif?v=3) |
| **SimpleLightmapFilter**<br>_pixi-filters/simple-lightmap_<br>[View demo][SimpleLightmap_demo] | ![simple-lightmap](https://filters.pixijs.download/main/screenshots/simple-lightmap.png?v=3) |
| **SimplexNoiseFilter**<br>_pixi-filters/simplex-noise_<br>[View demo][SimplexNoise_demo] | ![simplex-noise](https://filters.pixijs.download/main/screenshots/simplex-noise.png?v=3) |
| **TiltShiftFilter**<br>_pixi-filters/tilt-shift_<br>[View demo][TiltShift_demo] | ![tilt-shift](https://filters.pixijs.download/main/screenshots/tilt-shift.png?v=3) |
| **TwistFilter**<br>_pixi-filters/twist_<br>[View demo][Twist_demo] | ![twist](https://filters.pixijs.download/main/screenshots/twist.png?v=3) |
| **ZoomBlurFilter**<br>_pixi-filters/zoom-blur_<br>[View demo][ZoomBlur_demo] | ![zoom-blur](https://filters.pixijs.download/main/screenshots/zoom-blur.png?v=4) |
Expand Down Expand Up @@ -152,6 +153,7 @@ API documention can be found [here](http://pixijs.io/filters/docs/).
[RGBSplit_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=RGBSplitFilter
[Shockwave_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=ShockwaveFilter
[SimpleLightmap_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=SimpleLightmapFilter
[SimplexNoise_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=SimplexNoiseFilter
[TiltShift_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=TiltShiftFilter
[Twist_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=TwistFilter
[ZoomBlur_demo]: https://filters.pixijs.download/main/examples/index.html?enabled=ZoomBlurFilter
Expand Down
1 change: 1 addition & 0 deletions examples/src/filters/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export { default as reflection } from './reflection.mjs';
export { default as rgb } from './rgb.mjs';
export { default as shockwave } from './shockwave.mjs';
export { default as simpleLightmap } from './lightmap.mjs';
export { default as simplexNoise } from './simplex-noise.mjs';
export { default as tiltShift } from './tilt-shift.mjs';
export { default as twist } from './twist.mjs';
export { default as zoomBlur } from './zoom-blur.mjs';
16 changes: 16 additions & 0 deletions examples/src/filters/simplex-noise.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default function ()
{
const app = this;

app.addFilter('SimplexNoiseFilter', {
oncreate(folder)
{
folder.add(this, 'strength', 0, 1).name('strength');
folder.add(this, 'noiseScale', 0, 50).name('noise scale');
folder.add(this, 'offsetX', 0, 5).name('offsetX');
folder.add(this, 'offsetY', 0, 5).name('offsetY');
folder.add(this, 'offsetZ', 0, 5).name('offsetZ');
folder.add(this, 'step', -1, 1).name('step');
},
});
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@
"require": "./lib/simple-lightmap/index.js",
"types": "./lib/simple-lightmap/index.d.ts"
},
"./simplex-noise": {
"import": "./lib/simplex-noise/index.mjs",
"require": "./lib/simplex-noise/index.js",
"types": "./lib/simplex-noise/index.d.ts"
},
"./tilt-shift": {
"import": "./lib/tilt-shift/index.mjs",
"require": "./lib/tilt-shift/index.js",
Expand Down
8 changes: 8 additions & 0 deletions scripts/screenshots/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,14 @@
"arguments": {
"strength": 4
}
},
{
"name": "SimplexNoiseFilter",
"filename": "simplex-noise",
"arguments": {
"strength": 0.5,
"noiseScale": 10
}
}
]
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export * from './reflection';
export * from './rgb-split';
export * from './shockwave';
export * from './simple-lightmap';
export * from './simplex-noise';
export * from './tilt-shift';
export * from './twist';
export * from './zoom-blur';
143 changes: 143 additions & 0 deletions src/simplex-noise/SimplexNoiseFilter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { Filter, GlProgram, GpuProgram } from 'pixi.js';
import { vertex, wgslVertex } from '../defaults';
import fragment from './simplex.frag';
import source from './simplex.wgsl';

/** Options for the SimplexNoiseFilter constructor. */
export interface SimplexNoiseFilterOptions
{
/**
* Noise map strength.
* @default 0.5
*/
strength?: number;
/**
* Noise map scale.
* @default 10.0
*/
noiseScale?: number;
/**
* Horizontal offset for the noise map.
* @default 0
*/
offsetX?: number;
/**
* Vertical offset for the noise map.
* @default 0
*/
offsetY?: number;
/**
* Depth offset for the noise map.
* @default 0
*/
offsetZ?: number;
/**
* The threshold used with the step function to create a blocky effect in the noise pattern.
* When this is greater than 0, the step function is used to compare the noise value to this threshold.
* @default -1
*/
step?: number;
}

/**
* The SimplexNoiseFilter multiplies simplex noise with the current texture data. <br>
* ![original](../screenshots/original.png)![filter](../screenshots/simplex-noise.png)
* @class
* @extends Filter
* @see {@link https://www.npmjs.com/package/pixi-filters|pixi-filters}
*/
export class SimplexNoiseFilter extends Filter
{
/** Default constructor options. */
public static readonly defaults: SimplexNoiseFilterOptions = {
strength: 0.5,
noiseScale: 10.0,
offsetX: 0,
offsetY: 0,
offsetZ: 0,
step: -1,
};

/**
* @param options - Options for the SimplexNoise constructor.
*/
constructor(options?: SimplexNoiseFilterOptions)
{
options = { ...SimplexNoiseFilter.defaults, ...options };

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

const glProgram = GlProgram.from({
vertex,
fragment,
name: 'simplex-filter',
});

super({
gpuProgram,
glProgram,
resources: {
simplexUniforms: {
uStrength: { value: options?.strength ?? 0, type: 'f32' },
uNoiseScale: { value: options?.noiseScale ?? 0, type: 'f32' },
uOffsetX: { value: options?.offsetX ?? 0, type: 'f32' },
uOffsetY: { value: options?.offsetY ?? 0, type: 'f32' },
uOffsetZ: { value: options?.offsetZ ?? 0, type: 'f32' },
uStep: { value: options?.step ?? 0, type: 'f32' },
}
}
});
}

/**
* Strength of the noise (color = (noiseMap + strength) * texture)
* @default 0.5
*/
get strength(): number { return this.resources.simplexUniforms.uniforms.uStrength; }
set strength(value: number) { this.resources.simplexUniforms.uniforms.uStrength = value; }

/**
* Noise map scale.
* @default 10
*/
get noiseScale(): number { return this.resources.simplexUniforms.uniforms.uNoiseScale; }
set noiseScale(value: number) { this.resources.simplexUniforms.uniforms.uNoiseScale = value; }

/**
* Horizontal offset for the noise map.
* @default 0
*/
get offsetX(): number { return this.resources.simplexUniforms.uniforms.uOffsetX; }
set offsetX(value: number) { this.resources.simplexUniforms.uniforms.uOffsetX = value; }

/**
* Vertical offset for the noise map.
* @default 0
*/
get offsetY(): number { return this.resources.simplexUniforms.uniforms.uOffsetY; }
set offsetY(value: number) { this.resources.simplexUniforms.uniforms.uOffsetY = value; }

/**
* Depth offset for the noise map.
* @default 0
*/
get offsetZ(): number { return this.resources.simplexUniforms.uniforms.uOffsetZ; }
set offsetZ(value: number) { this.resources.simplexUniforms.uniforms.uOffsetZ = value; }

/**
* The threshold used with the step function to create a blocky effect in the noise pattern.
* When this is greater than 0, the step function is used to compare the noise value to this threshold.
* @default -1
*/
get step(): number { return this.resources.simplexUniforms.uniforms.uStep; }
set step(value: number) { this.resources.simplexUniforms.uniforms.uStep = value; }
}
1 change: 1 addition & 0 deletions src/simplex-noise/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './SimplexNoiseFilter';
61 changes: 61 additions & 0 deletions src/simplex-noise/simplex.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
precision highp float;
in vec2 vTextureCoord;
out vec4 finalColor;

uniform sampler2D uTexture;
uniform float uStrength;
uniform float uNoiseScale;
uniform float uOffsetX;
uniform float uOffsetY;
uniform float uOffsetZ;
uniform float uStep;

uniform vec4 uInputSize;
uniform vec4 uInputClamp;

//Noise from: https://www.shadertoy.com/view/4sc3z2
const vec3 MOD3 = vec3(.1031,.11369,.13787);
vec3 hash33(vec3 p3)
{
p3 = fract(p3 * MOD3);
p3 += dot(p3, p3.yxz+19.19);
return -1.0 + 2.0 * fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
}

float simplex_noise(vec3 p)
{
const float K1 = 0.333333333;
const float K2 = 0.166666667;

vec3 i = floor(p + (p.x + p.y + p.z) * K1);
vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);

vec3 e = step(vec3(0.0), d0 - d0.yzx);
vec3 i1 = e * (1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy * (1.0 - e);

vec3 d1 = d0 - (i1 - 1.0 * K2);
vec3 d2 = d0 - (i2 - 2.0 * K2);
vec3 d3 = d0 - (1.0 - 3.0 * K2);

vec4 h = max(0.6 - vec4(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), 0.0);
vec4 n = h * h * h * h * vec4(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.0)));

return dot(vec4(31.316), n);
}

void main(void)
{
float noise = simplex_noise(
vec3(vTextureCoord*uNoiseScale+vec2(uOffsetX, uOffsetY), uOffsetZ)
) * 0.5 + 0.5;

noise += 2.0 * uStrength - 1.0;
noise = clamp(noise, 0.0, 1.0);

if (uStep > 0.0) { //step > 0.5
noise = 1.0 - step(noise, uStep);
}

finalColor = texture(uTexture, vTextureCoord) * noise;
}
61 changes: 61 additions & 0 deletions src/simplex-noise/simplex.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
struct SimplexUniforms {
uStrength:f32,
uNoiseScale:f32,
uOffsetX:f32,
uOffsetY:f32,
uOffsetZ:f32,
uStep:f32
};

struct GlobalFilterUniforms {
uInputSize:vec4<f32>,
uInputPixel:vec4<f32>,
uInputClamp:vec4<f32>,
uOutputFrame:vec4<f32>,
uGlobalFrame:vec4<f32>,
uOutputTexture:vec4<f32>,
};

@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;

@group(0) @binding(1) var uTexture: texture_2d<f32>;
@group(0) @binding(2) var uSampler: sampler;
@group(1) @binding(0) var<uniform> simplexUniforms : SimplexUniforms;

@fragment
fn mainFragment(
@location(0) uv: vec2<f32>,
@builtin(position) position: vec4<f32>
) -> @location(0) vec4<f32> {
var noise: f32 = simplex_noise(vec3<f32>(uv * simplexUniforms.uNoiseScale + vec2<f32>(simplexUniforms.uOffsetX, simplexUniforms.uOffsetY), simplexUniforms.uOffsetZ)) * 0.5 + 0.5;
noise = noise + (2. * simplexUniforms.uStrength - 1.);
noise = clamp(noise, 0.0, 1.0);
if (simplexUniforms.uStep > 0.0) {
noise = 1. - step(noise, simplexUniforms.uStep);
}
return textureSample(uTexture, uSampler, uv) * noise;
}

const MOD3: vec3<f32> = vec3<f32>(0.1031, 0.11369, 0.13787);
fn hash33(p3: vec3<f32>) -> vec3<f32> {
var p3_var = p3;
p3_var = fract(p3_var * MOD3);
p3_var = p3_var + (dot(p3_var, p3_var.yxz + 19.19));
return -1. + 2. * fract(vec3<f32>((p3_var.x + p3_var.y) * p3_var.z, (p3_var.x + p3_var.z) * p3_var.y, (p3_var.y + p3_var.z) * p3_var.x));
}

fn simplex_noise(p: vec3<f32>) -> f32 {
let K1: f32 = 0.33333334;
let K2: f32 = 0.16666667;
let i: vec3<f32> = floor(p + (p.x + p.y + p.z) * K1);
let d0: vec3<f32> = p - (i - (i.x + i.y + i.z) * K2);
let e: vec3<f32> = step(vec3<f32>(0.), d0 - d0.yzx);
let i1: vec3<f32> = e * (1. - e.zxy);
let i2: vec3<f32> = 1. - e.zxy * (1. - e);
let d1: vec3<f32> = d0 - (i1 - 1. * K2);
let d2: vec3<f32> = d0 - (i2 - 2. * K2);
let d3: vec3<f32> = d0 - (1. - 3. * K2);
let h: vec4<f32> = max(vec4<f32>(0.6) - vec4<f32>(dot(d0, d0), dot(d1, d1), dot(d2, d2), dot(d3, d3)), vec4<f32>(0.0));
let n: vec4<f32> = h * h * h * h * vec4<f32>(dot(d0, hash33(i)), dot(d1, hash33(i + i1)), dot(d2, hash33(i + i2)), dot(d3, hash33(i + 1.)));
return dot(vec4<f32>(31.316), n);
}