Creative Coding

Seit einem Seminar bei Prof. Dan Verständig an der Otto-von-Guericke-Universisät-Magdeburg mit dem Titel „Critical Code Studies“ im Jahr 2018 habe ich mich mit der Anwendung Processing und später auch mit p5.js beschäftigt. Ich habe mich bereits vorher mit anderen visuell orientierten Programmiersprachen auseinandergesetzt, doch mit Processing eröffneten sich mir ganz neue Möglichkeiten. Hier habe ich einfach mal ein paar Creative Coding Projekte gesammelt, die ich in der Vergangenheit programmiert habe. Auf meinem Open Processing Profil finden sich weitere p5.js Sketche.

Functions Describe the World Thing

Ein gemeinsam mit generativer KI (Gemini) erstelltes Projekt, das ein Kamerabild in eine Reihe oszillierender Kurven umwandelt. Zuvor habe ich etwas vergleichbares ohne Input und auch ohne Interaktion gemacht und habe mich gefragt, ob es funktionieren würde. Über das Ergebnis war ich sehr glücklich und der Effekt hat genau das rüber gebracht, was ich mir davon gewünscht habe.

Link zu Open Processing

Code


let capture; // Variable to hold the camera input

let phaseOffsets = []; // 2D array to store the current phase offset for each point

// Set the vertical distance between lines

const lineSpacing = 4;

// Set a CONSTANT amplitude for the waves.

const amplitude = 3.5;

// Define a base frequency for the underlying wave structure.

const baseFrequency = 0.05;

// Smoothing factor. A smaller value means slower, smoother transitions.

const smoothing = 0.08; 

/**

 * p5.js setup function, runs once at the beginning.

 */

function setup() {

const canvasSize = min(windowWidth, windowHeight);

createCanvas(canvasSize, canvasSize);

// — CAMERA SETUP —

capture = createCapture(VIDEO);

capture.size(width, height);

capture.hide();

// — INITIALIZE PHASE OFFSETS ARRAY —

// Pre-populate the 2D array to store the smoothed frequency values.

for (let y = 0; y < height; y += lineSpacing) {

let rowz = [];

for (let x = 0; x < width; x += 2) {

rowz.push(0);

}

phaseOffsets.push(rowz);

}

}

/**

 * p5.js draw function, runs in a continuous loop.

 */

function draw() {

background(0);

capture.loadPixels();

if (capture.pixels.length === 0) {

return;

}

stroke(255, 200);

noFill();

strokeWeight(1);

for (let y_idx = 0; y_idx < phaseOffsets.length; y_idx++) {

const y = y_idx * lineSpacing;

beginShape();

for (let x_idx = 0; x_idx < phaseOffsets[y_idx].length; x_idx++) {

const x = x_idx * 2;

// — PIXEL ANALYSIS —

const pixelX = floor(x);

const pixelY = floor(y);

const index = (pixelY * width + pixelX) * 4;

const r = capture.pixels[index];

const g = capture.pixels[index + 1];

const b = capture.pixels[index + 2];

const brightness = (r + g + b) / 3;

// — SMOOTHED PHASE MODULATION —

// 1. Normalize the brightness to a 0.0 – 1.0 range

let normalizedBrightness = brightness / 255.0;

// 2. Apply an exponential curve to better match human perception.

//    You can experiment with different exponents (e.g., 2, 3, or even 1.5)

let curvedBrightness = pow(normalizedBrightness, 2);

// 3. Map this new curved value to the target offset.

const targetOffset = map(curvedBrightness, 0, 1, TWO_PI * 8, 0);

// 2. Get the CURRENT offset from our storage array

let currentOffset = phaseOffsets[y_idx][x_idx];

// 3. Interpolate the current offset towards the target

currentOffset = lerp(currentOffset, targetOffset, smoothing);

// 4. Store the new smoothed value back in the array

phaseOffsets[y_idx][x_idx] = currentOffset;

// 5. Use the smoothed value to draw the wave

const angle = x * baseFrequency + currentOffset;

const waveY = sin(angle) * amplitude;

vertex(x, y + waveY);

}

endShape();

}

}a

