We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › wandering 3D
Page Index Toggle Pages: 1
wandering 3D (Read 1074 times)
wandering 3D
Aug 22nd, 2009, 1:07am
 
Yes! I can send a post!
i try since a certain time to put the daniel shiffman's wandering example in 3D but still don't find a way to do this. I face great difficulties to understand how to rotate the boid in the direction of velocity.
I made this sketch to understand how i could rotate an object around x, y, z axis:
import processing.opengl.*;

float theta = 0;
float phi = 0;
float psi = 0;
void setup(){
 size(200, 200, OPENGL);
 
}
void draw(){
 background( 255);
 directionalLight(250, 250, 250, -1, 0, -1);

 translate(width/2, height/2, 0);
float Ry[][]={{cos(theta), 0, sin(theta)},
            {0, 1, 0},
            {-sin(theta), 0, cos(theta)}};
float Rz[][]={{cos(phi), -sin(phi), 0},
            {sin(phi), cos(phi), 0},
            {0, 0, 1}};
float Rx[][]={{1, 0, 0},
            {0, cos(psi), -sin(psi)},
            {0, sin(psi), cos(psi)}};
float Ryz[][]={{Ry[0][0]*Rz[0][0]+Ry[0][1]*Rz[1][0]+Ry[0][2]*Rz[2][0], Ry[0][0]*Rz[0][1]+Ry[0][1]*Rz[1][1]+Ry[0][2]*Rz[2][1], Ry[0][0]*Rz[0][2]+Ry[0][1]*Rz[1][2]+Ry[0][2]*Rz[2][2]},
            {Ry[1][0]*Rz[0][0]+Ry[1][1]*Rz[1][0]+Ry[1][2]*Rz[2][0], Ry[1][0]*Rz[0][1]+Ry[1][1]*Rz[1][1]+Ry[1][2]*Rz[2][1], Ry[1][0]*Rz[0][2]+Ry[1][1]*Rz[1][2]+Ry[1][2]*Rz[2][2]},
            {Ry[2][0]*Rz[0][0]+Ry[2][1]*Rz[1][0]+Ry[2][2]*Rz[2][0], Ry[2][0]*Rz[0][1]+Ry[2][1]*Rz[1][1]+Ry[2][2]*Rz[2][1], Ry[2][0]*Rz[0][2]+Ry[2][1]*Rz[1][2]+Ry[2][2]*Rz[2][2]}};
           
float Ryzx[][]={{Ryz[0][0]*Rx[0][0]+Ryz[0][1]*Rx[1][0]+Ryz[0][2]*Rx[2][0], Ryz[0][0]*Rx[0][1]+Ryz[0][1]*Rx[1][1]+Ryz[0][2]*Rx[2][1], Ryz[0][0]*Rx[0][2]+Ryz[0][1]*Rx[1][2]+Ryz[0][2]*Rx[2][2]},
              {Ryz[1][0]*Rx[0][0]+Ryz[1][1]*Rx[1][0]+Ryz[1][2]*Rx[2][0], Ryz[1][0]*Rx[0][1]+Ryz[1][1]*Rx[1][1]+Ryz[1][2]*Rx[2][1], Ryz[1][0]*Rx[0][2]+Ryz[1][1]*Rx[1][2]+Ryz[1][2]*Rx[2][2]},
              {Ryz[2][0]*Rx[0][0]+Ryz[2][1]*Rx[1][0]+Ryz[2][2]*Rx[2][0], Ryz[2][0]*Rx[0][1]+Ryz[2][1]*Rx[1][1]+Ryz[2][2]*Rx[2][1], Ryz[2][0]*Rx[0][2]+Ryz[2][1]*Rx[1][2]+Ryz[2][2]*Rx[2][2]}};        
            applyMatrix (Ryzx[0][0],Ryzx[0][1],Ryzx[0][2],0,
                    Ryzx[1][0],Ryzx[1][1],Ryzx[1][2],0,
                    Ryzx[2][0],Ryzx[2][1],Ryzx[2][2],0,
                    0,0,0,1);
         box(50);  
      stroke(50, 100, 0);  
      noFill();
         theta+=0.01;
         phi+=0.0;
         psi+=0.00;
         println(Ry[0][1]);
}

