El efecto Moiré

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

En los anteriores artículos hemos introducido algunos conceptos fundamentales del dibujo con Processing, lo que no está nada mal, para sentar unas bases de las que partir. Pero a programar se aprende programando. Y eso es lo que vamos a hacer en este artículo. Vamos a crear un programa, comprobar qué funciona cómo esperamos, y luego explicaremos cómo y por que funciona. Esto hará este artículo más interesante y entretenido.

EL EFECTO MOIRÉ

ventana_de_moire¿Alguna vez lo habías oido mencionar? Se trata de un efecto óptico que se produce cuando hay dibujadas muchas líneas casi paralelas pero que, al cruzarse, crean un punto de convergencia en el que parecen mezclarse unas con otras. Por lo visto es una cuestión de física del ojo, en ese sentido no puedo decirte mucho más, ya que no es mi campo. Si estás interesado, quizá quieras leer este artículo.

Lo que nos importa es que vamos a hacer que nuestro sketch processing genere un dibujo con el efecto Moiré. Pero no solo eso. Vamos a ir más allá. Haremos que, al arrastrar el puntero del ratón sobre la ventana de ejecución, las líneas se redibujen, de forma que el punto de convergencia siga al ratón (al menos, claro, hasta que lo saquemos fuera de la ventana dónde se ejecuta el sketch).

El aspecto será parecido a lo que ves en la imagen de la izquierda aunque, desde luego, la ejecución real es mucho más dinámica cuando la pruebas en tu ordenador.

EL SKETCH

Vamos a reproducir el listado del sketch completo, para que lo copies en tu Processing, y lo ejecutes para ver su funcionamiento.

Cópialo, pruébalo, y veamos como funciona.

Lo primero que tenemos que observar indefectiblemente es una similitud muy clara con los sketches de Arduino. Hay tres secciones en este ejemplo claramente diferenciadas. En la primera se definen las variables que se van a usar en el sketch, aunque, en este caso, se sólo una:

int intervalo = 7;

Usaremos esta variable para determinar la distancia en píxeles entre líneas, cómo verás en seguida.

Dentro de la sección setup() tenemos dos instrucciones que ya conocemos y que establecen el tamaño de la superficie dónde se ejecutará el sketch, y el color de las líneas:

size(250,180);
stroke(0,200,200);

También tenemos una instrucción nueva:

noCursor();

Esto hace que, cuando se posiciona el puntero sobre la ventana de ejecución, sea invisible. Esta instrucción no usa argumentos. Cómo alternativa, podríamos haber puesto la intrucción cursor() que, en función de los argumentos recibidos puede mostar el puntero del ratón de distintos modos, cómo ves en este enlace.

En conjunto, la sección setup() cumple la misma misión que en los sketchs Arduino. Se ejecuta una única vez al principio del sketch, y se usa para establecer los parámetros que deben estar presentes durante todo el ciclo de vida del mismo.

A continuación encontramos la sección draw(). Esta actúa del mismo modo que la sección loop() de Arduino. Se ejecuta de principio a fin, y vuelta al oprincipio, en un bucle inacabable. Y ahora vamos a ver que es lo que se ejecuta.

