Skip to content
Draft
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
182 changes: 132 additions & 50 deletions src/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,14 @@ export function makeCuboid(
scale,
}: Partial<Options> = {},
): number[][][] {
const options: Options = { amplitude, frequency, octaves, persistence, scale };
const field: number[][][] = new Array(width);
for (let x = 0; x < width; x++) {
field[x] = new Array(height);
for (let y = 0; y < height; y++) {
field[x][y] = new Array(depth);
for (let z = 0; z < depth; z++) {
let value = 0.0;
for (let octave = 0; octave < octaves; octave++) {
const freq = frequency * Math.pow(2, octave);
value += noise3(x * freq, y * freq, z * freq) *
(amplitude * Math.pow(persistence, octave));
}
field[x][y][z] = value / (2 - 1 / Math.pow(2, octaves - 1));
if (scale) field[x][y][z] = scale(field[x][y][z]);
field[x][y][z] = getCuboidNoiseValue(noise3, options, x, y, z);
}
}
}
Expand All @@ -68,22 +62,13 @@ export function makeCylinderSurface(
scale,
}: Partial<Options> = {},
): number[][] {
const radius = circumference / TWO_PI;
const options: Options = { amplitude, frequency, octaves, persistence, scale };
const radius = getCircleRadius(circumference);
const field: number[][] = new Array(circumference);
for (let x = 0; x < circumference; x++) {
field[x] = new Array(height);
for (let y = 0; y < height; y++) {
let value = 0.0;
for (let octave = 0; octave < octaves; octave++) {
const freq = frequency * Math.pow(2, octave);
const nx = x / circumference;
const rdx = nx * TWO_PI;
const [a, b] = [radius * Math.sin(rdx), radius * Math.cos(rdx)];
value += noise3(a * freq, b * freq, y * freq) *
(amplitude * Math.pow(persistence, octave));
}
field[x][y] = value / (2 - 1 / Math.pow(2, octaves - 1));
if (scale) field[x][y] = scale(field[x][y]);
field[x][y] = getCylinderSurfaceNoiseValue(noise3, options, circumference, radius, x, y);
}
}
return field;
Expand All @@ -100,15 +85,10 @@ export function makeLine(
scale,
}: Partial<Options> = {},
): number[] {
const options: Options = { amplitude, frequency, octaves, persistence, scale };
const field: number[] = new Array(length);
for (let x = 0; x < length; x++) {
let value = 0.0;
for (let octave = 0; octave < octaves; octave++) {
const freq = frequency * Math.pow(2, octaves);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor note. I think this was a typo and should be octave. It's changed to that in the getLineNoiseValue function

value += noise1(x * freq) * (amplitude * Math.pow(persistence, octave));
}
field[x] = value / (2 - 1 / Math.pow(2, octaves - 1));
if (scale) field[x] = scale(field[x]);
field[x] = getLineNoiseValue(noise1, options, x);
}
return field;
}
Expand All @@ -125,18 +105,12 @@ export function makeRectangle(
scale,
}: Partial<Options> = {},
): number[][] {
const options: Options = { amplitude, frequency, octaves, persistence, scale };
const field: number[][] = new Array(width);
for (let x = 0; x < width; x++) {
field[x] = new Array(height);
for (let y = 0; y < height; y++) {
let value = 0.0;
for (let octave = 0; octave < octaves; octave++) {
const freq = frequency * Math.pow(2, octave);
value += noise2(x * freq, y * freq) *
(amplitude * Math.pow(persistence, octave));
}
field[x][y] = value / (2 - 1 / Math.pow(2, octaves - 1));
if (scale) field[x][y] = scale(field[x][y]);
field[x][y] = getRectangleNoiseValue(noise2, options, x, y);
}
}
return field;
Expand All @@ -153,26 +127,134 @@ export function makeSphereSurface(
scale,
}: Partial<Options> = {},
): number[][] {
const options: Options = { amplitude, frequency, octaves, persistence, scale };
const circumferenceSemi = circumference / 2;
const field: number[][] = new Array(circumference);
for (let x = 0; x < circumference; x++) {
const circumferenceSemi = circumference / 2;
field[x] = new Array(circumferenceSemi);
for (let y = 0; y < circumferenceSemi; y++) {
const [nx, ny] = [x / circumference, y / circumferenceSemi];
const [rdx, rdy] = [nx * TWO_PI, ny * Math.PI];
const sinY = Math.sin(rdy + Math.PI);
const a = TWO_PI * Math.sin(rdx) * sinY;
const b = TWO_PI * Math.cos(rdx) * sinY;
const d = TWO_PI * Math.cos(rdy);
let value = 0.0;
for (let octave = 0; octave < octaves; octave++) {
const freq = frequency * Math.pow(2, octave);
value += noise3(a * freq, b * freq, d * freq) *
(amplitude * Math.pow(persistence, octave));
}
field[x][y] = value / (2 - 1 / Math.pow(2, octaves - 1));
if (scale) field[x][y] = scale(field[x][y]);
field[x][y] = getSphereSurfaceNoiseValue(noise3, options, circumference, circumferenceSemi, x, y);
}
}
return field;
}

