kampos
Version:
Tiny and fast effects compositor on WebGL
166 lines (154 loc) • 5.46 kB
JavaScript
/**
* @function turbulence
* @property {string} COLOR
* @property {string} ALPHA
* @param {object} params
* @param {string} params.noise 3D noise implementation to use.
* @param {string} [params.output] how to output the `turbulenceValue` variable. Use `turbulence.COLOR` or `turbulence.ALPHA` for outputting to color or alpha correspondingly. Defaults to `turbulence.COLOR`.
* @param {{x: number, y: number}} [params.frequency={x: 0.0, y: 0.0}] initial frequencies to use for x and y axes.
* @param {number} [params.octaves=1] initial number of octaves to use for turbulence noise generation.
* @param {boolean} [params.isFractal=false] initial number of octaves to use for turbulence noise generation.
* @param {number} [params.time=0] initial time for controlling initial noise value.
* @param {string} [params.input] how to define `turbulenceSeed`. Defaults to `turbulence.FRAGCOORD_XY_TIME`.
* @returns {turbulenceEffect}
*
* @example turbulence({noise: kampos.noise.simplex, output: turbulence.COLOR, octaves: 4, isFractal: true})
*/
function turbulence({
noise,
output = OUTPUT_TYPES.COLOR,
frequency,
octaves = 1,
isFractal = false,
time = 0.0,
input = INPUT_TYPES.FRAGCOORD_XY_TIME,
}) {
const { x: fx, y: fy } = frequency || { x: 0.0, y: 0.0 };
/**
* @typedef {Object} turbulenceEffect
* @property {{x: number?, y: number?}} frequency
* @property {number} octaves
* @property {boolean} isFractal
*
* @description Generates a turbulence/fractal noise value stored into `turbulenceValue`.
* Depends on a `noise(vec3 P)` function to be declared and injected via the `noise` param, for example, simply supplying the {@link perlinNoiseEffect}.
*
* @example
* effect.frequency = {x: 0.0065};
* effect.octaves = 4;
* effect.isFractal = true;
*/
return {
fragment: {
uniform: {
u_turbulenceEnabled: 'bool',
u_turbulenceFrequency: 'vec2',
u_turbulenceOctaves: 'int',
u_isFractal: 'bool',
u_time: 'float',
},
constant: `
${noise}
const int MAX_OCTAVES = 9;
float turbulence (vec3 seed, vec2 frequency, int numOctaves, bool isFractal) {
float sum = 0.0;
vec3 position = vec3(0.0);
position.x = seed.x * frequency.x;
position.y = seed.y * frequency.y;
position.z = seed.z;
float ratio = 1.0;
for (int octave = 0; octave <= MAX_OCTAVES; octave++) {
if (octave > numOctaves) {
break;
}
if (isFractal) {
sum += noise(position) / ratio;
}
else {
sum += abs(noise(position)) / ratio;
}
position.x *= 2.0;
position.y *= 2.0;
ratio *= 2.0;
}
if (isFractal) {
sum = (sum + 1.0) / 2.0;
}
return clamp(sum, 0.0, 1.0);
}`,
source: `
${input || ''}
float turbulenceValue = turbulence(turbulenceSeed, u_turbulenceFrequency, u_turbulenceOctaves, u_isFractal);`,
main: `
${output || ''}`,
},
get frequency() {
const [x, y] = this.uniforms[0].data;
return { x, y };
},
set frequency({ x, y }) {
if (typeof x !== 'undefined') this.uniforms[0].data[0] = x;
if (typeof y !== 'undefined') this.uniforms[0].data[1] = y;
},
get octaves() {
return this.uniforms[1].data[0];
},
set octaves(value) {
this.uniforms[1].data[0] = Math.max(0, parseInt(value));
},
get isFractal() {
return !!this.uniforms[2].data[0];
},
set isFractal(toggle) {
this.uniforms[2].data[0] = +toggle;
},
get time() {
return this.uniforms[3].data[0];
},
set time(value) {
this.uniforms[3].data[0] = Math.max(0, parseFloat(value));
},
uniforms: [
{
name: 'u_turbulenceFrequency',
type: 'f',
data: [fx, fy],
},
{
name: 'u_turbulenceOctaves',
type: 'i',
data: [octaves],
},
{
name: 'u_isFractal',
type: 'i',
data: [+!!isFractal],
},
{
name: 'u_time',
type: 'f',
data: [time],
},
],
};
}
const OUTPUT_TYPES = {
COLOR: 'color = vec3(turbulenceValue);',
ALPHA: 'alpha = turbulenceValue;',
};
const INPUT_TYPES = {
FRAGCOORD_XY_TIME:
'vec3 turbulenceSeed = vec3(gl_FragCoord.xy, u_time * 0.0001);',
FRAGCOORD_XYZ: 'vec3 turbulenceSeed = vec3(gl_FragCoord.xyz);',
FRAGCOORD_XY_MOUSE_TIME:
'vec3 turbulenceSeed = vec3(gl_FragCoord.xy - u_mouse * u_resolution, u_time * 0.0001);',
FRAGCOORD_XY_MOUSE_Z:
'vec3 turbulenceSeed = vec3(gl_FragCoord.xy - u_mouse * u_resolution, gl_FragCoord.z);',
};
turbulence.COLOR = OUTPUT_TYPES.COLOR;
turbulence.ALPHA = OUTPUT_TYPES.ALPHA;
turbulence.FRAGCOORD_XY_TIME = INPUT_TYPES.FRAGCOORD_XY_TIME;
turbulence.FRAGCOORD_XYZ = INPUT_TYPES.FRAGCOORD_XYZ;
turbulence.FRAGCOORD_XY_MOUSE_TIME = INPUT_TYPES.FRAGCOORD_XY_MOUSE_TIME;
turbulence.FRAGCOORD_XY_MOUSE_Z = INPUT_TYPES.FRAGCOORD_XY_MOUSE_Z;
export default turbulence;