• fullscreen
  • Swarm3D.pde
  • particle.pde
  • // Gravity Swarm
    // Claudio Gonzales, March 2010
    // Albuquerque, New Mexico
    
    particle[] Z = new particle[8000];
    float colour = random(1);
    boolean tracer = false;
    int depth;
    
    void setup() {
      smooth();
      size(500,500,P2D);  
      depth = width;
      background(255);
      frameRate(25);
      
      float n = 100;
      float px, py, pz;
      float m, v, theta, phi;
      
      for(int k = 0; k < n; k++) {
        px = random(width);
        py = random(height);
        pz = random(depth);
        m = random(50);
        for(int i = int((Z.length-1000)*k/n); i < int((Z.length-1000)*(k+1)/n); i++) {
          v = sq(random(sqrt(m)));
          theta = random(TWO_PI);
          phi = random(TWO_PI);
          Z[i] = new particle( px+v*cos(phi)*cos(theta), py+v*cos(phi)*sin(theta), pz+v*sin(phi), 0, 0, 0, 1 );
        }
      }
      px = width/2;
      py = height/2;
      for(int i = Z.length-1000; i < Z.length; i++) {
        pz = random(depth);
        v = sq(random(sqrt(width/4)));
        theta = random(TWO_PI);
        Z[i] = new particle( px+v*cos(theta), py+v*sin(theta), pz, 0, 0, 0, 1 );
      }
    
      /*
      for(int i = 0; i < Z.length; i++) {
        r = i/float(Z.length);
        Z[i] = new particle( random(width), r*height, depth/2, 0, 0, 0, 1 );
      }
      */
      
      frameRate(60);
    
    }
    
    void draw() {
      
      colorMode(RGB,255);
      float r;
      
      if( !tracer ) {
        background(0);
      }
      else {
        fill(0,10);
        rect(0,0,width,height);
      }
      
      filter(INVERT);
    
      for(int i = 0; i < Z.length; i++) {
        if( mousePressed && mouseButton == LEFT ) {
          Z[i].gravitate( new particle( mouseX, mouseY, depth/2, 0, 0, 0, 0.75 ) );
        }
        else if( mousePressed && mouseButton == RIGHT ) {
          Z[i].repel( new particle( mouseX, mouseY, depth/2, 0, 0, 0, 1 ) );
        }
        else {
          Z[i].deteriorate();
        }
    
        Z[i].update();
        r = float(i)/Z.length;
        colorMode(HSB,1);
        if( Z[i].magnitude/100 < 0.1 ) {
          stroke( colour, pow(r,0.1), 0.9*sqrt(1-r), Z[i].magnitude/100+abs(Z[i].z/depth)*0.05 );
        }
        else {
          stroke( colour, pow(r,0.1), 0.9*sqrt(1-r), 0.1+abs(Z[i].z/depth)*0.05 );
        }
        Z[i].display();
      }
    
      colour+=random(0.01);
      colour = colour%1;
    
      filter(INVERT);
      
    }
    
    void keyPressed() {
      
      if( key == ' ' ) {
      
        float r, choice = random(1);
        
        for(int i = 0; i < Z.length; i++) {
          
          r = i/float(Z.length);
      
          if( choice > 0.8 ) {
            // Slice
            Z[i].reset( r*width, r*height, random(depth), 0, 0, 0, 1 );
          }
    
          else if( choice > 0.6 ) {
            // Plane
            Z[i].reset( random(width), r*height, depth/2, 0, 0, 0, 1 );
          }
          
          else if( choice > 0.4 ) {
            // X
            if( r < 0.5 )
              Z[i].reset( (1-2*r)*width, 2*r*height, 2*r*depth, 0, 0, 0, 1 );
            else
              Z[i].reset( (1-(2*r-1))*width, (1-(2*r-1))*height, (2*r-1)*depth, 0, 0, 0, 1 );
          }
          
          else if( choice > 0.2 ) {
            // Smooth Curve
            Z[i].reset( (1-r)*width, sqrt(r)*height, r*depth, 0, 0, 0, 1 );
          }
      
          else { 
            // Swirl
            Z[i].reset( height/2+r*cos(r*10*PI)*height/2, height/2+r*sin(r*10*PI)*height/2, r*depth, 0, 0, 0, 1 );
          }
        }
      
      }
      else if( key == ENTER ) {
        tracer = !tracer;
      }
        
    }
    
    
    
    
    class particle {
      
      float x;
      float y;
      float z;
      float px;
      float py;
      float magnitude;
      float theta;
      float phi;
      float mass;
      
      particle( float dx, float dy, float dz, float V, float T, float P, float M ) {
        x = dx;
        y = dy;
        z = dz;
        px = dx;
        py = dy;
        magnitude = V;
        theta = T;
        phi = P;
        mass = M;
      }
      
      void reset ( float dx, float dy, float dz, float V, float T, float P, float M ) {
        x = dx;
        y = dy;
        z = dz;
        px = dx;
        py = dy;
        magnitude = V;
        theta = T;
        phi = P;
        mass = M;
      }
      
      void gravitate( particle C ) {
        float dx, dy, dz;
        float F, t, p;
        if( sq( x - C.x ) + sq( y - C.y ) + sq( z - C.z ) != 0 ) {
          F = mass * C.mass;
          // magnitude
    
          dx = ( mass * x + C.mass * C.x ) / ( mass + C.mass );
          dy = ( mass * y + C.mass * C.y ) / ( mass + C.mass );
          dz = ( mass * z + C.mass * C.z ) / ( mass + C.mass );
          // find point to which particle is being attracted (dx,dy,dz)
          
          t = atan2( dy-y, dx-x );                          // find yaw angle
          p = atan2( dz-z, sqrt( sq(dy-y) + sq(dx-x) ) ) ;  // find depth angle
          
          dx = F * cos(p) * cos(t);
          dy = F * cos(p) * sin(t);
          dz = F * sin(p);
    
          dx += magnitude * cos(phi) * cos(theta);
          dy += magnitude * cos(phi) * sin(theta);
          dz += magnitude * sin(phi);
          
          magnitude = sqrt( sq(dx) + sq(dy) + sq(dz) );
          theta = atan2( dy, dx );
          phi = atan2( dz, sqrt( sq(dx) + sq(dy) ) );
    
        }
      }
    
      void repel( particle C ) {
        float dx, dy, dz;
        float F, t, p;
        if( sq( x - C.x ) + sq( y - C.y ) + sq( z - C.z ) != 0 ) {
          F = mass * C.mass;
          // magnitude
    
          dx = ( mass * x + C.mass * C.x ) / ( mass + C.mass );
          dy = ( mass * y + C.mass * C.y ) / ( mass + C.mass );
          dz = ( mass * z + C.mass * C.z ) / ( mass + C.mass );
          // find point to which particle is being attracted (dx,dy,dz)
          
          t = atan2( y-dy, x-dx );                          // find yaw angle
          p = atan2( z-dz, sqrt( sq(dy-y) + sq(dx-x) ) ) ;  // find depth angle
          
          dx = F * cos(p) * cos(t);
          dy = F * cos(p) * sin(t);
          dz = F * sin(p);
    
          dx += magnitude * cos(phi) * cos(theta);
          dy += magnitude * cos(phi) * sin(theta);
          dz += magnitude * sin(phi);
          
          magnitude = sqrt( sq(dx) + sq(dy) + sq(dz) );
          theta = atan2( dy, dx );
          phi = atan2( dz, sqrt( sq(dx) + sq(dy) ) );
    
        }
      }
      
      void deteriorate() {
        magnitude *= 0.925;
      }
      
      void update() {
        
        x += magnitude * cos(phi) * cos(theta);
        y += magnitude * cos(phi) * sin(theta);
        z += magnitude * sin(phi);
    
      }
      
      void display() {
        line(px,py,x,y);
        px = x;
        py = y;
      }
      
      
    }
    
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Claudio Gonzales

    Galactic Dust

    Add to Faves Me Likey@! 90
    You must login/register to add this sketch to your favorites.

    An extension of my Swarm projects into three dimensions, with some new special effects thrown in.

    Click left or right to attract/repel particles (respectively).
    Press the space bar to reset the particles in one of five ways, press enter to toggle tracing function.

    dotlassie
    5 Mar 2010
    Whose idea was this originally?
    This is freekin' amazing!
    To dotlassie:
    It's based off one of my old programs that I thought up, when I was just starting to mess around with particles and the idea of attraction. See the Particle Swarm (http://openprocessing.org/visuals/?visualID=2363). I know my particle code has been recycled a few times around the site, but I can't name any sketches offhand.

    To Sinan Aşçıoğlu:
    Thank you very much! I always love to hear that people like my work.


    polar
    6 Mar 2010
    Awesome!
    I made some changes using it as screensaver with simulated keypressed (' '), screen deleting and simulated mouse-movements.
    Thank you so much!
    polar
    7 Mar 2010

    I added the screensaver on this site:

    http://openprocessing.org/visuals/?visualID=8098
    Very cool! I'm honored to have helped fuel something so intriguing!
    Denis Hovart
    3 Apr 2011
    Love it !
    Leonardo
    11 Dec 2012
    Hi,

    I love your design .. great wor, however I have a problem hope you (someone) can help.
    However, I am having trouble running the code on the Processing application, on my browser it runs fine, on the dektop application it runs VERY SLOW, why might this be?

    any comments?
    Claudio Gonzales
    12 Dec 2012
    Hmmm..... My guess would be the build environment. Make sure to use P2D, it makes the rendering of these particles much faster. But if you're copying the code verbatim, then you shouldn't be having that issue.
    Adam Kercheval
    31 May 2013
    bump up the frame rate. worked for me.
    You need to login/register to comment.