フロッキング3D
今日は前に描いた2Dのフロッキングのコードを3Dにしようと思った。が、途中で3Dの角度計算が必要になるのに気づいて爆死した。それっぽく動いてるけど、Z軸方向でのフロッキングは機能してないと思う。今度調べる。
Processingの機能のうちで限定的な部分をWebで実装しているProcessing.jsだと動かないコードになってきた。予めProcessing.jsとかP5.jsで書くようにすれば良いのかもしれない。今だったらp5.jsをやると思う。
Flock flock; int num =500; // setup関数 : 初回1度だけ実行される void setup() { fullScreen(P3D); // ウィンドウサイズを960px,540pxに colorMode(HSB, 360, 100, 100, 100); // HSBでの色指定にする flock = new Flock(); for (int i = 0; i < num; i++) { float x = random(-width/2, width/2); float y = random(-height/2, height/2); float z = random(-500/2, 500/2); flock.addBoid(new Boid(x, y, z)); } background(0, 0, 0); } // draw関数 : setup関数実行後繰り返し実行される void draw() { hint(DISABLE_DEPTH_TEST); fill(220, 20, 10, 15); rect(0, 0, width, height); translate(width/2, height/2, -500); rotateY(frameCount*0.001); rotateZ(PI/6); flock.run(); } void mousePressed() { for (int i = 0; i < 5; i = i + 1) { flock.addBoid(new Boid(mouseX-width/2, mouseY-height/2, random(-250, 250))); } } void keyPressed() { flock.randomize(); flock.addBoid(new Boid(mouseX-width/2, mouseY-height/2, random(-250, 250))); } class Flock { ArrayList<Boid> boids = new ArrayList<Boid>(); void addBoid(Boid b) { boids.add(b); } void run() { for (Boid b : boids) { b.run(boids); } } void randomize() { for (Boid b : boids) { b.randomize(); } } } class Boid { ArrayList<Integer>colors = new ArrayList<Integer>(); color c; PVector pos; PVector vel; PVector acc; float r; float maxForce; float maxSpeed; Boid(float x, float y, float z) { pos = new PVector(x, y, z); //vel = PVector.random2D(); float angleA = random(360); float angleB = random(360); float thetaA = radians(angleA); float thetaB = radians(angleB); float vx = cos(thetaA)*cos(thetaB); float vy = sin(thetaA)*cos(thetaB); float vz = sin(thetaB); vel = new PVector(vx, vy, vz); acc = new PVector(); int n = (int)random(0, 3); r = map(n, 0, 3, 0.5, 3); maxForce = map(n, 0, 3, 0.03, 0.01); maxSpeed = map(n, 0, 3, 2, 0.5); colors.add(color(12, 78, 100)); colors.add(color(60, 38, 100)); colors.add(color(90, 32, 92)); colors.add(color(139, 36, 74)); colors.add(color(170, 100, 64)); int m = (int) random(0, 5); c = colors.get(m); } void run(ArrayList<Boid> boids) { flock(boids); update(); borders(); render(); } void flock(ArrayList<Boid> boids) { PVector sep = separate(boids); PVector ali = align(boids); PVector coh = cohesion(boids); sep.mult(1.5); ali.mult(1.0); coh.mult(1.0); applyForce(sep); applyForce(ali); applyForce(coh); } void applyForce(PVector f) { acc.add(f); } void update() { vel.add(acc); vel.limit(maxSpeed); pos.add(vel); acc.mult(0); } void borders() { if (pos.x < -width/2-r) pos.x = width + r; if (pos.x > width/2 + r) pos.x = -r; if (pos.y < -height/2-r) pos.y = height + r; if (pos.y > height/2 + r) pos.y = -r; if (pos.z < -250 - r) pos.z = width + r; if (pos.z > 250 + r) pos.z = -r; } void render() { float angle = vel.heading2D(); float theta = angle + radians(90); //float hue = abs(degrees(angle)%360); fill(c); noStroke(); pushMatrix(); translate(pos.x, pos.y, pos.z); rotate(theta); beginShape(TRIANGLES); vertex(0, -r*2); vertex(-r, r*2); vertex(r, r*2); endShape(); popMatrix(); } PVector separate(ArrayList<Boid> boids) { float desiredSeparation = 25f; PVector steer = new PVector(0, 0); float count = 0; for (Boid other : boids) { float d = PVector.dist(pos, other.pos); if ((d > 0) && (d < desiredSeparation)) { PVector diff = PVector.sub(pos, other.pos); diff.normalize(); diff.div(d); steer.add(diff); count++; } } if (count > 0) { steer.div(count); } if (steer.mag() > 0) { //steer.setMag(maxSpeed); steer.normalize(); steer.mult(maxSpeed); steer.sub(vel); steer.limit(maxForce); } return steer; } PVector align(ArrayList<Boid> boids) { float neighbordist = 50; PVector sum = new PVector(0, 0); float count = 0; for (Boid other : boids) { float d = PVector.dist(pos, other.pos); if ((d > 0) && (d < neighbordist)) { sum.add(other.vel); count++; } } if (count > 0) { sum.div(count); sum.normalize(); sum.mult(maxSpeed); PVector steer = PVector.sub(sum, vel); steer.limit(maxForce); return steer; } else { return new PVector(); } } PVector cohesion(ArrayList<Boid> boids) { float neighbordist = 50; PVector sum = new PVector(0, 0); float count = 0; for (Boid other : boids) { float d = PVector.dist(pos, other.pos); if ((d > 0) && (d < neighbordist)) { sum.add(other.pos); count++; } } if (count > 0) { sum.div(count); return seek(sum); } else { return new PVector(0, 0); } } PVector seek(PVector target) { PVector desired = PVector.sub(target, pos); desired.normalize(); desired.mult(maxSpeed); PVector steer = PVector.sub(desired, vel); steer.limit(maxForce); return steer; } void randomize() { float angle = random(360); float theta = radians(angle); vel = new PVector(cos(theta), sin(theta)); } }