Binarain

Als eine Leistungserbringung im Rahmen meines Masterstudiums habe im Seminar „Critical Code Studies“ zusammen mit einer Kommilitonin ein Creative Coding Projekt gemacht. Die Idee ist, dass ein Kamerabild mithilfe von Nullen und Einsen nachgezeichnet wird. Starke Veränderungen im Bild sorgen dafür, dass die Zahlen eine größere und längere Spur ziehen. Das resultiert in einem Effekt, in dem sich eine Art Spur der Bewegungen durch die Szene zieht und nach unten verläuft. Die Interpretation des Kunstwerks haben wir einfach mal offen gelassen 😉

Link zu Open Processing

Code

var zahlen = [];
var cam;
var prevFrame;
var threshold;
var camMode;
var scl = 1;
var arrLength = 2000;
var ct = 0;
var move;

function setup() {
move=0;
frameRate(24);
//createCanvas(window.innerWidth, window.innerHeight);
createCanvas(720,480);
background(130);
threshold = 40;
//pixelDensity(1);
cam = createCapture(VIDEO);
cam.size(width/scl,height/scl);
cam.hide();
prevFrame = createImage(cam.width,cam.height);

for(let i = 0; i < arrLength; i++){
zahlen.push(new Zahl());
}

}

function draw() {

switch(camMode){
case 1:
break;
case 2:
filter(GRAY);
break;
case 3:
filter(POSTERIZE, 2);
break;
case 4:
filter(THRESHOLD, 0.5);
break;
case 5:
filter(OPAQUE);
break;
case 6:
filter(DILATE);
break;
case 7:
filter(BLUR);
break;
case 8:
filter(ERODE);
break;

}

ct+=1;

//if(ct%3==0)background(230,5);

cam.loadPixels();
prevFrame.loadPixels();

if(ct%1==0){
for (let i = 0; i < zahlen.length; i++) {
zahlen[i].display();
zahlen[i].move();
}
}

prevFrame.copy(cam,0,0,cam.width,cam.height ,0,0,cam.width,cam.height);
}

function keyPressed(){
switch(key){
case ‚1‘:
camMode = 1;
break;
case ‚2‘:
camMode = 2;
break;
case ‚3‘:
camMode = 3;
break;
case ‚4‘:
camMode = 4;
break;
case ‚5‘:
camMode = 5;
break;
case ‚6‘:
camMode = 6;
break;
case ‚7‘:
camMode = 7;
break;
case ‚8‘:
camMode = 8;
break;

case 's':
  save();

}
}

class Zahl {

constructor() {
this.x = random(width);
this.y = random(height);
this.t = random(2,10);
let ran = random(0,1);
this.op = 30;
this.col = color(0,255,255);
this.col.setAlpha(this.op);
this.sz = 5;
this.trig = false;
this.timer = 0;

if(ran>0.5){
  this.numb = "0";
}
else{
  this.numb = "1";
}


fill(this.col);
textSize(this.sz);
text(this.numb,this.x,this.y);

}

move(){
this.y += this.t;
if(this.y > height){
this.y = 0;
this.op= 0;
this.col.setAlpha(this.op);
this.timer=0;
//this.col=color(0,0,0);

  //zahlen.pop();
}

}

display(){

  //background(255,255,255,5);


  //for (let x = 0; x < cam.width; x+=1){
  //for (let y = 0; y < cam.height; y+=1){
let pIndex = (floor(this.x/scl) + floor(this.y/scl) * cam.width)*4;
//print(pIndex);

let r1 = prevFrame.pixels[pIndex];
let g1 = prevFrame.pixels[pIndex+1];
let b1 = prevFrame.pixels[pIndex+2];
      //let a1 = prevFrame.pixels[pIndex+3];

let r2 = cam.pixels[pIndex];
let g2 = cam.pixels[pIndex+1];
let b2 = cam.pixels[pIndex+2];
      //let a2 = cam.pixels[pIndex+3];

let move = dist(r1,g1,b1,r2,g2,b2);


if(move > threshold){
  this.op = 255;
  this.col = color(r1,g1,b1);
  this.col.setAlpha(this.op);
  this.sz = 25;
  this.trig = true;
  this.timer = 50;
}

if(this.timer>0)this.timer--;
else this.trig=false;


if(this.sz>5)this.sz-=0.5;
if(this.op>50)this.op-=10;

this.col.setAlpha(this.op);
if(this.trig==true)fill(this.col);
else fill(color(r2,g2,b2));

noStroke();
textSize(this.sz);
text(this.numb,this.x,this.y);

}

}