export function fractalNoiseOptions({
amplitude = defaultAmplitude,
frequency = defaultFrequency,
octaves = defaultOctaves,
persistence = defaultPersistence,
scale,
}: Partial<Options> = {}): Options {
return { amplitude, frequency, octaves, persistence, scale };
}

export function getCircleRadius(
circumference: number,
): number {
return circumference / TWO_PI;
}

export function getCuboidNoiseValue(
noise3: Noise3Fn,
options: Options,
x: number,
y: number,
z: number,
): number {
let value = 0.0;
for (let octave = 0; octave < options.octaves; octave++) {
const freq = options.frequency * Math.pow(2, octave);
value += noise3(x * freq, y * freq, z * freq) *
(options.amplitude * Math.pow(options.persistence, octave));
}
const result = normalizeFractalNoiseValue(options, value);
if (options.scale) return options.scale(result);
return result;
}

export function getCylinderSurfaceNoiseValue(
noise3: Noise3Fn,
options: Options,
circumference: number,
radius: number,
x: number,
y: number,
): number {
let value = 0.0;
for (let octave = 0; octave < options.octaves; octave++) {
const freq = options.frequency * Math.pow(2, octave);
const nx = x / circumference;
const rdx = nx * TWO_PI;
const [a, b] = [radius * Math.sin(rdx), radius * Math.cos(rdx)];
value += noise3(a * freq, b * freq, y * freq) *
(options.amplitude * Math.pow(options.persistence, octave));
}
const result = normalizeFractalNoiseValue(options, value);
if (options.scale) return options.scale(result);
return result;
}

export function getLineNoiseValue(
noise1: Noise1Fn,
options: Options,
x: number,
): number {
let value = 0.0;
for (let octave = 0; octave < options.octaves; octave++) {
const freq = options.frequency * Math.pow(2, octave);
value += noise1(x * freq) * (options.amplitude * Math.pow(options.persistence, octave));
}
const result = normalizeFractalNoiseValue(options, value);
if (options.scale) return options.scale(result);
return result;
}

export function getRectangleNoiseValue(
noise2: Noise2Fn,
options: Options,
x: number,
y: number,
): number {
let value = 0.0;
for (let octave = 0; octave < options.octaves; octave++) {
const freq = options.frequency * Math.pow(2, octave);
value += noise2(x * freq, y * freq) * (options.amplitude * Math.pow(options.persistence, octave));
}
const result = normalizeFractalNoiseValue(options, value);
if (options.scale) return options.scale(result);
return result;
}

export function getSphereSurfaceNoiseValue(
noise3: Noise3Fn,
options: Options,
circumference: number,
circumferenceSemi: number,
x: number,
y: number,
): number {
const [nx, ny] = [x / circumference, y / circumferenceSemi];
const [rdx, rdy] = [nx * TWO_PI, ny * Math.PI];
const sinY = Math.sin(rdy + Math.PI);
const a = TWO_PI * Math.sin(rdx) * sinY;
const b = TWO_PI * Math.cos(rdx) * sinY;
const d = TWO_PI * Math.cos(rdy);
let value = 0.0;
for (let octave = 0; octave < options.octaves; octave++) {
const freq = options.frequency * Math.pow(2, octave);
value += noise3(a * freq, b * freq, d * freq) *
(options.amplitude * Math.pow(options.persistence, octave));
}
const result = normalizeFractalNoiseValue(options, value);
if (options.scale) return options.scale(result);
return result;
}

/**
* Normalize the result so that it's within a similar range regardless of the
* number of octaves.
*/
function normalizeFractalNoiseValue(options: Options, value: number) {
return value / (2 - 1 / Math.pow(2, options.octaves - 1));
}