Simplex Noise
Perlin noise blends four corners of a square. In 2001, Perlin swapped the squares for triangles: three corners, each with a round reach of its own. This is the grid under Islands' default terrain. Tap a point to see its triangle and the three circles that touch it, and compare with the square lattice of part 3. How it works.
El ruido de Perlin mezcla cuatro esquinas de un cuadrado. En 2001, Perlin cambió los cuadrados por triángulos: tres esquinas, cada una con su propio alcance redondo. Esta es la rejilla que hay debajo del terreno por defecto de Islands. Toca un punto para ver su triángulo y los tres círculos que lo tocan, y compara con la red cuadrada de la parte 3. Cómo funciona.
The idea in plain words
Cover the plane with triangles instead of squares, and give every corner a random slope, as in Perlin noise. Then, instead of blending corners across a cell, let each corner spread its slope only inside a circle around it, fading to nothing at the edge. The noise at any point is the sum of the three circles that reach it.
Picture three lamps above a triangle, each lighting a round pool on the floor. The light at a spot is whatever the nearby lamps add up to. The analogy has limits: these pools can be negative, darker than the floor, because each one is tilted along its corner's arrow; and they end at an exact radius instead of fading out forever.
Tap any point. The scene draws its triangle and the reach of its three corners. Notice that no circle quite reaches the other corners. Then switch to Square lattice and back, in the Relief view, and look for the rows and columns.
Why it matters, and the catch
A square cell has 4 corners in 2D, 8 in 3D and 16 in 4D: 2n, doubling with each dimension. A triangle has 3 corners, a tetrahedron 4, and the simplest shape in n dimensions n + 1. That is the name: a simplex is the simplest shape that fills its space. The saving is small in 2D and large for the 3D and 4D noise used to animate textures.
The round reach also matters. Square cells leave a faint trace along the axes; triangles point in six directions and the kernels are circles, so the trace mostly disappears. Measured on the power spectrum, square-lattice Perlin noise had 12–31 % more energy along the axes than along the diagonals; simplex noise stayed within 6 %.
The catch is the bookkeeping. To find the triangle, the point has to be skewed into a space where the triangles become halves of squares, and the corners skewed back. In 2D that costs about what it saves: in this port, a sample takes about the same time on either lattice. Perlin also patented a version of the method in 2005; the patent expired in 2022.
Islands' terrain uses this grid
The noise Islands' map pipeline calls "Perlin", its default for terrain, is simplex noise with the diamond gradients and scale of part 3. Catlike Coding, which Islands follows, pairs simplex with its own gradients: the same directions, normalised, with a scale derived for triangles. The pairing is Islands' choice, and it changes the range. Measured on 4 seeds:
- Simplex with Perlin gradients (Islands' terrain default) spans about −0.43 to 0.43, with a standard deviation of 0.17.
- Simplex with simplex gradients spans about −1 to 1, with a standard deviation of 0.45.
The reason is that Perlin's scale was derived for four corners blended by the quintic, not for three round kernels. Islands maps a single octave to 0–1 as 0.5 + 0.5 × noise, so its default terrain value sits between about 0.29 and 0.71. Whether that matters depends on the stages that read it; it is reported here as a measurement, not as a bug.
Is there a theorem?
- Still zero on the lattice. Each kernel reaches 1.22 cells, and the edges of the triangles are 1.41 cells long, so at a corner no other kernel arrives, and the corner's own ramp is zero there. The noise is exactly zero at every corner: the grid of zeros from part 3 survives, now triangular. Measured: at most 5 × 10⁻¹⁵, rounding error.
- The slope at a corner is the arrow. The kernel 8(½ − d²)³ equals 1 at its centre, so at the corner the slope is exactly that corner's gradient, as on the square lattice.
- Smooth up to the second derivative. The kernel and its first two derivatives are zero where the circle ends, so adding or dropping a corner as the point moves causes no jump in value, slope or curvature: the same C² smoothness the quintic gave the square lattice.
- n + 1 corners. An n-dimensional simplex has n + 1 corners, against 2n for a cube, and finding it only needs the coordinates sorted. Gustavson puts the cost at about O(n²) per sample against O(2n) for classic noise.
The scale that keeps simplex gradients within −1 to 1 is a worked maximum rather than a theorem: Catlike Coding finds the largest value at the centre of a triangle, about 0.2425, and divides by it.
The equations
Islands first shrinks the input by √3, so that features come out about as large as on the square lattice. Then, for a point (x, y):
- Skew: s = (x + y)·F, with F = (√3 − 1)/2 ≈ 0.366; the rhombus is (i, j) = (⌊x + s⌋, ⌊y + s⌋)
- Triangle: corners (i, j) and (i+1, j+1), plus (i+1, j) if x + s − i > y + s − j, otherwise (i, j+1)
- Unskew: a corner (a, b) sits at (a, b) − (a + b)·G in real space, with G = (3 − √3)/6 ≈ 0.211
- Kernel: for an offset d from a corner with gradient g, k = 8 · max(0, ½ − |d|²)³ · (g · d)
- Simplex noise: f = the sum of k over the three corners of the triangle
Read it as a recipe: skew to find the rhombus, compare the two fractions to pick the half, unskew the three corners, and add three ramps, each dimmed by a round bump. There is no blending step: the bumps fade on their own.
What the picture does and does not say
- The zoom counts square cells, so the three noises can be compared at the same scale. With the shrink by √3, a triangle edge is about 1.41 square cells.
- Arrows are drawn to scale within each noise: the longest possible gradient is 0.4 of a square cell. Simplex gradients are all the same length; Perlin's are not.
- The histogram and range count the pixels on screen. The figures in the text come from 4 seeds of 1,600 square cells each.
- The spectrum figures come from two batches of 8 seeds, 256 × 256 samples each, comparing power within 3° of the axes and of the diagonals. The batches disagreed by a lot (12 % and 31 % for the square lattice), so read them as a direction, not a precise number. A simpler test, the average slope in 12 directions, could not tell the lattices apart: all within 2 %.
- Peaks counted on the same area: about 2,850 for simplex, against about 3,800 for the square lattice. The features of simplex noise come out a little larger.
- Timings are for this JavaScript port in Node, per sample: 164 ns for simplex with Perlin gradients, 267 ns with normalised gradients, 179 ns for the square lattice. Islands runs four samples at once with Burst, so its numbers differ.
- The code is a JavaScript port of Islands' 2D simplex noise. Checked against a C# replica at 18 points × 3 seeds for each gradient set, value and derivatives agree to within 6 × 10⁻⁶.
How it works
This part moves the gradient noise of part 3 onto triangles. It covers:
- Skewing a point to find its rhombus.
- Picking one of the rhombus's two triangles.
- Unskewing the corners to measure real distances.
- The round kernel that replaces the blend.
- The two gradient sets Islands can use.
- Drawing a lattice of triangles.
Plain JavaScript and the Canvas 2D API, no libraries. The noise itself is about 50 lines and reuses the gradients of part 3; the scene is about 400. It follows the simplex part of Catlike Coding's Pseudorandom Noise and Gustavson's Simplex noise demystified.
1. Skew to find the rhombus
A lattice of equilateral triangles is awkward to index. The trick is to stretch the plane
along its diagonal until each pair of triangles becomes a unit square. Adding (x + y)·F to
both coordinates does exactly that; after it, floor works as on any square grid.
const SQRT3 = Math.sqrt(3);
export const SKEW = (SQRT3 - 1) / 2; // F = (√3 − 1) / 2 ≈ 0.366
export const UNSKEW = (3 - SQRT3) / 6; // G = (3 − √3) / 6 ≈ 0.211
// Islands shrinks the input by √3 so features are about as large as on the square lattice.
export const SHRINK = 1 / SQRT3;
export function simplexCell(x, y) {
x *= SHRINK; y *= SHRINK;
const skew = (x + y) * SKEW;
const sx = x + skew, sy = y + skew;
const i0 = Math.floor(sx), j0 = Math.floor(sy);
…
} Why shrink by √3 first?
Only to make the noise comparable with the square-lattice versions. Along the diagonal through the origin, square lattice points are √2 apart and triangle corners √(2/3) apart. Dividing the frequency by √3 makes them line up, so the same frequency setting gives features of a similar size. Catlike Coding derives it; Islands copies it.
2. Which triangle
The skewed square is split by its diagonal from (i, j) to (i+1, j+1). If the point's x fraction is larger than its y fraction, it lies below the diagonal and the third corner is (i+1, j); otherwise it is (i, j+1). The small diagram in the panel shows this square.
// Which triangle of the rhombus: below or above its diagonal.
const xGy = sx - i0 > sy - j0;
return { x, y, sx, sy, corners: [[i0, j0], [i0 + 1, j0 + 1], xGy ? [i0 + 1, j0] : [i0, j0 + 1]] }; 3. Unskew the corners
Distances only make sense in real space, so each corner is moved back by (i + j)·G and the offset to the point is taken there. F and G are chosen so that skewing and unskewing undo each other.
const cell = simplexCell(x, y);
let v = 0, dx = 0, dy = 0, dxx = 0;
for (const [i, j] of cell.corners) {
// Unskew the corner back to real space and take the offset to the point.
const unskew = (i + j) * UNSKEW;
const k = kernel(gradient(i, j), cell.x - i + unskew, cell.y - j + unskew);
v += k.v; dx += k.dx; dy += k.dy; dxx += k.dxx;
}
// Chain rule for the shrink by √3.
return { v, dx: dx * SHRINK, dy: dy * SHRINK, dxx: dxx * SHRINK * SHRINK }; 4. A round kernel instead of a blend
Each corner contributes its gradient ramp, as in part 3, multiplied by (½ − d²)³ where d is the distance. That bump is 1/8 at the centre, so Islands multiplies it by 8, and it is zero beyond d² = ½. The three contributions are simply added.
// One corner's radial kernel times its gradient ramp. (ox, oy): offset from the corner to
// the point, in unskewed space. The kernel 8(0.5 − r²)³ reaches zero at r = √0.5.
function kernel(g, ox, oy) {
const f = 0.5 - ox * ox - oy * oy;
if (f <= 0) return { v: 0, dx: 0, dy: 0, dxx: 0 };
const ramp = g[0] * ox + g[1] * oy;
return {
v: 8 * f * f * f * ramp,
dx: 8 * f * f * (f * g[0] - 6 * ox * ramp),
dy: 8 * f * f * (f * g[1] - 6 * oy * ramp),
…
};
} Why exactly ½?
In the shrunk, unskewed space the triangles have edges of √(2/3) and heights of √½. A radius of √½ lets each corner reach the opposite edge of its triangle, so the three kernels cover every point, but stops before the next corner, which is why the noise is still zero at every corner.
5. Two sets of gradients
Islands can put two kinds of gradient on the triangles. Perlin reuses the diamond of part 3, scale included; this is the terrain default. Simplex normalises the same directions to length 1 and uses the scale that fits triangles. Switch between them in the scene and watch the range in the panel.
export const GRADIENTS = {
// Perlin's diamond, scaled as in part 3: the default for terrain in Islands' map pipeline.
perlin: latticeGradient,
// The same directions normalised to length 1, then scaled to span about [-1, 1].
simplex: (seed, i, j) => {
const [gx, gy] = latticeGradient(seed, i, j), k = (5.832 / Math.SQRT2) / Math.hypot(gx, gy);
return [gx * k, gy * k];
},
}; 6. Drawing triangles
The lattice lines are where sx, sy or sx − sy is a whole number. Each of those is a straight line a·x + b·y = k in real space, so the scene draws three families of lines and clips each to the screen.
// In skewed space the triangles are bounded by sx = k, sy = k and sx − sy = k.
const a = SHRINK * (1 + SKEW), b = SHRINK * SKEW;
lineFamily(a, b, toX, toY, x1, y1);
lineFamily(b, a, toX, toY, x1, y1);
lineFamily(SHRINK, -SHRINK, toX, toY, x1, y1); Going further
- Go to 3D. The cube is skewed the same way and split into six tetrahedra; sorting the three fractions picks one. Islands has
Simplex3D. - Match the scale to the lattice. Try Perlin's diamond with a scale measured for triangles and compare the range with Islands' default.
- Stack several frequencies of this noise and you get fractal noise, the way Islands builds terrain: a later page of this series.
La idea en palabras sencillas
Cubre el plano con triángulos en vez de cuadrados y da a cada esquina una pendiente aleatoria, como en el ruido de Perlin. Después, en vez de mezclar las esquinas a lo largo de una celda, deja que cada esquina reparta su pendiente solo dentro de un círculo a su alrededor, que se apaga hasta cero en el borde. El ruido en cualquier punto es la suma de los tres círculos que lo alcanzan.
Imagina tres lámparas sobre un triángulo, cada una iluminando un charco redondo en el suelo. La luz en un sitio es lo que sumen las lámparas cercanas. La analogía tiene límites: estos charcos pueden ser negativos, más oscuros que el suelo, porque cada uno está inclinado según la flecha de su esquina; y terminan en un radio exacto en vez de apagarse poco a poco para siempre.
Toca cualquier punto. La escena dibuja su triángulo y el alcance de sus tres esquinas. Fíjate en que ningún círculo llega del todo a las otras esquinas. Después cambia a Red cuadrada y vuelve, en la vista Relieve, y busca las filas y las columnas.
Por qué importa, y la pega
Una celda cuadrada tiene 4 esquinas en 2D, 8 en 3D y 16 en 4D: 2n, el doble con cada dimensión. Un triángulo tiene 3 esquinas, un tetraedro 4, y la figura más simple en n dimensiones, n + 1. De ahí el nombre: un símplex es la figura más simple que llena su espacio. El ahorro es pequeño en 2D y grande en el ruido 3D y 4D que se usa para animar texturas.
El alcance redondo también importa. Las celdas cuadradas dejan una huella tenue a lo largo de los ejes; los triángulos apuntan en seis direcciones y los núcleos son círculos, así que la huella casi desaparece. Medido en el espectro de potencia, el ruido de Perlin sobre la red cuadrada tuvo entre un 12 % y un 31 % más de energía a lo largo de los ejes que de las diagonales; el simplex se quedó dentro del 6 %.
La pega es la contabilidad. Para encontrar el triángulo, el punto tiene que sesgarse a un espacio donde los triángulos se vuelven mitades de cuadrados, y las esquinas hay que desesgarlas de vuelta. En 2D eso cuesta más o menos lo que ahorra: en este port, una muestra tarda casi lo mismo en las dos redes. Perlin además patentó una versión del método en 2005; la patente caducó en 2022.
El terreno de Islands usa esta rejilla
El ruido que el pipeline de mapas de Islands llama "Perlin", el que usa por defecto para el terreno, es ruido simplex con los gradientes en rombo y la escala de la parte 3. Catlike Coding, que es lo que sigue Islands, combina el simplex con sus propios gradientes: las mismas direcciones, normalizadas, con una escala deducida para triángulos. La combinación es una elección de Islands, y cambia el rango. Medido en 4 semillas:
- Simplex con gradientes de Perlin (el terreno por defecto de Islands) va de unos −0,43 a 0,43, con una desviación típica de 0,17.
- Simplex con gradientes simplex va de unos −1 a 1, con una desviación típica de 0,45.
El motivo es que la escala de Perlin se dedujo para cuatro esquinas mezcladas con la quíntica, no para tres núcleos redondos. Islands lleva una sola octava al rango de 0 a 1 como 0,5 + 0,5 × ruido, así que su valor de terreno por defecto queda entre unos 0,29 y 0,71. Que eso importe o no depende de las etapas que lo leen; aquí se cuenta como una medida, no como un error.
¿Hay un teorema?
- Sigue valiendo cero en la red. Cada núcleo alcanza 1,22 celdas, y los lados de los triángulos miden 1,41 celdas, así que a una esquina no llega ningún otro núcleo, y la rampa de la propia esquina vale cero ahí. El ruido vale exactamente cero en cada esquina: la rejilla de ceros de la parte 3 sobrevive, ahora triangular. Medido: como mucho 5 × 10⁻¹⁵, error de redondeo.
- La pendiente en una esquina es la flecha. El núcleo 8(½ − d²)³ vale 1 en su centro, así que en la esquina la pendiente es exactamente el gradiente de esa esquina, como en la red cuadrada.
- Suave hasta la segunda derivada. El núcleo y sus dos primeras derivadas valen cero donde termina el círculo, así que ganar o perder una esquina cuando el punto se mueve no produce saltos en el valor, la pendiente ni la curvatura: la misma suavidad C² que la quíntica daba a la red cuadrada.
- n + 1 esquinas. Un símplex de n dimensiones tiene n + 1 esquinas, frente a 2n de un cubo, y encontrarlo solo exige ordenar las coordenadas. Gustavson calcula un coste de O(n²) por muestra, frente a O(2n) del ruido clásico.
La escala que mantiene los gradientes simplex entre −1 y 1 es un máximo calculado, no un teorema: Catlike Coding encuentra el mayor valor en el centro de un triángulo, unos 0,2425, y divide por él.
Las ecuaciones
Islands primero encoge la entrada en √3, para que los rasgos salgan más o menos del tamaño de los de la red cuadrada. Después, para un punto (x, y):
- Sesgo: s = (x + y)·F, con F = (√3 − 1)/2 ≈ 0,366; el rombo es (i, j) = (⌊x + s⌋, ⌊y + s⌋)
- Triángulo: esquinas (i, j) y (i+1, j+1), más (i+1, j) si x + s − i > y + s − j, y si no (i, j+1)
- Desesgo: una esquina (a, b) está en (a, b) − (a + b)·G en el espacio real, con G = (3 − √3)/6 ≈ 0,211
- Núcleo: para un desplazamiento d desde una esquina con gradiente g, k = 8 · max(0, ½ − |d|²)³ · (g · d)
- Ruido simplex: f = la suma de k sobre las tres esquinas del triángulo
Léelo como una receta: sesga para encontrar el rombo, compara las dos fracciones para elegir la mitad, desesga las tres esquinas y suma tres rampas, cada una atenuada por un bulto redondo. No hay paso de mezcla: los bultos se apagan solos.
Lo que la imagen dice y lo que no
- El zoom cuenta celdas cuadradas, para poder comparar los tres ruidos a la misma escala. Con el encogimiento en √3, un lado de triángulo mide unas 1,41 celdas cuadradas.
- Las flechas están a escala dentro de cada ruido: el gradiente más largo posible mide 0,4 celdas cuadradas. Los gradientes simplex miden todos lo mismo; los de Perlin, no.
- El histograma y el rango cuentan los píxeles en pantalla. Las cifras del texto salen de 4 semillas de 1.600 celdas cuadradas cada una.
- Las cifras del espectro salen de dos tandas de 8 semillas, de 256 × 256 muestras cada una, comparando la potencia a menos de 3° de los ejes y de las diagonales. Las tandas discreparon bastante (12 % y 31 % para la red cuadrada), así que léelas como una dirección, no como un número preciso. Una prueba más simple, la pendiente media en 12 direcciones, no distinguió las redes: todas dentro del 2 %.
- Cumbres contadas en la misma área: unas 2.850 en simplex, frente a unas 3.800 en la red cuadrada. Los rasgos del ruido simplex salen algo más grandes.
- Los tiempos son de este port a JavaScript en Node, por muestra: 164 ns para simplex con gradientes de Perlin, 267 ns con gradientes normalizados, 179 ns para la red cuadrada. Islands calcula cuatro muestras a la vez con Burst, así que sus números son otros.
- El código es un port a JavaScript del ruido simplex 2D de Islands. Comprobado contra una réplica en C# en 18 puntos × 3 semillas para cada conjunto de gradientes, el valor y las derivadas coinciden con un margen de 6 × 10⁻⁶.
Cómo funciona
Esta parte lleva el ruido de gradiente de la parte 3 a los triángulos. Cubre:
- Sesgar un punto para encontrar su rombo.
- Elegir uno de los dos triángulos del rombo.
- Desesgar las esquinas para medir distancias reales.
- El núcleo redondo que sustituye a la mezcla.
- Los dos conjuntos de gradientes que puede usar Islands.
- Dibujar una red de triángulos.
JavaScript puro y la API Canvas 2D, sin librerías. El ruido en sí ocupa unas 50 líneas y reutiliza los gradientes de la parte 3; la escena, unas 400. Sigue la parte de simplex de Pseudorandom Noise de Catlike Coding y Simplex noise demystified de Gustavson. Los comentarios del código están en inglés.
1. Sesgar para encontrar el rombo
Una red de triángulos equiláteros es incómoda de indexar. El truco es estirar el plano a lo
largo de su diagonal hasta que cada pareja de triángulos se convierta en un cuadrado unidad.
Sumar (x + y)·F a las dos coordenadas hace exactamente eso; después, floor
funciona como en cualquier rejilla cuadrada.
const SQRT3 = Math.sqrt(3);
export const SKEW = (SQRT3 - 1) / 2; // F = (√3 − 1) / 2 ≈ 0.366
export const UNSKEW = (3 - SQRT3) / 6; // G = (3 − √3) / 6 ≈ 0.211
// Islands shrinks the input by √3 so features are about as large as on the square lattice.
export const SHRINK = 1 / SQRT3;
export function simplexCell(x, y) {
x *= SHRINK; y *= SHRINK;
const skew = (x + y) * SKEW;
const sx = x + skew, sy = y + skew;
const i0 = Math.floor(sx), j0 = Math.floor(sy);
…
} ¿Por qué encoger primero en √3?
Solo para que el ruido se pueda comparar con las versiones de red cuadrada. A lo largo de la diagonal que pasa por el origen, los puntos de la red cuadrada están a √2 de distancia y las esquinas de los triángulos a √(2/3). Dividir la frecuencia entre √3 los hace coincidir, así que la misma frecuencia da rasgos de tamaño parecido. Catlike Coding lo deduce; Islands lo copia.
2. Qué triángulo
El cuadrado sesgado está dividido por su diagonal de (i, j) a (i+1, j+1). Si la fracción x del punto es mayor que su fracción y, queda por debajo de la diagonal y la tercera esquina es (i+1, j); si no, es (i, j+1). El pequeño diagrama del panel muestra este cuadrado.
// Which triangle of the rhombus: below or above its diagonal.
const xGy = sx - i0 > sy - j0;
return { x, y, sx, sy, corners: [[i0, j0], [i0 + 1, j0 + 1], xGy ? [i0 + 1, j0] : [i0, j0 + 1]] }; 3. Desesgar las esquinas
Las distancias solo tienen sentido en el espacio real, así que cada esquina se devuelve restando (i + j)·G y el desplazamiento hasta el punto se toma ahí. F y G están elegidos para que sesgar y desesgar se deshagan mutuamente.
const cell = simplexCell(x, y);
let v = 0, dx = 0, dy = 0, dxx = 0;
for (const [i, j] of cell.corners) {
// Unskew the corner back to real space and take the offset to the point.
const unskew = (i + j) * UNSKEW;
const k = kernel(gradient(i, j), cell.x - i + unskew, cell.y - j + unskew);
v += k.v; dx += k.dx; dy += k.dy; dxx += k.dxx;
}
// Chain rule for the shrink by √3.
return { v, dx: dx * SHRINK, dy: dy * SHRINK, dxx: dxx * SHRINK * SHRINK }; 4. Un núcleo redondo en vez de una mezcla
Cada esquina aporta su rampa de gradiente, como en la parte 3, multiplicada por (½ − d²)³, donde d es la distancia. Ese bulto vale 1/8 en el centro, así que Islands lo multiplica por 8, y vale cero más allá de d² = ½. Los tres aportes simplemente se suman.
// One corner's radial kernel times its gradient ramp. (ox, oy): offset from the corner to
// the point, in unskewed space. The kernel 8(0.5 − r²)³ reaches zero at r = √0.5.
function kernel(g, ox, oy) {
const f = 0.5 - ox * ox - oy * oy;
if (f <= 0) return { v: 0, dx: 0, dy: 0, dxx: 0 };
const ramp = g[0] * ox + g[1] * oy;
return {
v: 8 * f * f * f * ramp,
dx: 8 * f * f * (f * g[0] - 6 * ox * ramp),
dy: 8 * f * f * (f * g[1] - 6 * oy * ramp),
…
};
} ¿Por qué justo ½?
En el espacio encogido y desesgado, los triángulos tienen lados de √(2/3) y alturas de √½. Un radio de √½ deja que cada esquina llegue al lado opuesto de su triángulo, de modo que los tres núcleos cubren todos los puntos, pero se detiene antes de la esquina siguiente, y por eso el ruido sigue valiendo cero en cada esquina.
5. Dos conjuntos de gradientes
Islands puede poner dos tipos de gradiente en los triángulos. Perlin reutiliza el rombo de la parte 3, escala incluida; es el valor por defecto del terreno. Simplex normaliza esas mismas direcciones a longitud 1 y usa la escala que corresponde a los triángulos. Cambia entre ellos en la escena y mira el rango en el panel.
export const GRADIENTS = {
// Perlin's diamond, scaled as in part 3: the default for terrain in Islands' map pipeline.
perlin: latticeGradient,
// The same directions normalised to length 1, then scaled to span about [-1, 1].
simplex: (seed, i, j) => {
const [gx, gy] = latticeGradient(seed, i, j), k = (5.832 / Math.SQRT2) / Math.hypot(gx, gy);
return [gx * k, gy * k];
},
}; 6. Dibujar triángulos
Las líneas de la red son los sitios donde sx, sy o sx − sy son números enteros. Cada una es una recta a·x + b·y = k en el espacio real, así que la escena dibuja tres familias de rectas y recorta cada una a la pantalla.
// In skewed space the triangles are bounded by sx = k, sy = k and sx − sy = k.
const a = SHRINK * (1 + SKEW), b = SHRINK * SKEW;
lineFamily(a, b, toX, toY, x1, y1);
lineFamily(b, a, toX, toY, x1, y1);
lineFamily(SHRINK, -SHRINK, toX, toY, x1, y1); Para ir más lejos
- Pasa a 3D. El cubo se sesga del mismo modo y se divide en seis tetraedros; ordenar las tres fracciones elige uno. Islands tiene
Simplex3D. - Ajusta la escala a la red. Prueba el rombo de Perlin con una escala medida para triángulos y compara el rango con el valor por defecto de Islands.
- Apila varias frecuencias de este ruido y tendrás ruido fractal, que es como Islands construye el terreno: una página posterior de esta serie.
SourcesFuentes
- J. Flick, "Pseudorandom Noise: Simplex Noise", Catlike Coding (2021). The design Islands.Noise follows, including the 1/√3 frequency, the 8(½ − d²)³ kernel and the 5.832/√2 scale; code under MIT-0. catlikecoding.com/unity/tutorials/pseudorandom-noise/simplex-noise/
- K. Perlin, "Noise Hardware", chapter 2 of the SIGGRAPH 2002 course notes on real-time shading (course 36). Simplex noise, first presented in the 2001 notes. userpages.cs.umbc.edu/olano/s2002c36/ch02.pdf
- S. Gustavson, "Simplex noise demystified" (2005). The skew and unskew factors and a step-by-step 2D implementation. itn-web.it.liu.se/~stegu76/simplexnoise/simplexnoise.pdf
- K. Perlin, "Standard for Perlin noise", US patent 6,867,776 B2 (filed 2002, granted 2005, expired 2022). patents.google.com/patent/US6867776B2/en
- A. Lagae, S. Lefebvre, R. Cook, T. DeRose, G. Drettakis, D. S. Ebert, J. P. Lewis, K. Perlin, M. Zwicker, "A Survey of Procedural Noise Functions", Computer Graphics Forum 29(8) (2010) 2579–2600. doi.org/10.1111/j.1467-8659.2010.01827.x
Part of Islands Lab. Tutorial format and noise design after Catlike Coding.Parte de Islands Lab. Formato de tutorial y diseño del ruido según Catlike Coding.