class Zahl {

constructor() {
this.x = random(width);
this.y = random(height);
this.t = random(2,10);
let ran = random(0,1);
this.op = 30;
this.col = color(0,255,255);
this.col.setAlpha(this.op);
this.sz = 5;
this.trig = false;
this.timer = 0;

if(ran>0.5){
  this.numb = "0";
}
else{
  this.numb = "1";
}


fill(this.col);
textSize(this.sz);
text(this.numb,this.x,this.y);

}

move(){
this.y += this.t;
if(this.y > height){
this.y = 0;
this.op= 0;
this.col.setAlpha(this.op);
this.timer=0;
//this.col=color(0,0,0);

  //zahlen.pop();
}

}

display(){

  //background(255,255,255,5);


  //for (let x = 0; x < cam.width; x+=1){
  //for (let y = 0; y < cam.height; y+=1){
let pIndex = (floor(this.x/scl) + floor(this.y/scl) * cam.width)*4;
//print(pIndex);

let r1 = prevFrame.pixels[pIndex];
let g1 = prevFrame.pixels[pIndex+1];
let b1 = prevFrame.pixels[pIndex+2];
      //let a1 = prevFrame.pixels[pIndex+3];

let r2 = cam.pixels[pIndex];
let g2 = cam.pixels[pIndex+1];
let b2 = cam.pixels[pIndex+2];
      //let a2 = cam.pixels[pIndex+3];

let move = dist(r1,g1,b1,r2,g2,b2);


if(move > threshold){
  this.op = 255;
  this.col = color(r1,g1,b1);
  this.col.setAlpha(this.op);
  this.sz = 25;
  this.trig = true;
  this.timer = 50;
}

if(this.timer>0)this.timer--;
else this.trig=false;


if(this.sz>5)this.sz-=0.5;
if(this.op>50)this.op-=10;

this.col.setAlpha(this.op);
if(this.trig==true)fill(this.col);
else fill(color(r2,g2,b2));

noStroke();
textSize(this.sz);
text(this.numb,this.x,this.y);

}

}

Failing Sand

Ich träume schon seit einigen Jahren von einem Computerspiel, das die Physik einer Pixel Simulation (wie Noita oder Powdertoy) auf spielerische Weise einbindet. Deshalb habe ich einfach Mal eine einfache Pixelsimulation (Falling Sand) in p5.js programmiert, um besser zu verstehen, wie so ein Programm überhaupt grundlegend funktionieren würde.

Link zu Open Processing

Code

let size = 5;
let screen = 500;
let ratio = screen/size;
let pixels=[];
let mode;
let pencil = 0;
let watrspd = 1;

function setup() {
createCanvas(screen, screen);
background(128,210,255);
mode=1;
frameRate(30);

for(let i = 0; i < ratio; i++)
{
        pixels[i]=[];
        for(let j = 0; j < 0; j++)
        {
                //pixels[i][j] = new Pixel(i,j,1);
        }
}

}

