class Element
{
float rr;
int id, sX, sY, sZ;
color c;
PVector p1, p2, p3, p4, r1, r2, r3, r4;
Element (int id_, PVector p1_, PVector p2_, PVector p3_, PVector p4_, int sX_, int sY_, int sZ_, color c_, PVector r1_, PVector r2_, PVector r3_, PVector r4_, float rr_)
{
id = id_;
p1 = p1_;
p2 = p2_;
p3 = p3_;
p4 = p4_;
r1 = r1_;
r2 = r2_;
r3 = r3_;
r4 = r4_;
sX = sX_;
sY = sY_;
sZ = sZ_;
c = c_;
rr = rr_;
}
void upDatePos(PVector p1_, PVector p2_,PVector p3_, PVector p4_, PVector r1_, PVector r2_, PVector r3_, PVector r4_)
{
p1 = p1_;
p2 = p2_;
p3 = p3_;
p4 = p4_;
r1 = r1_;
r2 = r2_;
r3 = r3_;
r4 = r4_;
}
void upDateRR (float rr_)
{
rr = rr_;
}
}
class Layer
{
float x, y, z,r, rMin, rMax, rotation ;
int ellementsAmount, startID;
float SPEED,GROW,ROTATION, timeZ, timeGrow;
Element [] elements;
Layer (float x_, float y_, float z_, int ellementsAmount_, float SPEED_, float GROW_,float ROTATION_, int rMin_, int rMax_, int r_, int startID_)
{
x = x_;
y = y_;
z = z_;
r = r_;
rMin = rMin_;
rMax = rMax_;
ellementsAmount = ellementsAmount_;
startID = startID_;
SPEED = SPEED_;
GROW = GROW_;
ROTATION = ROTATION_;
timeZ = sin (z);
timeGrow = sin (r/2);
rotation = random (TWO_PI);
createElements ();
}
void createElements ()
{
elements = new Element [ellementsAmount];
float angle = rotation, steps = TWO_PI / (float) ellementsAmount;
float time = random (100);
int s = 0;
int id = startID;
for(int i = 0; i < ellementsAmount; i++)
{
int sX = (int) random (10, rMin*1/3), sY = (int) random (1,30), sZ = (int) random (10, 150) ;
float b = constrain (20+noise (time)*60, 40, 80);
if (b < 60) s = 91;
else {
s = 0;
b += 10;
}
//Radius -----------------
//println (b);
color c = color (197,s, b, 255);
float eX = x + cos (angle) * r;
float eY = y + sin (angle) * r;
float sA = r; // Strecke Ankathete
float sG = (float) sX; // Strecke Gegenkathete
float nextAngle = (atan (sG / sA));
PVector p1 = new PVector (eX, eY, z); // save PVector
eX = x + cos (angle+nextAngle) * r;
eY = y + sin (angle+nextAngle) * r;
PVector p2 = new PVector (eX, eY, z); // save PVector
sA = (float) sX; // Strecke Ankathete
sG = (float) sY; // Strecke Gegenkathete
float currentAngle = (atan ( sG /sA));
eX = p1.x + cos (angle+nextAngle+currentAngle) * (sG);
eY = p1.y + sin (angle+nextAngle+currentAngle) * (sG);
PVector p3 = new PVector (eX, eY, z); // save PVector
eX = p2.x + cos (angle+currentAngle) * (sG);
eY = p2.y + sin (angle+currentAngle) * (sG);
PVector p4 = new PVector (eX, eY, z); // save PVector
//println ("d_sY: " + PVector.dist(p1, p3) + ", d_sY_2: " + PVector.dist(p2, p4) + ", d_sH:" + PVector.dist(p1, p4) + ", d_sX:" + PVector.dist(p4, p3) + ", d_sX_2:" + PVector.dist(p1, p2));
//Random -----------------
float rr = random ( r*2); // Random Radius
eX = x + cos (angle) * (r+rr);
eY = y + sin (angle) * (r+rr);
sA = (r+rr); // Strecke Ankathete
sG = (float) sX; // Strecke Gegenkathete
nextAngle = (atan (sG / sA));
PVector r1 = new PVector (eX, eY, z); // save PVector
eX = x + cos (angle+nextAngle) * (r+rr);
eY = y + sin (angle+nextAngle) * (r+rr);
PVector r2 = new PVector (eX, eY, z); // save PVector
sA = (float) sX; // Strecke Ankathete
sG = (float) sY; // Strecke Gegenkathete
currentAngle = (atan ( sG /sA));
eX = r1.x + cos (angle+nextAngle+currentAngle) * (sG);
eY = r1.y + sin (angle+nextAngle+currentAngle) * (sG);
PVector r3 = new PVector (eX, eY, z); // save PVector
eX = r2.x + cos (angle+currentAngle) * (sG);
eY = r2.y + sin (angle+currentAngle) * (sG);
PVector r4 = new PVector (eX, eY, z); // save PVector
elements [i] = new Element (id, p1, p2, p3, p4, sX, sY, sZ, c, r1, r2, r3, r4, rr);
angle += steps;
time += 0.1;
id ++;
}
}
void move ()
{
z = sin (timeZ)*maxZ;
r = rMax/2+rMin + sin (timeGrow)*rMax/2;
timeZ += SPEED*(0.2+m*2);
timeGrow += GROW*(0.2+m*2);
rotation += ROTATION*(0.2 + m*2);
if (timeZ >= TWO_PI) timeZ -= TWO_PI;
if (timeGrow >= TWO_PI) timeGrow -= TWO_PI;
if (rotation >= TWO_PI) rotation -= TWO_PI;
upDateElementPos ();
}
void upDateElementPos ()
{
float angle = rotation, steps = TWO_PI / (float) ellementsAmount;
for (int i = 0; i < elements.length; i++)
{
Element e = elements [i];
float eX = x + cos (angle) * r;
float eY = y + sin (angle) * r;
float sA = r; // Strecke Ankathete
float sG = (float) e.sX; // Strecke Gegenkathete
float nextAngle = (atan (sG / sA));
PVector p1 = new PVector (eX, eY, z); // save PVector
eX = x + cos (angle+nextAngle) * r;
eY = y + sin (angle+nextAngle) * r;
PVector p2 = new PVector (eX, eY, z); // save PVector
sA = (float) e.sX; // Strecke Ankathete
sG = (float) e.sY; // Strecke Gegenkathete
float currentAngle = (atan ( sG /sA));
eX = p1.x + cos (angle+nextAngle+currentAngle) * (sG);
eY = p1.y + sin (angle+nextAngle+currentAngle) * (sG);
PVector p3 = new PVector (eX, eY, z); // save PVector
eX = p2.x + cos (angle+currentAngle) * (sG);
eY = p2.y + sin (angle+currentAngle) * (sG);
PVector p4 = new PVector (eX, eY, z); // save PVector
//Random ----------------------------------
eX = x + cos (angle) * (r+e.rr);
eY = y + sin (angle) * (r+e.rr);
sA = (r+e.rr); // Strecke Ankathete
sG = (float) e.sX; // Strecke Gegenkathete
nextAngle = (atan (sG / sA));
PVector r1 = new PVector (eX, eY, z); // save PVector
eX = x + cos (angle+nextAngle) * (r+e.rr);
eY = y + sin (angle+nextAngle) * (r+e.rr);
PVector r2 = new PVector (eX, eY, z); // save PVector
sA = (float) e.sX; // Strecke Ankathete
sG = (float) e.sY; // Strecke Gegenkathete
currentAngle = (atan ( sG /sA));
eX = r1.x + cos (angle+nextAngle+currentAngle) * (sG);
eY = r1.y + sin (angle+nextAngle+currentAngle) * (sG);
PVector r3 = new PVector (eX, eY, z); // save PVector
eX = r2.x + cos (angle+currentAngle) * (sG);
eY = r2.y + sin (angle+currentAngle) * (sG);
PVector r4 = new PVector (eX, eY, z); // save PVector
elements [i].upDatePos (p1, p2, p3, p4, r1, r2, r3,r4);
angle += steps;
}
}
void display ()
{
noStroke ();
for (int i = 0; i < elements.length; i++)
{
Element p = elements [i];
fill(p.c);
float x1 = lerp (p.p1.x, p.r1.x, m), x2 = lerp (p.p2.x, p.r2.x, m), x3 = lerp (p.p3.x, p.r3.x, m), x4 = lerp (p.p4.x, p.r4.x, m);
float y1 = lerp (p.p1.y, p.r1.y, m), y2 = lerp (p.p2.y, p.r2.y, m), y3 = lerp (p.p3.y, p.r3.y, m), y4 = lerp (p.p4.y, p.r4.y, m);
createBox (x1, x2, x3, x4, y1, y2, y3, y4, p.p1.z, p.sZ/2);
}
}
void createBox (float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4, float z_, float h_)
{
beginShape ();
vertex (x1, y1, z_ + h_);
vertex (x2, y2, z_ + h_);
vertex (x2, y2, z_ - h_);
vertex (x1, y1, z_ - h_);
endShape (CLOSE);
// oben
beginShape ();
vertex (x1, y1, z_ + h_);
vertex (x2, y2, z_ + h_);
vertex (x4, y4, z_ + h_);
vertex (x3, y3, z_ + h_);
endShape (CLOSE);
// unten
beginShape ();
vertex (x1, y1, z_ - h_);
vertex (x2, y2, z_ - h_);
vertex (x4, y4, z_ - h_);
vertex (x3, y3, z_ - h_);
endShape (CLOSE);
// hinten
beginShape ();
vertex (x3, y3, z_ + h_);
vertex (x4, y4, z_ + h_);
vertex (x4, y4, z_ - h_);
vertex (x3, y3, z_ - h_);
endShape (CLOSE);
// rechts
beginShape ();
vertex (x4, y4, z_ + h_);
vertex (x2, y2, z_ + h_);
vertex (x2, y2, z_ - h_);
vertex (x4, y4, z_ - h_);
endShape (CLOSE);
// links
beginShape ();
vertex (x3, y3, z_ + h_);
vertex (x1, y1, z_ + h_);
vertex (x1, y1, z_ - h_);
vertex (x3, y3, z_ - h_);
endShape (CLOSE);
}
}
int offsetX = width/2;
boolean mouseIsPressed = false;
void mouseDragged ()
{
if (mouseIsPressed)
{
m = map (mouseX, 50, width-50, 0,1);
m = constrain (m, 0,1);
}
}
void mousePressed ()
{
if (!mouseIsPressed && editPosition ) mouseIsPressed = true;
}
void mouseReleased ()
{
if (mouseIsPressed) mouseIsPressed = false;
}
void keyPressed()
{
if (keyCode == KeyEvent.VK_R) {
editPosition = true;
cam.setActive(false);
}
}
void keyReleased()
{
if (keyCode == KeyEvent.VK_R) {
editPosition = false;
cam.setActive(true);
}
}
import processing.opengl.*;
import peasy.test.*;
import peasy.org.apache.commons.math.*;
import peasy.*;
import peasy.org.apache.commons.math.geometry.*;
PeasyCam cam;
Layer [] layers;
PFont font;
int maxZ = 250;
float m = 0.0;
boolean editPosition = false;
void setup ()
{
size (800, 600, P3D);
frameRate (30);
colorMode (HSB, 360, 100, 100);
hintsForOPENGL ();
noiseDetail(4, 0.8);
// Camera --------------------------------------------------------------------
cam = new PeasyCam(this, width/2, height/2, 0,800);
cam.setMinimumDistance(16);
cam.setMaximumDistance(10000);
cam.setRotations(radians (-5), radians (-20), radians (0));
font = loadFont ("ArialMT-18.vlw");
float x = width/2, y = height/2;
int layersAmount = 12, ellementsAmount = (int) random (60,120);
layers = new Layer [layersAmount];
int startID = 0;
for (int i = 0; i < layersAmount; i++)
{
float z = random (-maxZ, maxZ), speedZ = random (-0.07, 0.07), speedR = random (-0.05, 0.05), speedRot = random (-0.015, 0.015);
int rMin = (int) random (25, 240), rMax = (int) constrain (random (rMin * 1.1, rMin * 2), rMin*1.1, 500), r = (int) random (rMin, rMax);
layers [i] = new Layer (x,y,z, ellementsAmount, speedZ, speedR, speedRot, rMin, rMax, r, startID);
startID += ellementsAmount;
}
}
void draw()
{
background (0,0,97);
cam.beginHUD();
//image (bg.bg, 0,0);
noStroke();
fill (0,120);
textFont (font, 12);
text (frameRate, 10,20);
if (editPosition) text ("Edit Position: " + str (m), 10, 40);
cam.endHUD();
hintsForOPENGL ();
display ();
}
void display ()
{
for (int i = 0; i < layers.length; i++)
{
Layer t = layers [i];
t.move();
t.display();
}
}
void hintsForOPENGL ()
{
hint(ENABLE_NATIVE_FONTS);
hint(DISABLE_OPENGL_ERROR_REPORT);
hint(ENABLE_OPENGL_4X_SMOOTH);
hint(DISABLE_OPENGL_2X_SMOOTH);
//hint (DISABLE_DEPTH_TEST);
//hint(ENABLE_DEPTH_SORT);
}
I wanted to avoid usage of 'translate', 'popmatrix' & co because it usually slows the program down. Unfortunately, if the values are small, the boxes get deformed. Maybe I'll solve the problem later by using 'double' instead of 'float' values.
Made for a music visualisation: http://www.vimeo.com/22590998
Controls:
PeasyCam for camera
Press 'R' btn + drag mouse to left / right to change position of the boxes