If you're seeing this message, it means we're having trouble loading external resources on our website.

Si estás detrás de un filtro de páginas web, por favor asegúrate de que los dominios *.kastatic.org y *.kasandbox.org estén desbloqueados.

Contenido principal

Ruido Perlin

Un buen generador de números aleatorios produce números que no tienen relación y que no muestran un patrón discernible. Como estamos empezando a ver, un poco de aleatoriedad puede ser algo bueno cuando se programan comportamientos orgánicos, naturales. Sin embargo, la aleatoriedad como el único principio guía no es necesariamente natural.
Hay un algoritmo que produce resultados más naturales, y que se conoce como “ruido Perlin". Ken Perlin desarrolló la función de ruido mientras trabajaba en la película original de Tron al principio de la década de 1980; la usó para crear texturas procedurales de efectos generados por computadora. En 1997, Perlin ganó un premio de la Academia de logro técnico por este trabajo. El ruido Perlin se puede usar para generar varios efectos con cualidades naturales como nubes, paisajes y texturas estampadas como mármol.
El ruido Perlin tiene un aspecto más orgánico porque produce una secuencia naturalmente ordenada (“suave”) de números pseudoaleatorios. La gráfica a continuación muestra ruido Perlin a través del tiempo, con el eje x que representa al tiempo; observa la suavidad de la curva.
Imagen de la Naturaleza del Código
Figura I.5: ruido
De manera contrastante, la siguiente gráfica a continuación muestra números aleatorios puros a través del tiempo.
Imagen de la Naturaleza del Código
Figura I.6: aleatorio
ProcessingJS tiene una implementación del algoritmo de ruido Perlin integrada: la función noise(). La función noise() toma uno, dos o tres argumentos, ya que el ruido se calcula en una, dos o tres dimensiones. Empecemos por ver el ruido unidimensional.

Detalle del ruido

La referencia del ruido nos dice que el ruido se calcula a través de varias “octavas”. Llamar la función noiseDetail() cambiará tanto el número de octavas como la importancia relativa entre ellas. Esto, a su vez, cambia cómo se comporta el ruido.
Considera dibujar un círculo en nuestra ventana de ProcessingJS en una posición x aleatoria:
var x = random(0, width);
ellipse(x, 180, 16, 16);
Ahora, en lugar de una posición x aleatoria, queremos una posición x con ruido Perlin que sea “más suave”. Podrías pensar que todo lo que necesitas hacer es reemplazar random() con noise(), es decir,
var x = noise(0, width);
ellipse(x, 180, 16, 16);
Mientras que conceptualmente esto es exactamente lo que queremos hacer, calcular un valor de x que oscile entre 0 y el ancho de acuerdo con el ruido Perlin, no es la implementación correcta. Mientras que los argumentos de la función random() especifican un rango de valores entre un mínimo y un máximo, noise() no funciona de esa manera. En cambio, noise() espera que le pasemos un argumento que significa "un momento en el tiempo" y siempre regresa un valor entre 0 y 1. Podemos pensar en el ruido Perlin unidimensional como una secuencia lineal de valores a través del tiempo. Por ejemplo, aquí hay ejemplos de entradas y valores de salida:
TiempoValor de ruido
00.469
0.010.480
0.020.492
0.030.505
0.040.517
Ahora, para poder acceder a uno de esos valores de ruido en ProcessingJS, tenemos que pasarle un momento específico en el tiempo a la función noise(). Por ejemplo:
var n = noise(0.03);
De acuerdo con la tabla anterior, noise() regresará 0.505 al tiempo 0.03. Podemos escribir un programa que almacene una variable de tiempo y pida ese valor de ruido de manera continua en draw().
El código anterior resulta en el mismo valor escrito una y otra vez. Esto sucede porque estamos pidiendo el resultado de la función noise() en el mismo punto en el tiempo una y otra vez.
Sin embargo, si aumentamos la variable de tiempo t, obtendremos un resultado diferente.
La tasa a la cual aumentamos t también afecta la suavidad del ruido. Si hacemos saltos grandes en el tiempo, entonces estamos saltando hacia adelante y los valores serán más aleatorios.
Ruido a través del tiempo
Figura 1.7
Intenta ejecutar el código anterior varias veces, aumentando t en 0.01, 0.02, 0.05, 0.1, 0.0001, y verás resultados diferentes.

Mapear el ruido

Ahora estamos listos para responder a la pregunta de qué hacer con el valor del ruido. Una vez que tengamos el valor con un rango entre 0 y 1, depende de nosotros mapear ese rango a lo que queramos.
Podríamos simplemente multiplicarlo por el número máximo en el rango, pero esta también es una buena oportunidad para introducir la función map() de ProcessingJS, la cual nos ayudará en otras situaciones más adelante. La función map() toma cinco argumentos. El primero es el valor que queremos mapear, en este caso n. Después tenemos que darle el rango actual del valor (mínimo y máximo), seguido de nuestro rango deseado.
Imagen de la Naturaleza del Código
Figura I.8
En este caso, sabemos que el ruido tiene un rango entre 0 y 1, pero nos gustaría dibujar un rectángulo con un ancho de entre 0 y el ancho actual.
Podemos aplicar exactamente la misma lógica a nuestro caminante aleatorio y asignarle sus valores x y y de acuerdo con el ruido Perlin.
Observa cómo el ejemplo anterior requiere un par de variables adicionales: tx y ty. Esto es porque necesitamos llevar un registro de dos variables de tiempo, una para la posición x del objeto Walker y otra para la posición y.
Pero hay algo un poco extraño acerca de esas variables. ¿Por qué tx empieza en 0 y ty en 10,000? Mientras que estos números son opciones arbitrarias, inicializamos de manera muy específica nuestras dos variables de tiempo con valores muy diferentes. Esto es porque la función de ruido es determinista: cada vez te da el mismo resultado para un tiempo específico t. Si pidiéramos el valor de ruido al mismo tiempo t para x y y, entonces x y y siempre serían iguales, lo que significaría que el objeto Walker solo se movería a lo largo de una diagonal. En lugar de eso, simplemente usamos dos partes diferentes del espacio de ruido, empezando en 0 para x y en 10,000 para y de modo que x y y parezcan actuar de manera independiente una de la otra.
Imagen de la Naturaleza del Código
Figura I.9
En verdad, no hay ningún concepto verdadero del tiempo en juego aquí. Es una metáfora útil para ayudarnos a entender cómo funciona la función de ruido, pero en realidad lo que tenemos es espacio, en lugar de tiempo. La gráfica anterior muestra una secuencia lineal de valores de ruido en un espacio unidimensional, y podemos pedir un valor en una posición x específica cada que queramos. En los ejemplos, a menudo verás una variable llamada xoff para indicar el desplazamiento en la dirección x a lo largo de la gráfica de ruido, en vez de t para el tiempo (como se indica en el diagrama).
En el próximo desafío, intentarás usar ruido con el Walker de una manera ligeramente diferente. ¡Que te diviertas!

Este curso de "Simulaciones Naturales" es un derivado de "La Naturaleza del Código" por Daniel Shiffman, usado bajo una Licencia Creative Commons Reconocimiento-NoComercial 3.0 Unported.

¿Quieres unirte a la conversación?

¿Sabes inglés? Haz clic aquí para ver más discusiones en el sitio en inglés de Khan Academy.