function draw() {

background(128,210,255);
for(let i = 0; i < ratio; i++)
{
        for(let j = 0; j < ratio-1; j++)
        {
            if(pixels[i][j]!=null && pixels[i][j].updated==false)
            {
                    //is sand?
                    if(pixels[i][j].type==1){
                    //nothing under sand?   
                    if(pixels[i][j+1]==null){
                        pixels[i][j+1] = pixels[i][j];
                        pixels[i][j] = null;
                        pixels[i][j+1].updated=true;

                    }
                    //water under sand? 
                    else if(pixels[i][j+1].type==2){
                        let saver = pixels[i][j+1];
                        pixels[i][j+1] = pixels[i][j]; 
                        pixels[i][j] = saver;
                        //pixels[i][j].updated=true;
                        pixels[i][j+1].updated=true;
                    }
                    //water right under sand?   
                    else if(i+1<ratio&&pixels[i+1][j+1]!=null&&pixels[i+1][j+1].type==2){
                        let saver = pixels[i+1][j+1];
                        pixels[i+1][j+1] = pixels[i][j]; 
                        pixels[i][j] = saver;
                        pixels[i][j].updated=true;
                        pixels[i+1][j+1].updated=true;
                    }
                    //water left under sand?    
                    else if(i-1>=0&&pixels[i-1][j+1]!=null&&pixels[i-1][j+1].type==2){
                        let saver = pixels[i-1][j+1];
                        pixels[i-1][j+1] = pixels[i][j]; 
                        pixels[i][j] = saver;
                        pixels[i][j].updated=true;
                        pixels[i-1][j+1].updated=true;
                    }
                    //nothing right under sand? 
                    else if(i+1<ratio&&pixels[i+1][j+1]==null){
                        pixels[i+1][j+1] = pixels[i][j];
                        pixels[i][j] = null;
                        pixels[i+1][j+1].updated=true;
                    }
                    //nothing left under sand?
                    else if(i-1>=0&&pixels[i-1][j+1]==null){
                        pixels[i-1][j+1] = pixels[i][j];
                        pixels[i][j] = null;
                        pixels[i-1][j+1].updated=true;
                    }

                    }

                    //is water?
                    if(pixels[i][j]!=null&&pixels[i][j].type==2){

                    //nothing under water?
                    if(pixels[i][j+1]==null){
                        pixels[i][j+1] = pixels[i][j];
                        pixels[i][j] = null;
                        pixels[i][j+1].updated=true;

                    }


                    //nothing left under water? (old)
                    else if(i-1>=0&&pixels[i-1][j+1]==null){
                        pixels[i-1][j+1] = pixels[i][j];
                        pixels[i][j] = null;
                        pixels[i-1][j+1].updated=true;
                    }

                    //nothing right under water? (old)
                    else if(i+1<ratio&&pixels[i+1][j+1]==null){
                        pixels[i+1][j+1] = pixels[i][j];
                        pixels[i][j] = null;
                        pixels[i+1][j+1].updated=true;
                    }

                    //nothing left to water?
                    else if(i-1>=0&&pixels[i-1][j]==null){
                        let distance = 0;
                        while(distance<=watrspd&&i-1-distance>=0&&pixels[i-1-distance][j]==null){
                            pixels[i-1-distance][j] = pixels[i-distance][j];
                            pixels[i-distance][j] = null;
                            pixels[i-1-distance][j].updated=true;
                            distance+=1;
                        }

                    }

                    //nothing right to water?
                    else if(i+1<ratio&&pixels[i+1][j]==null){
                        let distance = 0;
                        while(distance<=watrspd&&i+1+distance<ratio&&pixels[i+1+distance][j]==null){
                            pixels[i+1+distance][j] = pixels[i+distance][j];
                            pixels[i+distance][j] = null;
                            pixels[i+1+distance][j].updated=true;
                            distance+=1;
                        }
                    }

                    }
            }       
        }   
}

for(let i = 0; i < ratio; i++)
{
        for(let j = 0; j < ratio; j++)
        {   
            if(pixels[i][j]!=null){
                if(pixels[i][j].type==2)pixels[i][j].color=color(96+random(2),157+random(2),191+random(5));
                fill(pixels[i][j].color);
                noStroke();
                rect(i*size,j*size,size,size);
                pixels[i][j].setUpdated(false);
            }
        }
}

if(mouseIsPressed==true)
{
    mouseXVal = mouseX;
    mouseYVal = mouseY;

    if(mouseXVal>screen)mouseXVal=screen;
    if(mouseXVal<0)mouseXVal=0;
    if(mouseYVal>screen)mouseYVal=screen;
    if(mouseYVal<0)mouseYVal=0;

    mouseXVal = int(mouseXVal/size);
    mouseYVal = int(mouseYVal/size);

    if(mouseX<width-5){

    switch (mode) {
case 1:
  if(pixels[mouseXVal][mouseYVal]==null){
        pixels[mouseXVal][mouseYVal]=new Pixel(mouseXVal,mouseYVal,1);
        pixels[mouseXVal+1][mouseYVal]=new Pixel(mouseXVal,mouseYVal,1);
        pixels[mouseXVal][mouseYVal+1]=new Pixel(mouseXVal,mouseYVal,1);
        pixels[mouseXVal+1][mouseYVal+1]=new Pixel(mouseXVal,mouseYVal,1);
    }
  break;
case 2:
  if(pixels[mouseXVal][mouseYVal]==null){
        pixels[mouseXVal][mouseYVal]=new Pixel(mouseXVal,mouseYVal,2);
        pixels[mouseXVal+1][mouseYVal]=new Pixel(mouseXVal,mouseYVal,2);
        pixels[mouseXVal][mouseYVal+1]=new Pixel(mouseXVal,mouseYVal,2);
        pixels[mouseXVal+1][mouseYVal+1]=new Pixel(mouseXVal,mouseYVal,2);
        }
            break;
case 3:
  if(pixels[mouseXVal][mouseYVal]==null){
        pixels[mouseXVal][mouseYVal]=new Pixel(mouseXVal,mouseYVal,3);
        pixels[mouseXVal+1][mouseYVal]=new Pixel(mouseXVal,mouseYVal,3);
        pixels[mouseXVal][mouseYVal+1]=new Pixel(mouseXVal,mouseYVal,3);
        pixels[mouseXVal+1][mouseYVal+1]=new Pixel(mouseXVal,mouseYVal,3);
    }
  break;
case 4:
  pixels[mouseXVal][mouseYVal]=null; 
  break;
default:
  //  

}

    }
}
fill(255,100);
ellipse(mouseX,mouseY,pencil+1,pencil+1);

}

