fast-noise-lite-ts
Version:
A fast and lightweight noise generation library for JavaScript
214 lines (213 loc) • 9.42 kB
JavaScript
import { prime, randomVectors2D, randomVectors3D } from "../constants";
import { hashR2, hashR3 } from "../utilities";
export function cellularR2(options, x, y) {
const seed = options.seed;
let xr = Math.round(x);
let yr = Math.round(y);
let distance0 = Number.MAX_VALUE;
let distance1 = Number.MAX_VALUE;
let closestHash = 0;
let cellularJitter = 0.43701595 * (options.cellularJitterModifier ?? 1.0);
let xPrimed = (xr - 1) * prime.x;
let yPrimedBase = (yr - 1) * prime.y;
switch (options.cellularDistanceFunction) {
default:
case "euclidean":
case "euclidean-squared":
for (let xi = xr - 1; xi <= xr + 1; xi++) {
let yPrimed = yPrimedBase;
for (let yi = yr - 1; yi <= yr + 1; yi++) {
let hash = hashR2(seed, xPrimed, yPrimed);
let idx = hash & (255 << 1);
let vecX = xi - x + randomVectors2D[idx] * cellularJitter;
let vecY = yi - y + randomVectors2D[idx | 1] * cellularJitter;
let newDistance = vecX * vecX + vecY * vecY;
distance1 = Math.max(Math.min(distance1, newDistance), distance0);
if (newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
}
yPrimed += prime.y;
}
xPrimed += prime.x;
}
break;
case "manhattan":
for (let xi = xr - 1; xi <= xr + 1; xi++) {
let yPrimed = yPrimedBase;
for (let yi = yr - 1; yi <= yr + 1; yi++) {
let hash = hashR2(seed, xPrimed, yPrimed);
let idx = hash & (255 << 1);
let vecX = xi - x + randomVectors2D[idx] * cellularJitter;
let vecY = yi - y + randomVectors2D[idx | 1] * cellularJitter;
let newDistance = Math.abs(vecX) + Math.abs(vecY);
distance1 = Math.max(Math.min(distance1, newDistance), distance0);
if (newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
}
yPrimed += prime.y;
}
xPrimed += prime.x;
}
break;
case "hybrid":
for (let xi = xr - 1; xi <= xr + 1; xi++) {
let yPrimed = yPrimedBase;
for (let yi = yr - 1; yi <= yr + 1; yi++) {
let hash = hashR2(seed, xPrimed, yPrimed);
let idx = hash & (255 << 1);
let vecX = xi - x + randomVectors2D[idx] * cellularJitter;
let vecY = yi - y + randomVectors2D[idx | 1] * cellularJitter;
let newDistance = Math.abs(vecX) + Math.abs(vecY) + (vecX * vecX + vecY * vecY);
distance1 = Math.max(Math.min(distance1, newDistance), distance0);
if (newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
}
yPrimed += prime.y;
}
xPrimed += prime.x;
}
break;
}
if (options.cellularDistanceFunction === "euclidean" &&
options.cellularReturnType !== "cell-value") {
distance0 = Math.sqrt(distance0);
distance1 = Math.sqrt(distance1);
}
switch (options.cellularReturnType) {
case "cell-value":
return closestHash * (1 / 2147483648.0);
case "distance":
return distance0 - 1;
case "distance-2":
return distance1 - 1;
case "distance-2-add":
return (distance1 + distance0) * 0.5 - 1;
case "distance-2-sub":
return distance1 - distance0 - 1;
case "distance-2-mul":
return distance1 * distance0 * 0.5 - 1;
case "distance-2-div":
return distance0 / distance1 - 1;
default:
return 0;
}
}
export function cellularR3(options, x, y, z) {
const seed = options.seed;
let xr = Math.round(x);
let yr = Math.round(y);
let zr = Math.round(z);
let distance0 = Number.MAX_VALUE;
let distance1 = Number.MAX_VALUE;
let closestHash = 0;
let cellularJitter = 0.39614353 * (options.cellularJitterModifier ?? 1.0);
let xPrimed = (xr - 1) * prime.x;
let yPrimedBase = (yr - 1) * prime.y;
let zPrimedBase = (zr - 1) * prime.z;
switch (options.cellularDistanceFunction) {
case "euclidean":
case "euclidean-squared":
for (let xi = xr - 1; xi <= xr + 1; xi++) {
let yPrimed = yPrimedBase;
for (let yi = yr - 1; yi <= yr + 1; yi++) {
let zPrimed = zPrimedBase;
for (let zi = zr - 1; zi <= zr + 1; zi++) {
let hash = hashR3(seed, xPrimed, yPrimed, zPrimed);
let idx = hash & (255 << 2);
let vecX = xi - x + randomVectors3D[idx] * cellularJitter;
let vecY = yi - y + randomVectors3D[idx | 1] * cellularJitter;
let vecZ = zi - z + randomVectors3D[idx | 2] * cellularJitter;
let newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ;
distance1 = Math.max(Math.min(distance1, newDistance), distance0);
if (newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
}
zPrimed += prime.z;
}
yPrimed += prime.y;
}
xPrimed += prime.x;
}
break;
case "manhattan":
for (let xi = xr - 1; xi <= xr + 1; xi++) {
let yPrimed = yPrimedBase;
for (let yi = yr - 1; yi <= yr + 1; yi++) {
let zPrimed = zPrimedBase;
for (let zi = zr - 1; zi <= zr + 1; zi++) {
let hash = hashR3(seed, xPrimed, yPrimed, zPrimed);
let idx = hash & (255 << 2);
let vecX = xi - x + randomVectors3D[idx] * cellularJitter;
let vecY = yi - y + randomVectors3D[idx | 1] * cellularJitter;
let vecZ = zi - z + randomVectors3D[idx | 2] * cellularJitter;
let newDistance = Math.abs(vecX) + Math.abs(vecY) + Math.abs(vecZ);
distance1 = Math.max(Math.min(distance1, newDistance), distance0);
if (newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
}
zPrimed += prime.z;
}
yPrimed += prime.y;
}
xPrimed += prime.x;
}
break;
case "hybrid":
for (let xi = xr - 1; xi <= xr + 1; xi++) {
let yPrimed = yPrimedBase;
for (let yi = yr - 1; yi <= yr + 1; yi++) {
let zPrimed = zPrimedBase;
for (let zi = zr - 1; zi <= zr + 1; zi++) {
let hash = hashR3(seed, xPrimed, yPrimed, zPrimed);
let idx = hash & (255 << 2);
let vecX = xi - x + randomVectors3D[idx] * cellularJitter;
let vecY = yi - y + randomVectors3D[idx | 1] * cellularJitter;
let vecZ = zi - z + randomVectors3D[idx | 2] * cellularJitter;
let newDistance = Math.abs(vecX) +
Math.abs(vecY) +
Math.abs(vecZ) +
(vecX * vecX + vecY * vecY + vecZ * vecZ);
distance1 = Math.max(Math.min(distance1, newDistance), distance0);
if (newDistance < distance0) {
distance0 = newDistance;
closestHash = hash;
}
zPrimed += prime.z;
}
yPrimed += prime.y;
}
xPrimed += prime.x;
}
break;
default:
break;
}
if (options.cellularDistanceFunction === "euclidean" &&
options.cellularReturnType !== "cell-value") {
distance0 = Math.sqrt(distance0);
distance1 = Math.sqrt(distance1);
}
switch (options.cellularReturnType) {
case "cell-value":
return closestHash * (1 / 2147483648.0);
case "distance":
return distance0 - 1;
case "distance-2":
return distance1 - 1;
case "distance-2-add":
return (distance1 + distance0) * 0.5 - 1;
case "distance-2-sub":
return distance1 - distance0 - 1;
case "distance-2-mul":
return distance1 * distance0 * 0.5 - 1;
case "distance-2-div":
return distance0 / distance1 - 1;
default:
return 0;
}
}