But i don't even know if i need this to calculate angle between velocity and the location of the boid. I don't know how to use the dot product with 3D vectors
I'm lost for sure, if anyone have any clue, it probably will be a great help for me.
thanks, theo.
Re: wandering 3D
Reply #1 - Aug 22nd, 2009, 3:11am
 
Haven't you tried using rotateX(), rotateY(), rotateZ() instead
Re: wandering 3D
Reply #2 - Aug 22nd, 2009, 3:33am
 
Yes, i tried and i think it work the same, but what i don't figure out, is the way you get the angle between velocity and location of the boid, and how you define them, do i need 3 vectors for each axis(heading,  attitude, roll)of  velocity, location, target, desired, steer...  ?
I'm really lost don't find a way how to think the thing.
Re: wandering 3D
Reply #3 - Aug 22nd, 2009, 3:50am
 
I made this, sorry it's a mess, just made a massacre with the daniel shiffman's sketch,  but maybe you will see what i am looking for :

import processing.opengl.*;

Boid[] wanderer = new Boid[1];
boolean debug = true;

void setup() {

 size(1000,1000, OPENGL);
 for(int i=0; i<wanderer.length; i ++){
 wanderer[i] = new Boid(new PVector(width/2,height/2, 00),6.0,0.1);
 }
 smooth();
}

void draw() {
 
 background(0);
 for(int i=0; i<wanderer.length; i ++){
 wanderer[i].wander();
 wanderer[i].run();
}
}
void mousePressed() {
 debug = !debug;
}

class Boid {

 PVector loc;
 PVector vel;
 PVector acc;
 PVector target;
 float r;
 float wandertheta;
 float wanderphi;
 float wanderpsi;
 float maxforce;    // Maximum steering force
 float maxspeed;    // Maximum speed
 float theta = 0;
 float phi = 0;
 float psi = 0;
 Boid(PVector l, float ms, float mf) {
   acc = new PVector(0,0, 0);
   vel = new PVector(0,0, 0);
   loc = l.get();
   r = 10.0;
   wandertheta = 0.0;
   wanderphi = 0.0;
   wanderpsi = 0.0;
   maxspeed = ms;
   maxforce = mf;
 }
 
 void run() {
   update();
   borders();
   render();
 }
 
 // Method to update location
 void update() {
   // Update velocity
   vel.add(acc);
   // Limit speed
   vel.limit(maxspeed);
   loc.add(vel);
   // Reset accelertion to 0 each cycle
   acc.mult(0);
 }

 void seek(PVector target) {
   acc.add(steer(target,false));
 }

 void arrive(PVector target) {
   acc.add(steer(target,true));
 }
 
 void wander() {
   float wanderR = 20.0f;         // Radius for our "wander circle"
   float wanderD = 60.0f;         // Distance for our "wander circle"
   float change = 0.25f;
   wandertheta += random(-change, change);     // Randomly change wander theta
   wanderphi += random(-change, change);
   wanderpsi += random(-change, change);
   // Now we have to calculate the new location to steer towards on the wander circle
   PVector circleloc = vel.get();  // Start with velocity
   circleloc.normalize();            // Normalize to get heading
   circleloc.mult(wanderD);          // Multiply by distance
   circleloc.add(loc);               // Make it relative to boid's location
   
   PVector circleOffSet = new PVector(wanderR*cos(wandertheta),wanderR*sin(wanderphi), wanderR*cos(wanderpsi));
   PVector target = PVector.add(circleloc,circleOffSet);
   acc.add(steer(target,false));  // Steer towards it
   
   // Render wandering circle, etc.
   if (debug) drawWanderStuff(loc,circleloc,target,wanderR);
   
 }  
 