function keyTyped() {

    switch (key) {
case '1':
  mode = 1;
  break;
case '2':
  mode = 2;
  break;
case '3':
  mode = 3;
  break;
case '4':
  mode = 4;  
  break;
default:
  //  

}
}

/function mouseWheel(event) { //print(pencil); if(abs(pencil)<200)pencil += event.delta/25; //pencil += event.delta/20; }/

/*function mouseDown()
{
mouseXVal = mouseX;
mouseYVal = mouseY;

if(mouseXVal>screen)mouseXVal=screen;
if(mouseXVal<0)mouseXVal=0;
if(mouseYVal>screen)mouseYVal=screen;
if(mouseYVal<0)mouseYVal=0;

mouseXVal = int(mouseXVal/size);
mouseYVal = int(mouseYVal/size);

if(pixels[mouseXVal][mouseYVal]==null)pixels[mouseXVal][mouseYVal]=new Pixel(mouseXVal,mouseYVal,1);
//print("X: "+mouseXVal+" Y: "+mouseYVal);

}*/

class Pixel{
constructor(x,y,t){
this.x = x;
this.y = y;
this.type = t;
if(this.type==1){
this.color = color(205+random(30),133+random(30),63+random(30))
//this.velocity =
}
if(this.type==2){
this.color = color(96+random(10),157+random(10),191+random(10))
}
if(this.type==3){
this.color = color(128+random(5),128+random(5),128+random(5))
}
this.updated = false;
}

getType(){
    return this.type;
}

getUpdated(){
    return this.updated;
}

setUpdated(newupdated){
    this.updated = newupdated;
}

}

Turtle Grid

Inspiriert von einem Klassiker in Einstiegskursen zur Informatik, habe ich ein Turtle-Programm erzeugt, das eine zufällige Linie auf einem Raster abläuft und dabei solche Strukturen erzeugt.

Link zu Open Processing

Code

let posX;
let posY;

let vecX;
let vecY;

let step;
let c;

function setup() {
createCanvas(400, 400);
background(220);
posX = width/2;
posY = height/2;

step = 32;
vecX = step;
vecY = step;
c=0;
}

function draw() {
c+=0.001;
let ran = int(random(5));

switch(ran) {
case 1:
vecX=1; break; case 2: vecY=1;
break;
case 3:
vecX=-1; break; case 4: vecY=-1;
break;

default:
// code block
}

print(ran);

if(posX<0){ posX+=step; } if(posX>width){
posX-=step;
}

if(posY<0){ posY+=step; } if(posY>height){
posY-=step;
}

color(255,0,0);
line(posX,posY,posX+=vecX,posY+=vecY);

}

Infinite Gummi Worm

Es fing alles an mit einem Kreis, der sich in verschiedenen Bewegungen, die Farbe kontinuierlich ändernd, über die Leinwand bewegt. In diesem Prozess sind viele sehr unterschiedliche Bilder entstanden

Link zu Open Processing

Code

var x = 0;
var t = 0;
var t2 = 0;
var speed = 3;
var speed2 = 5;

function setup() {
createCanvas(600, 600);
}

function draw() {
//background(220);
noStroke();
//stroke(255,255,255);
ellipse(t+sin(x)20,t2+sin(x20),100+sin(x)10,100+sin(x)10,50);

//fill(sin(x*2)*255,sin(x)*255,tan(x),100);
fill(sin(x)*255,cos(x)*250,100,255);


if(t>=width || t<0){
    speed=speed*-1;

}

if(t2>=height || t2<0){
    speed2=speed2*-1;

}

x=x+0.1;
t=t+speed;
t2=t2+speed2;

}

Noise Particle Flow

Rauschen ist faszinierend. Und die Möglichkeit, mit Rauschen interessante visuelle Kompositionen zu schaffen, bietet nahezu grenzenlose Möglichkeiten. Hier wird eine Art Flow-Field erzeugt, um Partikel ein Bild nachzeichnen zu lassen. Die Partikel werden dann dem Rauschen entsprechend in bestimmte Bahnen geleitet und verändern dabei die Farbe.

Link zu Open Processing

Code

var inc = 0.05;
var scl = 20;
var cols, rows;
var zoff = 0;
var count = 2000;

var fr;

var particles = [];
var flowfield;

function setup() {

//frameRate(10);
//colorMode(RGB, 100);
createCanvas(700, 700);
background(0);
cols = floor(width/scl);
rows = floor(height/scl);
//pixelDensity(1);
// noiseDetail(4);
fr=createP('');

flowfield = new Array(cols*rows);

for(var i = 0; i < count; i++){
    particles[i]=new Partikel();
}

}

function draw() {
//background(0,10);

var yoff = 0;
for (var y = 0; y < rows; y++)
{
    var xoff = 0;
    for (var x = 0; x < cols; x++)
    {
        var index = x + y * cols;
        var angle = noise(xoff,yoff,sin(zoff))*TWO_PI;
        var v = p5.Vector.fromAngle(angle);
        //v.setMag(map(mouseX,0,width,0.0001,5));
        v.setMag(0.05);
        flowfield[index] = v;
        xoff+=inc;

      /*stroke(255,50);
        push();
        translate(x*scl,y*scl);
        rotate(v.heading());
        strokeWeight(1);
        line(0,0,scl,0);
        pop();*/

        //xoff+=inc;

    }
    yoff+=inc;
}
//zoff+=PI/500;
//if(zoff%TWO_PI==0)print("loop");


for(var i = 0; i < particles.length; i++){

    particles[i].update();
    particles[i].show();
    particles[i].overedge();
    particles[i].follow(flowfield);
    //print(particles[i].pos.x+" "+particles[i].pos.y);
}

//fr.html(floor(frameRate()));

}

var maxAlpha = 50;
var alphainc = 0.1;

function Partikel(){
this.pos = createVector(random(width),random(height));
this.vel = p5.Vector.random2D();
this.acc = createVector(0,0);

this.maxspeed = 2;
this.alpha = 0;
this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);



this.follow = function(vectors){
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y *cols;
    var force = vectors[index];

    this.applyForce(force);


}

this.update = function(){
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
    if(this.alpha<maxAlpha)this.alpha+=alphainc;
}

this.applyForce = function(force){

        this.acc.add(force);


}

this.show = function(){

    r = red(this.col);
    g = green(this.col);
    b = blue(this.col);
    mapX = map(this.pos.x,0,width,0,255);
    mapY = map(this.pos.y,0,height,0,255);
    newcol = color((r*25 + mapX)/26,0,(b*25+ mapY)/26,this.alpha);
    this.col = newcol;
    //print(r);
    fill(this.col);
    noStroke();
    ellipse(this.pos.x,this.pos.y,2,2);
}

this.overedge = function(){
    if(this.pos.x > width){
        this.pos.x = 0;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }
    if(this.pos.x < 0){
        this.pos.x = width;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }
    if(this.pos.y > height){
        this.pos.y = 0;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }
    if(this.pos.y < 0){
        this.pos.y = height;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }

    /*
    if(this.pos.x > width){

        this.vel.set(this.vel.x*-1,this.vel.y);
    }
    if(this.pos.x < 0){

        this.vel.set(this.vel.x*-1,this.vel.y);
    }
    if(this.pos.y > height){

        this.vel.set(this.vel.x,this.vel.y*-1);
    }
    if(this.pos.y < 0){

        this.vel.set(this.vel.x,this.vel.y*-1); 
    }*/
}

}

Noise Particle Flow Reloaded

Noise Particle Flow habe ich mehrere Male überarbeitet und in einer Version ist das folgende Ergebnis entstanden. Hier sind sind es nicht so feine Linien, die entlang des Flow Fields gezeichnet werden, sondern dickere Striche, wodurch ein etwas anderer Effekt entsteht.

Link zu Open Processing

Code

var inc = 0.05;
var scl = 20;
var cols, rows;
var zoff = 0;
var count = 1000;

var fr;

var particles = [];
var flowfield;

function setup() {

//frameRate(10);
//colorMode(RGB, 100);
createCanvas(1280 , 720);
background(0);
cols = floor(width/scl);
rows = floor(height/scl);
//pixelDensity(1);
// noiseDetail(4);
fr=createP('');

flowfield = new Array(cols*rows);

for(var i = 0; i < count; i++){
    particles[i]=new Partikel();
}

}

function draw() {
background(0,10);

var yoff = 0;
for (var y = 0; y < rows; y++)
{
    var xoff = 0;
    for (var x = 0; x < cols; x++)
    {
        var index = x + y * cols;
        var angle = noise(xoff,yoff,zoff)*10;
        var v = p5.Vector.fromAngle(angle);
        //v.setMag(map(mouseX,0,width,0.0001,5));
        v.setMag(0.05);
        flowfield[index] = v;
        xoff+=inc;

      /*stroke(255,50);
        push();
        translate(x*scl,y*scl);
        rotate(v.heading());
        strokeWeight(1);
        line(0,0,scl,0);
        pop();*/

        //xoff+=inc;

    }
    yoff+=inc;
}
zoff+=PI/600;
//if(zoff%TWO_PI==0)print("loop");


for(var i = 0; i < particles.length; i++){

    particles[i].update();
    particles[i].show();
    particles[i].overedge();
    particles[i].follow(flowfield);
    //print(particles[i].pos.x+" "+particles[i].pos.y);
}

//fr.html(floor(frameRate()));

}

