Value Noise
Part 1 gave every grid point a random number. Blend those numbers smoothly between the points and you get value noise, the simplest noise there is. Switch between four ways of blending, light the result as terrain, and watch where the creases appear. How it works.
La parte 1 dio un número aleatorio a cada punto de la rejilla. Mezcla esos números con suavidad entre los puntos y obtienes ruido de valor, el ruido más simple que existe. Cambia entre cuatro formas de mezclar, ilumina el resultado como si fuera terreno y mira dónde aparecen los pliegues. Cómo funciona.
The idea in plain words
Take the grid from part 1, where every point has a random number, and read each number as a height. Value noise fills in the space between the points with smooth slopes, so the random heights become rolling ground. That is the whole idea: random values on a lattice, blended.
Picture tent poles of random heights standing on a square grid, with a cloth laid over them. The analogy has limits. A real cloth sags between poles and slides off the tall ones; this cloth never dips below the lowest pole of its square or rises above the highest, and it lies perfectly flat on top of every pole. A second picture: joining the dots of a chart. Straight lines between the dots give corners; curves that ease into each dot give smooth hills.
The blending is the part to play with. Choose None and you get part 1 again, one flat colour per square. Then switch the view to Shaded relief and step through Linear, Smoothstep and Quintic: the lighting shows creases that the height view hides.
Why it matters, and the catch
Value noise is the cheapest smooth noise there is: four hashes and three blends per sample. Its skeleton (find the cell, fade the position inside it, interpolate the corners) is the same in Perlin and simplex noise, the next pages in this series, so this is where the machinery gets built.
The catch is that the grid shows through. Every peak and every pit of value noise sits exactly on a lattice point, so the hills line up in rows and columns. Switch to Slope and the lattice appears as a pattern of dark lines: with a smooth blend, the ground is flat across every grid line. And the values bunch up towards the middle. The histogram in the panel is no longer flat like the one in part 1, because blending averages, and averages avoid extremes.
Islands has value noise, built exactly this way, but its map pipeline does not use it for terrain; it defaults to gradient noise. Its own technique notes give the reason in one line: grid artefacts.
Is there a theorem?
Several small ones, all provable with a pencil, which is part of the charm.
- Peaks live on the lattice. Inside one cell the value is a weighted average of the four corners, with weights between 0 and 1. An average can never exceed the largest of the numbers it averages, so the highest point of every cell is one of its corners. Measured on 4 seeds of 1,600 cells each: 1,210 local maxima, every one of them on a lattice point.
- The grid lines are flat. If the fade curve has zero slope at both ends, as smoothstep and the quintic do, then the slope across every grid line is exactly zero. Every lattice point is therefore a flat spot: a peak, a pit or a saddle.
- Smoothness is set by the fade. No blend gives jumps in the value itself. Linear blending is continuous but its slope jumps at the grid lines; smoothstep keeps the slope continuous but its curvature jumps from +6 to −6; the quintic makes the curvature vanish at both ends too, so it is continuous up to the second derivative. Ken Perlin introduced the quintic in 2002 for exactly this reason: the curvature jumps of the older cubic showed up as visible artefacts on lit, displaced surfaces.
Nothing deep remains open here. The interesting questions start when the random values are replaced by random slopes, which is the next page.
The equations
For a point (x, y), the cell is (i, j) = (⌊x⌋, ⌊y⌋) and the position inside it is tx = x − i, ty = y − j. The corner values a, b, c, d sit at (i, j), (i, j+1), (i+1, j) and (i+1, j+1).
- Linear: s(t) = t
- Smoothstep: s(t) = 3t² − 2t³, s′(t) = 6t(1 − t), s″(t) = 6 − 12t
- Quintic: s(t) = 6t⁵ − 15t⁴ + 10t³, s′(t) = 30t²(t − 1)², s″(t) = 60t(2t − 1)(t − 1)
- Value noise: f = lerp(lerp(a, b, sy), lerp(c, d, sy), sx), with sx = s(tx), sy = s(ty)
- Slope along x: ∂f/∂x = [lerp(c, d, sy) − lerp(a, b, sy)] · s′(tx)
Read the main line from the inside out: blend along y on the left edge of the cell, blend along y on the right edge, then blend those two results along x. The slope formula says why the grid lines are flat: s′(0) = s′(1) = 0 for both smooth fades, so the whole expression is zero wherever tx is 0 or 1.
What the picture does and does not say
- Each lattice value is one byte of the hash, so there are only 256 possible heights at the lattice points. Between them, the blend is continuous.
- The shaded relief treats the noise as ground 0.35 units high per unit of value, lit from the upper left. A different height scale changes how strong the creases look, not where they are.
- In the profile, each curve is scaled to fit its own range; compare shapes and jumps, not heights. For linear blending the curvature is zero inside each cell and infinite on the grid lines, which a plot can only show as a flat line.
- The histogram counts the pixels on screen, so it changes as you move. Measured over 4 seeds of 1,600 cells each, the quintic blend has a standard deviation of 0.46 against 0.58 for the lattice values, and only 32 % of values beyond ±0.5, against 51 %.
- The code is a JavaScript port of Islands' 2D value noise. Checked against a C# replica of the same code at 15 points with three seeds, value and derivatives agree to within 2 × 10⁻⁶, the difference between C#'s single precision and JavaScript's double precision. Islands samples the horizontal x–z plane; this page calls the second axis y.
How it works
This part walks through the code of the scene, step by step. It covers:
- Turning hashes into lattice values.
- Finding the cell and the position inside it.
- Fade curves, and what their derivatives decide.
- Blending the four corners.
- Computing exact derivatives alongside the value.
- Rendering hundreds of thousands of samples fast enough to drag.
- Lighting a surface from its derivatives.
Plain JavaScript and the Canvas 2D API, no libraries. The noise itself is about 50 lines and reuses the hash from part 1; the scene is about 300. It follows the value noise part of Catlike Coding's Pseudorandom Noise, which is also where the C# in Islands comes from.
1. A value for every lattice point
The lattice is the grid of integer points. Each one gets the hash of its coordinates from part 1. Islands reads byte A and maps its 256 levels to the range −1 to 1, and so do we.
// The random value at a lattice point: byte A of the hash, mapped to [-1, 1].
export function latticeValue(seed, i, j) {
return byteOf(hash2(seed, i, j), 0) * (2 / 255) - 1;
} 2. Which cell, and where inside it
For any point, floor gives the lattice point at the corner of its
cell with the smallest coordinates, and the remainder t, between 0 and 1, says how far across the cell it
lies. With no blending at all, every point takes the value of its nearest corner: choose
None and the picture is the grid of part 1, offset by half a cell.
const i = Math.floor(x), j = Math.floor(y);
const fx = fade(x - i), fy = fade(y - j); 3. Fade curves
Blending straight from t gives linear interpolation. Passing t
through an S-shaped curve first makes each blend ease in and out of the corners. Each curve
comes with its first and second derivatives, because those decide how smooth the result is.
export const FADES = {
nearest: (t) => ({ s: t < 0.5 ? 0 : 1, ds: 0, dds: 0 }),
linear: (t) => ({ s: t, ds: 1, dds: 0 }),
smoothstep: (t) => ({ s: t * t * (3 - 2 * t), ds: 6 * t * (1 - t), dds: 6 - 12 * t }),
// 6t^5 - 15t^4 + 10t^3
quintic: (t) => ({
s: t * t * t * (t * (t * 6 - 15) + 10),
ds: t * t * (t * (t * 30 - 60) + 30),
dds: t * (t * (t * 120 - 180) + 60),
}),
}; Watch the profile in the panel. With Linear, the dashed slope curve jumps at every vertical line. With Smoothstep the slope is continuous, but the dotted curvature jumps. With Quintic both are continuous.
Why does the curvature matter if the eye only sees heights?
Because lighting depends on the surface normal, which comes from the slope, and the way light changes across a surface depends on how the slope changes: the curvature. A jump in curvature becomes a visible line in the shading. That is the artefact Perlin's 2002 paper removed by switching from the cubic to the quintic.
4. Blending the corners
In two dimensions there are four corners. Blend along y on the left edge and on the right edge, then blend those two results along x. Swapping the order gives the same value.
const a = lattice(i, j), b = lattice(i, j + 1);
const c = lattice(i + 1, j), d = lattice(i + 1, j + 1);
// Bilinear blend of the four corners, with faded weights.
const ab = a + (b - a) * fy.s; // left edge, at this y
const cd = c + (d - c) * fy.s; // right edge
return {
v: ab + (cd - ab) * fx.s,
…
}; 5. Exact derivatives for free
The value is built from products of simple terms, so the chain rule gives the slope in closed form, using quantities we already have. Islands does the same: its noise returns the value together with its partial derivatives.
return {
v: ab + (cd - ab) * fx.s,
dx: (cd - ab) * fx.ds,
dy: ((b - a) + ((d - c) - (b - a)) * fx.s) * fy.ds,
dxx: (cd - ab) * fx.dds,
}; Why not estimate the slope from neighbouring samples?
That needs two or four extra noise evaluations per pixel, and the answer depends on the step size. The formula costs a few multiplications and is exact, which matters here: the scene is about showing jumps in the slope, and a finite difference would smear them.
6. Fast enough to drag
The scene samples one point per screen pixel, about 300,000 on a desktop. Hashing four corners for each would mean more than a million hashes per frame. But the visible lattice has only a few hundred points, so we hash those once into an array and look them up.
// Corner values for the visible window, so each pixel does no hashing.
function fillCache(i0, j0, w, h) {
…
const data = new Float32Array(w * h);
for (let j = 0; j < h; j++) for (let i = 0; i < w; i++) data[j * w + i] = latticeValue(state.seed, i0 + i, j0 + j);
cache = { i0, j0, w, h, seed: state.seed, data };
} 7. Light from derivatives
To render Shaded relief, treat the noise as a height field. Its normal is (−∂z/∂x, −∂z/∂y, 1) normalised, and the brightness is the cosine between the normal and the light, clamped at zero. No neighbouring samples are needed.
// Surface z = 0.35 · noise; its normal comes straight from the derivatives.
const nx = -0.35 * n.dx, ny = -0.35 * n.dy, l = Math.hypot(nx, ny, 1);
const lam = Math.max(0, (nx * LIGHT_DIR[0] + ny * LIGHT_DIR[1] + LIGHT_DIR[2]) / l); With Linear the slope jumps at the grid lines, so the light does too: the surface looks like a quilt of facets. The smooth fades remove the facets but not the flat grid lines, which show as soft ridges and grooves aligned with the axes.
The profile draws each curve as one line, except that it lifts the pen where neighbouring samples differ by more than half the curve's range, so jumps look like jumps.
// Break the line where it jumps, so a discontinuity looks like one.
if (k === 0 || Math.abs(v - arr[k - 1]) / m > 0.5) pctx.moveTo(X(k), y); else pctx.lineTo(X(k), y); Going further
- Add a third dimension. Islands'
Lattice3Dblends eight corners instead of four; use the third axis as time and the noise animates. - Make it tile. Islands also has
LatticeTiling, which wraps lattice coordinates around the frequency so the texture repeats without a seam. - Replace each lattice value with a random slope. The grid lines stop being flat, the peaks leave the lattice points, and you have Perlin's gradient noise, the next page.
La idea en palabras sencillas
Toma la rejilla de la parte 1, donde cada punto tiene un número aleatorio, y lee cada número como una altura. El ruido de valor rellena el espacio entre los puntos con pendientes suaves, y las alturas aleatorias se convierten en un terreno ondulado. Esa es toda la idea: valores aleatorios en una red, mezclados.
Imagina postes de carpa de alturas al azar sobre una cuadrícula, con una tela echada por encima. La analogía tiene límites. Una tela real se hunde entre los postes y resbala de los altos; esta tela nunca baja del poste más bajo de su cuadrado ni sube por encima del más alto, y queda perfectamente plana sobre cada poste. Otra imagen: unir los puntos de un gráfico. Las líneas rectas entre puntos dan esquinas; las curvas que llegan a cada punto con suavidad dan colinas lisas.
Lo que hay que tocar es la mezcla. Elige Ninguna y vuelves a la parte 1, un color plano por cuadrado. Después cambia la vista a Relieve sombreado y pasa por Lineal, Smoothstep y Quíntica: la iluminación muestra pliegues que la vista de altura esconde.
Por qué importa, y la trampa
El ruido de valor es el ruido suave más barato que existe: cuatro hashes y tres mezclas por muestra. Su esqueleto (encontrar la celda, suavizar la posición dentro de ella, interpolar las esquinas) es el mismo en el ruido de Perlin y en el simplex, las siguientes páginas de la serie, así que aquí es donde se construye la maquinaria.
La trampa es que la rejilla se transparenta. Cada cumbre y cada hoyo del ruido de valor cae exactamente sobre un punto de la red, así que las colinas se alinean en filas y columnas. Cambia a Pendiente y la red aparece como un dibujo de líneas oscuras: con una mezcla suave, el terreno es plano en perpendicular a cada línea de la rejilla. Y los valores se amontonan hacia el centro. El histograma del panel ya no es plano como el de la parte 1, porque mezclar es promediar, y los promedios evitan los extremos.
Islands tiene ruido de valor, construido exactamente así, pero su pipeline de mapas no lo usa para el terreno: por defecto usa ruido de gradiente. Sus propias notas de técnicas dan el motivo en una línea: los artefactos de rejilla.
¿Hay un teorema?
Varios pequeños, todos demostrables con lápiz, y eso es parte de la gracia.
- Las cumbres viven en la red. Dentro de una celda, el valor es un promedio ponderado de las cuatro esquinas, con pesos entre 0 y 1. Un promedio nunca supera el mayor de los números que promedia, así que el punto más alto de cada celda es una de sus esquinas. Medido en 4 semillas de 1.600 celdas cada una: 1.210 máximos locales, todos sobre un punto de la red.
- Las líneas de la rejilla son planas. Si la curva de mezcla tiene pendiente cero en sus dos extremos, como smoothstep y la quíntica, la pendiente a través de cada línea de la rejilla es exactamente cero. Cada punto de la red es entonces un punto plano: una cumbre, un hoyo o un punto de silla.
- La suavidad la decide la curva. Ninguna mezcla da saltos en el valor. La mezcla lineal es continua, pero su pendiente salta en las líneas de la rejilla; smoothstep mantiene continua la pendiente, pero su curvatura salta de +6 a −6; la quíntica anula también la curvatura en los dos extremos, así que es continua hasta la segunda derivada. Ken Perlin introdujo la quíntica en 2002 justo por eso: los saltos de curvatura de la cúbica anterior se veían como artefactos en superficies iluminadas y desplazadas.
Aquí no queda nada profundo abierto. Las preguntas interesantes empiezan cuando los valores aleatorios se sustituyen por pendientes aleatorias, que es la página siguiente.
Las ecuaciones
Para un punto (x, y), la celda es (i, j) = (⌊x⌋, ⌊y⌋) y la posición dentro de ella es tx = x − i, ty = y − j. Los valores de las esquinas a, b, c, d están en (i, j), (i, j+1), (i+1, j) e (i+1, j+1).
- Lineal: s(t) = t
- Smoothstep: s(t) = 3t² − 2t³, s′(t) = 6t(1 − t), s″(t) = 6 − 12t
- Quíntica: s(t) = 6t⁵ − 15t⁴ + 10t³, s′(t) = 30t²(t − 1)², s″(t) = 60t(2t − 1)(t − 1)
- Ruido de valor: f = lerp(lerp(a, b, sy), lerp(c, d, sy), sx), con sx = s(tx), sy = s(ty)
- Pendiente en x: ∂f/∂x = [lerp(c, d, sy) − lerp(a, b, sy)] · s′(tx)
La línea principal se lee de dentro afuera: mezcla en y por el borde izquierdo de la celda, mezcla en y por el borde derecho, y luego mezcla esos dos resultados en x. La fórmula de la pendiente explica por qué las líneas de la rejilla son planas: s′(0) = s′(1) = 0 en las dos curvas suaves, así que la expresión entera vale cero donde tx es 0 o 1.
Lo que la imagen dice y lo que no
- Cada valor de la red es un byte del hash, así que en los puntos de la red solo hay 256 alturas posibles. Entre ellos, la mezcla es continua.
- El relieve sombreado trata el ruido como un terreno de 0,35 unidades de alto por unidad de valor, iluminado desde arriba a la izquierda. Otra escala de altura cambia cuánto se marcan los pliegues, no dónde están.
- En el perfil, cada curva se escala a su propio rango: compara formas y saltos, no alturas. Con la mezcla lineal, la curvatura es cero dentro de cada celda e infinita en las líneas de la rejilla, y un gráfico solo puede mostrarlo como una línea plana.
- El histograma cuenta los píxeles en pantalla, así que cambia al moverte. Medido en 4 semillas de 1.600 celdas cada una, la mezcla quíntica tiene una desviación típica de 0,46 frente a 0,58 de los valores de la red, y solo un 32 % de valores más allá de ±0,5, frente al 51 %.
- El código es un port a JavaScript del ruido de valor 2D de Islands. Comparado con una réplica en C# del mismo código en 15 puntos y tres semillas, valor y derivadas coinciden con una diferencia menor que 2 × 10⁻⁶, la que hay entre la precisión simple de C# y la doble de JavaScript. Islands muestrea el plano horizontal x–z; esta página llama y al segundo eje.
Cómo funciona
Esta parte recorre el código de la escena, paso a paso. Cubre:
- Convertir hashes en valores de la red.
- Encontrar la celda y la posición dentro de ella.
- Las curvas de mezcla, y lo que deciden sus derivadas.
- Mezclar las cuatro esquinas.
- Calcular derivadas exactas junto con el valor.
- Dibujar cientos de miles de muestras lo bastante rápido como para arrastrar.
- Iluminar una superficie a partir de sus derivadas.
JavaScript puro y la API Canvas 2D, sin librerías. El ruido en sí ocupa unas 50 líneas y reutiliza el hash de la parte 1; la escena, unas 300. Sigue la parte de ruido de valor de Pseudorandom Noise de Catlike Coding, que es también de donde viene el C# de Islands. Los comentarios del código están en inglés.
1. Un valor para cada punto de la red
La red es la rejilla de puntos enteros. Cada uno recibe el hash de sus coordenadas de la parte 1. Islands lee el byte A y lleva sus 256 niveles al rango de −1 a 1, y nosotros igual.
// The random value at a lattice point: byte A of the hash, mapped to [-1, 1].
export function latticeValue(seed, i, j) {
return byteOf(hash2(seed, i, j), 0) * (2 / 255) - 1;
} 2. Qué celda, y dónde dentro de ella
Para cualquier punto, floor da el punto de la red en la esquina de
coordenadas más pequeñas de su celda, y el resto t, entre 0 y 1, dice cuánto ha avanzado dentro
de la celda. Sin ninguna mezcla, cada punto toma el valor de su esquina más cercana: elige
Ninguna y la imagen es la rejilla de la parte 1, desplazada media celda.
const i = Math.floor(x), j = Math.floor(y);
const fx = fade(x - i), fy = fade(y - j); 3. Curvas de mezcla
Mezclar directamente con t es interpolación lineal. Pasar antes t
por una curva en forma de S hace que cada mezcla entre y salga de las esquinas con suavidad.
Cada curva viene con su primera y su segunda derivada, porque son las que deciden lo suave
que queda el resultado.
export const FADES = {
nearest: (t) => ({ s: t < 0.5 ? 0 : 1, ds: 0, dds: 0 }),
linear: (t) => ({ s: t, ds: 1, dds: 0 }),
smoothstep: (t) => ({ s: t * t * (3 - 2 * t), ds: 6 * t * (1 - t), dds: 6 - 12 * t }),
// 6t^5 - 15t^4 + 10t^3
quintic: (t) => ({
s: t * t * t * (t * (t * 6 - 15) + 10),
ds: t * t * (t * (t * 30 - 60) + 30),
dds: t * (t * (t * 120 - 180) + 60),
}),
}; Mira el perfil del panel. Con Lineal, la curva discontinua de la pendiente salta en cada línea vertical. Con Smoothstep la pendiente es continua, pero la curvatura punteada salta. Con Quíntica las dos son continuas.
¿Por qué importa la curvatura si el ojo solo ve alturas?
Porque la iluminación depende de la normal de la superficie, que sale de la pendiente, y la forma en que cambia la luz a lo largo de una superficie depende de cómo cambia la pendiente: la curvatura. Un salto de curvatura se convierte en una línea visible en el sombreado. Ese es el artefacto que el artículo de Perlin de 2002 eliminó al pasar de la cúbica a la quíntica.
4. Mezclar las esquinas
En dos dimensiones hay cuatro esquinas. Mezcla en y por el borde izquierdo y por el borde derecho, y luego mezcla esos dos resultados en x. Cambiar el orden da el mismo valor.
const a = lattice(i, j), b = lattice(i, j + 1);
const c = lattice(i + 1, j), d = lattice(i + 1, j + 1);
// Bilinear blend of the four corners, with faded weights.
const ab = a + (b - a) * fy.s; // left edge, at this y
const cd = c + (d - c) * fy.s; // right edge
return {
v: ab + (cd - ab) * fx.s,
…
}; 5. Derivadas exactas casi gratis
El valor se construye con productos de términos simples, así que la regla de la cadena da la pendiente en forma cerrada, con cantidades que ya tenemos. Islands hace lo mismo: su ruido devuelve el valor junto con sus derivadas parciales.
return {
v: ab + (cd - ab) * fx.s,
dx: (cd - ab) * fx.ds,
dy: ((b - a) + ((d - c) - (b - a)) * fx.s) * fy.ds,
dxx: (cd - ab) * fx.dds,
}; ¿Por qué no estimar la pendiente con muestras vecinas?
Eso exige dos o cuatro evaluaciones de ruido más por píxel, y el resultado depende del tamaño del paso. La fórmula cuesta unas pocas multiplicaciones y es exacta, lo que aquí importa: la escena trata de mostrar saltos en la pendiente, y una diferencia finita los emborronaría.
6. Lo bastante rápido como para arrastrar
La escena toma una muestra por píxel de pantalla, unas 300.000 en un escritorio. Hashear cuatro esquinas para cada una supondría más de un millón de hashes por fotograma. Pero la red visible solo tiene unos cientos de puntos, así que los hasheamos una vez en un array y los consultamos.
// Corner values for the visible window, so each pixel does no hashing.
function fillCache(i0, j0, w, h) {
…
const data = new Float32Array(w * h);
for (let j = 0; j < h; j++) for (let i = 0; i < w; i++) data[j * w + i] = latticeValue(state.seed, i0 + i, j0 + j);
cache = { i0, j0, w, h, seed: state.seed, data };
} 7. Luz a partir de derivadas
Para dibujar el Relieve sombreado, se trata el ruido como un campo de alturas. Su normal es (−∂z/∂x, −∂z/∂y, 1) normalizada, y el brillo es el coseno entre la normal y la luz, sin bajar de cero. No hacen falta muestras vecinas.
// Surface z = 0.35 · noise; its normal comes straight from the derivatives.
const nx = -0.35 * n.dx, ny = -0.35 * n.dy, l = Math.hypot(nx, ny, 1);
const lam = Math.max(0, (nx * LIGHT_DIR[0] + ny * LIGHT_DIR[1] + LIGHT_DIR[2]) / l); Con Lineal, la pendiente salta en las líneas de la rejilla y la luz también: la superficie parece un acolchado de facetas. Las curvas suaves quitan las facetas, pero no las líneas planas de la rejilla, que se ven como crestas y surcos suaves alineados con los ejes.
El perfil dibuja cada curva como una sola línea, salvo que levanta el lápiz donde dos muestras vecinas difieren en más de la mitad del rango de la curva, para que los saltos se vean como saltos.
// Break the line where it jumps, so a discontinuity looks like one.
if (k === 0 || Math.abs(v - arr[k - 1]) / m > 0.5) pctx.moveTo(X(k), y); else pctx.lineTo(X(k), y); Para ir más lejos
- Añadir una tercera dimensión.
Lattice3Dde Islands mezcla ocho esquinas en vez de cuatro; usa el tercer eje como tiempo y el ruido se anima. - Hacer que se repita sin costuras. Islands tiene también
LatticeTiling, que da la vuelta a las coordenadas de la red según la frecuencia para que la textura se repita sin que se note el borde. - Sustituir cada valor de la red por una pendiente aleatoria. Las líneas de la rejilla dejan de ser planas, las cumbres se apartan de los puntos de la red y tienes el ruido de gradiente de Perlin, la página siguiente.
SourcesFuentes
- J. Flick, "Pseudorandom Noise: Value Noise", Catlike Coding (2021). The design Islands.Noise follows; code under MIT-0. catlikecoding.com/unity/tutorials/pseudorandom-noise/value-noise/
- K. Perlin, "Improving noise", ACM Trans. Graph. 21(3) (2002) 681–682. Introduces the quintic fade 6t⁵ − 15t⁴ + 10t³. doi.org/10.1145/566654.566636
- K. Perlin, "An image synthesizer", SIGGRAPH '85, Computer Graphics 19(3) 287–296. doi.org/10.1145/325165.325247
- 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
- I. Quílez, "Value noise derivatives" (2008). iquilezles.org/articles/morenoise/
- I. Quílez, "Smoothstep variants": continuity of the common fade curves. iquilezles.org/articles/smoothsteps/
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.