 // A method that calculates a steering vector towards a target
 // Takes a second argument, if true, it slows down as it approaches the target
 PVector steer(PVector target, boolean slowdown) {
   PVector steer;  // The steering vector
   PVector desired = PVector.sub(target,loc);  // A vector pointing from the location to the target
   float d = desired.mag(); // Distance from the target is the magnitude of the vector
   // If the distance is greater than 0, calc steering (otherwise return zero vector)
   if (d > 0) {
     // Normalize desired
     desired.normalize();
     // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
     if ((slowdown) && (d < 100.0f)) desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary
     else desired.mult(maxspeed);
     // Steering = Desired minus Velocity
     steer = PVector.sub(desired,vel);
     steer.limit(maxforce);  // Limit to maximum steering force
   } else {
     steer = new PVector(0,0, -100);
   }
   return steer;
 }
 
 void render() {
   // Draw a triangle rotated in the direction of velocity
   PVector v = new PVector();
   v = vel.get();
   PVector ox = new PVector(loc.x, 0, 0);
   PVector oy = new PVector(0, loc.y, 0);
   PVector oz = new PVector(0, 0, loc.z);
   v.normalize();
   ox.normalize();  
   oy.normalize();  
   oz.normalize();
   float a = v.mag();
   
   float b = ox.mag();
   float d = oy.mag();
   float f = oy.mag();

  float cosinustheta = v.dot(ox)/(a*b);
  float theta = acos(cosinustheta)+radians(90);
 
    float cosinusphi = v.dot(oy)/(a*d);
  float phi = acos(cosinusphi)+radians(90);

float cosinuspsi = v.dot(oz)/(a*f);
  float psi = acos(cosinuspsi)+radians(90);

   println(cosinustheta);
   pushMatrix();
 
 
  float Ry[][]={{cos(theta), 0, sin(theta),0},
             {0, 1, 0, 0},
             {-sin(theta), 0, cos(theta), 0},
             {0, 0, 0, 1}};
           
  float Rz[][]={{cos(phi), -sin(phi), 0, 0},
             {sin(phi), cos(phi), 0, 0},
             {0, 0, 1, 0},
             {0, 0, 0, 1}};
           
  float Rx[][]={{1, 0, 0, 0},
             {0, cos(psi), -sin(psi), 0},
             {0, sin(psi), cos(psi), 0},
             {0, 0, 0, 1}};
           
float Ryz[][]={{Ry[0][0]*Rz[0][0]+Ry[0][1]*Rz[1][0]+Ry[0][2]*Rz[2][0]+Ry[0][3]*Rz[3][0], Ry[0][0]*Rz[0][1]+Ry[0][1]*Rz[1][1]+Ry[0][2]*Rz[2][1]+Ry[0][3]*Rz[3][1], Ry[0][0]*Rz[0][2]+Ry[0][1]*Rz[1][2]+Ry[0][2]*Rz[2][2]+Ry[0][3]*Rz[3][2], Ry[0][0]*Rz[0][3]+Ry[0][1]*Rz[1][3]+Ry[0][2]*Rz[2][3]+Ry[0][3]*Rz[3][3]},
              {Ry[1][0]*Rz[0][0]+Ry[1][1]*Rz[1][0]+Ry[1][2]*Rz[2][0]+Ry[1][3]*Rz[3][0], Ry[1][0]*Rz[0][1]+Ry[1][1]*Rz[1][1]+Ry[1][2]*Rz[2][1]+Ry[1][3]*Rz[3][1], Ry[1][0]*Rz[0][2]+Ry[1][1]*Rz[1][2]+Ry[1][2]*Rz[2][2]+Ry[1][3]*Rz[3][2], Ry[1][0]*Rz[0][3]+Ry[1][1]*Rz[1][3]+Ry[1][2]*Rz[2][3]+Ry[1][3]*Rz[3][3]},
              {Ry[2][0]*Rz[0][0]+Ry[2][1]*Rz[1][0]+Ry[2][2]*Rz[2][0]+Ry[2][3]*Rz[3][0], Ry[2][0]*Rz[0][1]+Ry[2][1]*Rz[1][1]+Ry[2][2]*Rz[2][1]+Ry[2][3]*Rz[3][1], Ry[2][0]*Rz[0][2]+Ry[2][1]*Rz[1][2]+Ry[2][2]*Rz[2][2]+Ry[2][3]*Rz[3][2], Ry[2][0]*Rz[0][3]+Ry[2][1]*Rz[1][3]+Ry[2][2]*Rz[2][3]+Ry[2][3]*Rz[3][3]},
              {Ry[3][0]*Rz[0][0]+Ry[3][1]*Rz[1][0]+Ry[3][2]*Rz[2][0]+Ry[3][3]*Rz[3][0], Ry[3][0]*Rz[0][1]+Ry[3][1]*Rz[1][1]+Ry[3][2]*Rz[2][1]+Ry[3][3]*Rz[3][1], Ry[3][0]*Rz[0][2]+Ry[3][1]*Rz[1][2]+Ry[3]
Re: wandering 3D
Reply #4 - Aug 22nd, 2009, 4:33am
 
oops, this is it, sorry :


import processing.opengl.*;

Boid[] wanderer = new Boid[1];
boolean debug = true;

void setup() {

 size(1000,1000, OPENGL);
 for(int i=0; i<wanderer.length; i ++){
 wanderer[i] = new Boid(new PVector(width/2,height/2, 00),6.0,0.1);
 }
 smooth();
}

void draw() {
 
 background(0);
 for(int i=0; i<wanderer.length; i ++){
 wanderer[i].wander();
 wanderer[i].run();
}
}
void mousePressed() {
 debug = !debug;
}

class Boid {

 PVector loc;
 PVector vel;
 PVector acc;
 PVector target;
 float r;
 float wandertheta;
 float wanderphi;
 float wanderpsi;
 float maxforce;    // Maximum steering force
 float maxspeed;    // Maximum speed
 float theta = 0;
 float phi = 0;
 float psi = 0;
 Boid(PVector l, float ms, float mf) {
   acc = new PVector(0,0, 0);
   vel = new PVector(0,0, 0);
   loc = l.get();
   r = 10.0;
   wandertheta = 0.0;
   wanderphi = 0.0;
   wanderpsi = 0.0;
   maxspeed = ms;
   maxforce = mf;
 }
 
 void run() {
   update();
   borders();
   render();
 }
 
 // Method to update location
 void update() {
   // Update velocity
   vel.add(acc);
   // Limit speed
   vel.limit(maxspeed);
   loc.add(vel);
   // Reset accelertion to 0 each cycle
   acc.mult(0);
 }

 void seek(PVector target) {
   acc.add(steer(target,false));
 }

 void arrive(PVector target) {
   acc.add(steer(target,true));
 }
 
 void wander() {
   float wanderR = 20.0f;         // Radius for our "wander circle"
   float wanderD = 60.0f;         // Distance for our "wander circle"
   float change = 0.25f;
   wandertheta += random(-change, change);     // Randomly change wander theta
   wanderphi += random(-change, change);
   wanderpsi += random(-change, change);
   // Now we have to calculate the new location to steer towards on the wander circle
   PVector circleloc = vel.get();  // Start with velocity
   circleloc.normalize();            // Normalize to get heading
   circleloc.mult(wanderD);          // Multiply by distance
   circleloc.add(loc);               // Make it relative to boid's location
   
   PVector circleOffSet = new PVector(wanderR*cos(wandertheta),wanderR*sin(wanderphi), wanderR*cos(wanderpsi));
   PVector target = PVector.add(circleloc,circleOffSet);
   acc.add(steer(target,false));  // Steer towards it
   
   // Render wandering circle, etc.
   if (debug) drawWanderStuff(loc,circleloc,target,wanderR);
   
 }  
 
 // A method that calculates a steering vector towards a target
 // Takes a second argument, if true, it slows down as it approaches the target
 PVector steer(PVector target, boolean slowdown) {
   PVector steer;  // The steering vector
   PVector desired = PVector.sub(target,loc);  // A vector pointing from the location to the target
   float d = desired.mag(); // Distance from the target is the magnitude of the vector
   // If the distance is greater than 0, calc steering (otherwise return zero vector)
   if (d > 0) {
     // Normalize desired
     desired.normalize();
     // Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
     if ((slowdown) && (d < 100.0f)) desired.mult(maxspeed*(d/100.0f)); // This damping is somewhat arbitrary
     else desired.mult(maxspeed);
     // Steering = Desired minus Velocity
     steer = PVector.sub(desired,vel);
     steer.limit(maxforce);  // Limit to maximum steering force
   } else {
     steer = new PVector(0,0, -100);
   }
   return steer;
 }
 
 void render() {
   // Draw a triangle rotated in the direction of velocity
   PVector v = new PVector();
   v = vel.get();
   PVector ox = new PVector(loc.x, 0, 0);
   PVector oy = new PVector(0, loc.y, 0);
   PVector oz = new PVector(0, 0, loc.z);
   v.normalize();
   ox.normalize();  
   oy.normalize();  
   oz.normalize();
   float a = v.mag();
   
   float b = ox.mag();
   float d = oy.mag();
   float f = oy.mag();

  float cosinustheta = v.dot(ox)/(a*b);
  float theta = acos(cosinustheta)+radians(90);
 
    float cosinusphi = v.dot(oy)/(a*d);
  float phi = acos(cosinusphi)+radians(90);

float cosinuspsi = v.dot(oz)/(a*f);
  float psi = acos(cosinuspsi)+radians(90);

   println(cosinustheta);
   pushMatrix();
 
translate(loc.x, loc.y, loc.z);
rotateY(theta);
rotateZ(phi);
rotateX(psi);
   beginShape(TRIANGLES);
   fill(50, 255, 0);
   noStroke();
   vertex(0, -r*2,0);
   vertex(-r, r*2, -r*2);
   vertex(r, r*2, 0);
   
   fill(255, 50, 0);
   noStroke();
   vertex(0, -r*2,0);
   vertex(-r, r*2, r*2);
   vertex(r, r*2, 0);
   
   fill(0, 50, 255);
   noStroke();
   vertex(r, r*2,0);
   vertex(-r, r*2, r*2);
    vertex(-r, r*2, -r*2);
   
    fill(255, 255, 0);
    noStroke();
   vertex(0, -r*2,0);
   vertex(-r, r*2, r*2);
    vertex(-r, r*2, -r*2);
   
   endShape();
   popMatrix();
    if(vel.x <=0 && vel.y <=0 || vel.y <=0){
  theta*=-1;
}
 }
 
 // Wraparound
 void borders() {
   if (loc.x < -r) loc.x = 1000+r;
   if (loc.y < -r) loc.y = 1000+r;
   if (loc.z < -1000-r) loc.z = 0-r;
   if (loc.x > 1000+r) loc.x = -r;
   if (loc.y > 1000+r) loc.y = -r;
   if (loc.z > 0+r) loc.z = -1000-r;
   
 }

}


// A method just to draw the circle associated with wandering
void drawWanderStuff(PVector loc, PVector circle, PVector target, float rad) {
  noFill();
 stroke(150, 250, 50, 40);
 pushMatrix();
 translate(circle.x,circle.y,circle.z);
 sphere(rad);
 popMatrix();
 noStroke();
  fill(250, 150, 50);
  pushMatrix();
 translate(target.x,target.y,target.z);
 sphere(6);
 popMatrix();
 stroke(255);
 line(loc.x,loc.y, loc.z, circle.x,circle.y, circle.z);
 line(circle.x,circle.y, circle.z, target.x,target.y, target.z);
}
Re: wandering 3D
Reply #5 - Aug 22nd, 2009, 5:14am
 
I'm not sure, but maybe this post can help
http://processing.org/discourse/yabb2/?num=1248129751
Re: wandering 3D
Reply #6 - Aug 22nd, 2009, 8:23am
 
Thanks very much antiplastik, you was right, seems to work now with this method .Still a doubtful sketch probably, but it make something which seems coherent when you run it:

import processing.opengl.*;

Boid[] wanderer = new Boid[100];


void setup() {

 size(1000,1000, OPENGL);
 for(int i=0; i<wanderer.length; i ++){
 wanderer[i] = new Boid(new PVector(width/2,height/2, 00),6.0,0.1);
 }
 smooth();
}

void draw() {
 
 background(0);
 directionalLight(250, 250, 250, -1, 0, -1);
 for(int i=0; i<wanderer.length; i ++){
 wanderer[i].wander();
 wanderer[i].run();
}
}
class Boid {

 PVector loc;
 PVector vel;
 PVector acc;
 PVector target;
 float r;
 float wandertheta;
 float wanderphi;
 float wanderpsi;
 float maxforce;    // Maximum steering force
 float maxspeed;    // Maximum speed
 float theta = 0;
 float phi = 0;
 float psi = 0;
 Boid(PVector l, float ms, float mf) {
   acc = new PVector(0,0, 0);
   vel = new PVector(0,0, 0);
   loc = l.get();
   r = 10.0;
   wandertheta = 0.0;
   wanderphi = 0.0;
   wanderpsi = 0.0;
   maxspeed = ms;
   maxforce = mf;
 }
 
 void run() {
   update();
   borders();
   render();
 }
 
 // Method to update location
 void update() {
   // Update velocity
   vel.add(acc);
   // Limit speed
   vel.limit(maxspeed);
   loc.add(vel);
   // Reset accelertion to 0 each cycle
   acc.mult(0);
 }
 void wander() {
   float wanderR = 20.0f;         // Radius for our "wander circle"
   float wanderD = 60.0f;         // Distance for our "wander circle"
   float change = 0.25f;
   wandertheta += random(-change, change);     // Randomly change wander theta
   wanderphi += random(-change, change);
   wanderpsi += random(-change, change);
   // Now we have to calculate the new location to steer towards on the wander circle
   PVector circleloc = vel.get();  // Start with velocity
   circleloc.normalize();            // Normalize to get heading
   circleloc.mult(wanderD);          // Multiply by distance
   circleloc.add(loc);               // Make it relative to boid's location
   
   PVector circleOffSet = new PVector(wanderR*cos(wandertheta),wanderR*sin(wanderphi), wanderR*cos(wanderpsi));
   PVector target = PVector.add(circleloc,circleOffSet);
   PVector steer;
   PVector desired = PVector.sub(target,loc);  // A vector pointing from the location to the target
     // Normalize desired
     desired.normalize();
     desired.mult(maxspeed);
     // Steering = Desired minus Velocity
     steer = PVector.sub(desired,vel);
     steer.limit(maxforce);  // Limit to maximum steering force
   
    acc.add(steer);  // Steer towards it
   
// drawWanderStuff(loc,circleloc,target,wanderR);
 
 }
 
 void render() {
   // Draw a triangle rotated in the direction of velocity
    PVector l = new PVector(0, loc.y, 0);
 
   
   PVector v ;
   v = vel.get();
     
   v.normalize();
    PVector crss = vel.cross(l);
   
    crss.normalize();
   
 
   
   l.normalize();
   
   
   
 
   
  float theta = PVector.angleBetween(v, l);
 


   pushMatrix();
 
translate(loc.x, loc.y, loc.z);
rotate(-theta, crss.x, crss.y, crss.z);

noStroke();
  box(20);
   popMatrix();
 
 }
 
 // Wraparound
 void borders() {
   if (loc.x < -r) loc.x = 1000+r;
   if (loc.y < -r) loc.y = 1000+r;
   if (loc.z < -1000-r) loc.z = 0-r;
   if (loc.x > 1000+r) loc.x = -r;
   if (loc.y > 1000+r) loc.y = -r;
   if (loc.z > 0+r) loc.z = -1000-r;
   
 }

}

Page Index Toggle Pages: 1