var maxAlpha = 255;
var alphainc = 255;

function Partikel(){
this.pos = createVector(random(width),random(height));
this.vel = p5.Vector.random2D();
this.acc = createVector(0,0);

this.maxspeed = 4.5;
this.alpha = 0;
this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);



this.follow = function(vectors){
    var x = floor(this.pos.x / scl);
    var y = floor(this.pos.y / scl);
    var index = x + y *cols;
    var force = vectors[index];

    this.applyForce(force);


}

this.update = function(){
    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
    if(this.alpha<maxAlpha)this.alpha+=alphainc;
}

this.applyForce = function(force){

        this.acc.add(force);


}

this.show = function(){

    r = red(this.col);
    g = green(this.col);
    b = blue(this.col);
    mapX = map(this.pos.x,0,width,0,255);
    mapY = map(this.pos.y,0,height,0,255);
    newcol = color((r*25 + mapX)/26,50,(b*25+ mapY)/26,this.alpha);
    this.col = newcol;
    //print(r);
    fill(this.col);
    noStroke();
    ellipse(this.pos.x,this.pos.y,16,16);
}

this.overedge = function(){
    if(this.pos.x > width){
        this.pos.x = 0;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }
    if(this.pos.x < 0){
        this.pos.x = width;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }
    if(this.pos.y > height){
        this.pos.y = 0;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }
    if(this.pos.y < 0){
        this.pos.y = height;
        //this.col = color(map(this.pos.x,0,width,0,255),0,map(this.pos.y,0,height,0,255),this.alpha);
    }

    /*
    if(this.pos.x > width){

        this.vel.set(this.vel.x*-1,this.vel.y);
    }
    if(this.pos.x < 0){

        this.vel.set(this.vel.x*-1,this.vel.y);
    }
    if(this.pos.y > height){

        this.vel.set(this.vel.x,this.vel.y*-1);
    }
    if(this.pos.y < 0){

        this.vel.set(this.vel.x,this.vel.y*-1); 
    }*/
}

}