Antes de empezar con el proceso en sí, vamos a detallar cuatro variables de Processing que necesitamos conocer. Son propias del lenguaje. Tienen nombres predefinidos (no podemos cambiarlos) y no podemos usar estos nombres para variables que definamos nosotros (Processing tiene algunas variables propias del lenguaje más, aparte de estas, pero aquí vamos a hablar sólo de las que usamos en el sketch de este artículo).

  • La variable width. Contiene la anchura de la superficie o lienzo de ejecución que hayamos establecido con el primer parámetro de size(). Si no usamos esta instrucción, la variable width contiene 100, que es el valor por defecto.
  • La variable height. Contiene la anchura de la superficie o lienzo de ejecución que hayamos establecido con el segundo parámetro de size(). Si no usamos esta instrucción, la variable height contiene 100, que es el valor por defecto.
  • La variable mouseX. Contiene la posición horizontal del puntero del ratón con respecto al borde izquierdo de la superficie de ejecución del sketch. Se mantiene constantemente actualizada, según el movimiento del ratón. Antes de que el ratón entre en la superficie de ejecución, vale 0. Si sacamos el ratón de la superficie de ejecución, conserva el último valor que tuvo. Por esta razón, nos permite determinar, en tiempo real, la distancia en píxeles entre el borde izquierdo del lienzo y el puntero (que, con independencia de que lo hayamos hecho invisible con noCursor(), está ahí; que se vea o no es irrelevante a este efecto).
  • La variable mouseY. Contiene la posición horizontal del puntero del ratón con respecto al borde superior de la superficie de ejecución del sketch. Se mantiene constantemente actualizada, según el movimiento del ratón. Antes de que el ratón entre en la superficie de ejecución, vale 0. Si sacamos el ratón de la superficie de ejecución, conserva el último valor que tuvo. Por esta razón, nos permite determinar, en tiempo real, la distancia en píxeles entre el borde superior del lienzo y el puntero (que, con independencia de que lo hayamos hecho invisible con noCursor(), está ahí; que se vea o no es irrelevante a este efecto).

Veamos lo que ocurre en la sección draw(). Lo primero es que se borra todo el lienzo de trabajo, con el color de fondo deseado (en este ejemplo, negro). Esto es así porque en cada ejecución, se van a dibujar todas las líneas que necesitamos, por lo que, si no borraramos el lienzo, se añadirían a las que hubiera de anteriores ejecuciones, impidiéndonos apreciar el efecto que pretendemos:

background(0);

Ahora entramos en un bucle que dibuja lineas que van desde el borde izquierdo a la posición del ratón, cada 7 píxeles de altura, y desde el borde derecho hasta la posición del ratón, cada siete píxeles de altura. El hecho de que sea cada 7 píxeles es porque es lo que hemos establecido con la variable intervalo. Si cambiamos este valor vermos las líneas más próximas (si lo reducimos), o más distantes (si lo aumentamos).

for(int i = 0; i <= height; i += intervalo) {
    line(0,i,mouseX,mouseY);
    line(width,i,mouseX,mouseY);
}

Fíjate en que las líneas las trazamos desde la posición indicada en cada borde (es decir, empezándolas a distintas alturas en cada ejecución del bucle) hasta la posición del puntero, donde convergen. Por esta razón no son realmente paralelas.

La estructura del bucle es la misma que en Arduino (y en PHP, en Java, y en casi cualquier lenguaje de programación, si a eso vamos), por lo que no vamos a entrar en detalles.

Dentro del bucle, las dos únicas intrucciones que hay son line(), que ya conocemos de un artículo anterior.

Si todavía no ves clara la operativa de este bucle, haz una cosa. Borra el segundo bucle provisionalmente (o ponlo cómo comentarios, para que no opere), y ejecuta de nuevo el sketch. En cuanto muevas el puntero por el lienzo lo verás claramente.

El segundo bucle hace lo mismo, pero con líneas que van desde el borde superior a la posición del ratón, originándose a 7 píxeles de distancia unas de otras, y desde el borde inferior a la posición del ratón, en las mismas condiciones.

Cómo ves, prácticamente no hemos traido nada nuevo, pero hemos aprovechado lo que ya sabíamos (bueno, si, alguna cosita nueva hemos traido, cómo la posición del puntero, pero así crecemos poco a poco).

Es gracias a la elevada velocidad conque se completa el bucle draw() y se vuelve a empezar que no notamos nada raro, cómo parpadeos, ni apreciamos el borrado de pantalla en cada ejecución.

     

Un comentario:

  1. Pingback: El teclado y la ventana » eldesvandejose.com

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *