Prigmatego #5 from Armando Rodriguez on Vimeo.
José Armando Rodríguez Ibarra 2017 México
/*Se Declara un objeto del tipo Wave, es posible implementar
mas de un sistema de partículas gracias a la clase*/
Wave wave0;
void setup() {
background(255);
//Al implementar P2D, es usado el modo de render por OPENGL
//lo cual permite un framerate mayor al ser implementado
size(1920, 1080, P2D);
// Se inicia el sistema de partículas en el centro de la
//pantalla, largo, amplitud y periodo.
wave0 = new Wave(new PVector(width/2, height/2), 25500, 300, 50);
noFill();
}
void draw() {
background(255);
//método que calcula la posición de la partículas
wave0.calculate();
//método que despliega la imagen
wave0.display();
//saveFrame(«circles-######.png»);
noFill();
}
//Clase partícula
class Particle {
/*Las variables hacen referencia al posición de la partícula y
a una variable baile corresponde al «ruido» o perturbación en la
trayectoria de posición de cada partícula, es llamada baile
por que a través de cambios minúsculos, se obtienen resultados
posiblemente irrepetibles.*/
PVector location;
float baile;
Particle() {
location = new PVector();
baile=random(10000000);
}
void setLocation(float x, float y) {
//Se asignan posiciones a las particulas
location.x = x;
location.y = y;
}
}
/*La clase Wave es la encargada de «dar» forma a las trayectorias
así como del carácter generativo en la aplicación. Wave es interpretado
como un solo trazo, es decir la imagen en realidad está compuesta por un
gran trazo (como dibujar sin despegar el lápiz).*/
class Wave {
int xspacing = 2; //Inicialmente es interpretado como el espaciamiento horizontal
//entre las partículas, pero posteriormente representa el grado de
//saturación de los trazos en la imagen.
int w; //Tamaño del trazo o longitud de Wave.
PVector ahora; //Estos vectores es una manera alternativa de registrar las posiciones
PVector antes; //actuales y pasadas de cada partícula.
PVector origin; //Para indicar el punto de inicio del trazo (Wave).
float theta = 10000.0; //Inicia el ángulo en 10000 dado que a partir de un valor grande
//los cambios en la forma son significativos.
float amplitude; //Amplitud de trazo
float period; //periodo del trazo (también es una senoidal).
float dx; //Valor de incremento en X, calculado en función del periodo y
//espaciamiento.
//Se inicia un sistema de partículas
Particle[] particles;
// Se inicia el sistema de partículas en el centro de la pantalla, largo, amplitud y periodo.
Wave(PVector o, int w_, float a, float p) {
antes = new PVector();
ahora = new PVector();
//Inicia el inicio del trazo en el centro de la ventana
origin = o.get();
w = w_;
period = p;
amplitude = a;
//Cálculo de dx en función del periodo y espaciamiento
dx = (TWO_PI / period) * xspacing;
//La cantidad de partículas iniciadas es determinada por la longitud total de la onda o
//trazo y el espaciamiento en X.
particles = new Particle[int(w/xspacing)];
for (int i = 0; i < particles.length; i++) {
particles[i] = new Particle();
}
}
void calculate() {
//Al incrementar el valor de theta se puede interpretar como la velocidad angular.
theta += 0.02;
/*En esta sección se explica el comportamiento generativo en la función:
El valor de x es aumentado lentamente conforme a la variable theta, que en cuyo caso es una
especie de velocidad angular, la dx cuyo valor es muy pequeño y aumenta lentamente
conforme a la suma de los valores cos(theta)+cos(x) que a su vez afectan minoritariamente el
valor de x. Las variables son interdependientes, excepto theta.
Se eligió esta forma de manipular los valores de las variables para alterar los resultados
obtenidos al emplear únicamente la función noise. Como resultado se tiene una variable X
con un comportamiento no lineal, mientras que la amplitud de la onda si es afectada por el
comportamiento de la función noise() que en cuyo caso toma el valor de la variable «baile»
correspondiente a cada partícula del sistema y es aumentado 0.00003 unidades sobre sí mismo
cada ciclo. El valor final que altera la amplitud es multiplicado por el factor de 10 para
obtener variaciones «orgánicas» de entre 0 y 10 unidades.
39
Finalmente la variable x adentro de las funciones trigonométricas (no confundir con las
coordenadas de puntos de origen) es multiplicada por distintos factores que pueden ser
alterados y dan pie a la creación de diferentes formas a la imagen final. Como se puede
observar la siguiente línea corresponde a la ecuación paramétrica de una función con una
forma específica:
origin.x+(cos(x)*(amplitude+(noise(particles[i].baile)*10))),origin.y+(sin(x*6)*(amplitude+
(noise(particles[i].baile)*10)))
Alterando el factor de multiplicación del sin(x*6) por sin(x), se obtiene una figura
predominantemente circular:
origin.x+(cos(x)*(amplitude+(noise(particles[i].baile)*10))),origin.y+(sin(x)*(amplitude+
(noise(particles[i].baile)*10)))
O alterando el factor de multiplicación del sin(x) por sin(x*2), se obtiene una figura
predominantemente con geometría de infinito:
origin.x+(cos(x)*(amplitude+(noise(particles[i].baile)*10))),origin.y+(sin(x*2)*(amplitude+
(noise(particles[i].baile)*10)))
Es posible emplear estas funciones para crear un sin fin de formas y geometría. */
float x=theta;
for (int i = 0; i < particles.length; i++) {
//las posición es calculada y establecida para cada partícula del sistema
particles[i].setLocation(origin.x+(sin(x+theta)*(amplitude)), origin.y /2 +(cos(sin((2*x+theta/2)))*(amplitude)));
x+=map(mouseX,0,width,0,2*PI);
float ang = x+ 1000;
}
}
void display() {
//El grosor debe ser inferior a un pixel para obtener el efecto de grafito.
strokeWeight(0.5);
stroke(0, 20);
/*La posición de cada partícula representa un punto que junto a la posición de la partícula
anterior, forma un trazo de línea recta (Se evita calcular con la primera partícula para no
crear trazos «basura»).*/
for (int i = 0; i < particles.length; i++) { ahora=particles[i].location; if (i>0)
{
ellipse(ahora.x, ahora.y, antes.x/2, antes.y );
}
antes=particles[i].location;
}
}
}
/*FIN*/