Perlin Noise Blob & Mikrofon

Auf meiner Reise p5.js besser kennenzulernen und verstehen, ist mir immer klarer geworden, welche Bandbreite an Möglichkeiten Rauschen überhaupt bietet. Hier werden die äußeren Punkte eines Kreises entlang eines Rauschmusters verzerrt. Nach einer vollen Umdrehung schließt der Wert wieder dort an, wo er angefangen hat. In der zweiten Variante habe ich das Ganze mit Mikrofon-Input erweitert.

Link zu Open Processing

Link zu Open Processing (mit Mikrofon)

Code 1

let phase = 0;
let zoff = 0;

function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
}

function draw() {
background(255,50);
translate(width / 2, height / 2);
noStroke();

let noiseMax = map(mouseX,0,width,0,2);
let blobs = 20;
for (let j = blobs; j > 0; j–){
//stroke(255);
//strokeWeight(2);
beginShape();
for (let i = 0; i < TWO_PI; i += radians(3)) {
let xoff = map(cos(i + phase), -1, 1, 0, noiseMax);
let yoff = map(sin(i + phase), -1, 1, 0, noiseMax);
let r = map(noise(xoff, yoff, zoff), 0, 1, 0, 10+(j*15));
let x = r * cos(i);
let y = r * sin(i);
vertex(x, y);
}
fill(map(j,0,blobs,0,255,0),150,255);
endShape(CLOSE);
}

//phase += 0.003;
zoff += mouseY/5000;
}

Code 2

let phase = 0;
let zoff = 0;
let m = 0;
let mic;
let levAv;

function setup() {
createCanvas(windowWidth, windowHeight);
background(255);
mic = new p5.AudioIn();
mic.start();
levAv=0;
}

function draw() {
background(0,50);
translate(width / 2, height / 2);
noStroke();

m = mic.getLevel();
lev = map(m,0,1,0,30);

let decay = 10;
levAv=levAv*(decay-1)+lev;
levAv/=decay;
//print(levAv+“ „+lev);

let noiseMax = lev;
let blobs = 15;
for (let j = blobs; j > 0; j–){
//stroke(255);
//strokeWeight(2);
beginShape();
for (let i = 0; i < TWO_PI; i += radians(4)) {
let xoff = map(cos(i + phase), -1, 1, 0, noiseMax);
let yoff = map(sin(i + phase), -1, 1, 0, noiseMax);
let r = map(noise(xoff, yoff, zoff), 0, 1, 50, 10+(j15))(1+levAv/10);
let x = r * cos(i);
let y = r * sin(i);
vertex(x, y);
}
fill(map(j,0,blobs,0,255,0),255,100);
endShape(CLOSE);
}

//phase += 0.003;
zoff += levAv/100;
}