• fullscreen
  • fractals3D.pde
  • generators.pde
  • // Fractal3D forest
    // create animating fractals with changing color, rotations and growing
    //
    //
     
    PVector triCol0[] = new PVector[] {
      new PVector( 1.0f, -1.0f,-1.0f),
      new PVector( -1.0f, 1.0f, -1.0f),
      new PVector( -1.0f,-1.0f,1.0f),
      new PVector( 1.0f,1.0f,1.0f)
      };
     
    PVector growStart[] = new PVector[] {
      new PVector( 1.0f, -1.0f, -1.0f),
      new PVector( 1.0f, 1.0f,-1.0f),
      new PVector( 1.0f, -1.0f,  -1.0f),
      new PVector( 1.0f, -1.0f,  -1.0f),
    };
     
    PVector binaryCol[] = new PVector[] {
      new PVector( -1.0f, -1.0f, 1.0f),
      new PVector( 1.0f, 1.0f,1.0f),
      new PVector( -1.0f, -1.0f,  1.0f),
      new PVector( -1.0f, -1.0f,  1.0f),
    };
    PVector[] cols[] = new PVector[][] {
      triCol0,
      binaryCol,
      growStart,
    };
     
    float  g_Fov = 45.0f;
    int CalculateMaxDepth( PVector pos, PVector cpos, float initialsize, float lodFactor, float logFactor)
    {
      PVector dvect = new PVector();
      dvect.set(cpos);
      dvect.sub(pos);
      float dist = dvect.mag();
     
      // find width of single pixel
      PVector cvect = new PVector();
      cvect.set(cpos);
      dvect.normalize();
      cvect.normalize();
      if ( cvect.dot(dvect) < cos(radians(45)))
        return 0;
      if ( cvect.dot(dvect) < cos(radians(35)))
        initialsize*=0.5f;
      float pixelwidth = (tan( g_Fov *0.5)*dist / 480.0f ) *lodFactor;
      // cull quality on behinid or to the side of the camera
      return (int)(log( initialsize / pixelwidth) / log(logFactor));
    }
    PFont g_font;
    void setup()
    {
      size(640,480,P3D);
      noSmooth();
      noStroke();
      mouseX=width/2-50;
      mouseY=40;
     
      g_font = loadFont("Arial-ItalicMT-32.vlw");
    }
    float smoothstep (float edge0, float edge1, float x)
    {
      x =  min(max((x - edge0) / (edge1 - edge0),0.0f),1.0f);
      return x*x*(3-2*x);
    }
    void drawBase()
    {
      pushMatrix();  // draw base
      scale(40.0f);
      fill(160,120,80);
      translate(0.0f,-0.015f,0.0f);
      box(1.05f, 0.04f, 1.05f);
      translate(0.0f,-0.5f,0.0f);
      box(1.2f, 1.0f, 1.2f);
      popMatrix();
    }
    int drawFractal( PVector campos, float px, float py, float animf, boolean isSponge, PVector[] colTable )
    {
      pushMatrix();
      translate(px,0.0f,py);
     
      // calculate animation factors
      float r0 = smoothstep(8.0f, 12.0f,animf)*2.0f *PI;
      float anim = sin(min(max(animf-12.0f,0.0),4.0f)*PI/4.0f)*PI*2.0f;
      float g0 = smoothstep(2.0f, 12.0f,animf)*10.0f;
      float hidden = smoothstep(0.2, 2.,animf)* smoothstep(20.0, 18.,animf);
      scale(smoothstep(0.0f,0.25,hidden));
      hidden = smoothstep(0.5f,1.0,hidden);
     
      rotateY(r0);
      drawBase();
     
      float intialSize =  isSponge ? 30.0f : 40.0f;
      scale( intialSize);
      translate(0.0f, -1.0f + min(hidden,1.0f),0.0f);
      PVector pos = new PVector(px,20.0f,py);
      int maxDepth = CalculateMaxDepth(pos, campos, intialSize, 8.0,isSponge ? 3 : 2);
      int selDepth = (int)ceil(g0);
      float blendV = g0 - floor(g0);
      blendV = smoothstep(0.,1.,blendV);
     
      if ( maxDepth < selDepth )
      {
        selDepth =maxDepth;
        blendV=1.;
      }
      if (!isSponge)
      {
         SeirpenskiTriangle( 0,selDepth,anim, new PVector(1.0,1.0,1.0),
           0.5f, colTable, blendV);
      }
      else
      {
        translate(0.0f,0.5,0.);
        PVector cvect = new PVector();
        cvect.set(pos);
        cvect.sub(campos);
        MengerSponge sponge = new MengerSponge( cvect, r0, colTable);
        sponge.Draw( 0,selDepth,anim, new PVector(1.0,1.0,1.0), 0.5f, blendV );
      }
      popMatrix();
      return maxDepth;
    }
    void draw()
    {
      beginCamera();
      PVector cpos = new PVector( mouseX-width*0.5,10+mouseY*0.6,34.0);
      camera(cpos.x,cpos.y,cpos.z,
        0.0,20.0,0.0,
        0.0,-1.0,0.0);
     
      perspective(45.0f, float(width)/float(height), 0.1f, 100.0f);      
      endCamera();
      float anim =(float)millis()/1000.0f;
      float fade = smoothstep(0.0f,2.0f, anim)*smoothstep(74.,68.,anim);
      background((int)(84.*fade),(int)(84.*fade),(int)(100.*fade));
      randomSeed(1200);  
     
      ambientLight(100,110,180);
      directionalLight(225*fade, 210*fade, 178*fade, 0.707f, -0.707f, 0.0f);
      directionalLight(64, 16, 0, 0.5f, -0.1f, 0.5f);
      
      anim-=1.0f;
      boolean useSponge = false;
      float animMany = 0.0f;
      if ( anim > 44.0f )
      {
        animMany = anim-44.0f;
        anim = animMany;
      }
      if ( anim > 22.0f)
      {
        anim -=22.0f;
        useSponge = true;
      }
      int maxDepth =0;
      if ( animMany == 0.0f)
      {
        maxDepth=drawFractal( cpos, 0.0f, 0.0f, anim, useSponge, useSponge ? binaryCol : growStart);
     
        float textAlpha = smoothstep(2.,6.,anim)*smoothstep(12.,8.,anim)*255;
        fill(255,255,255,textAlpha);
        textFont(g_font, 32);
        textMode(SCREEN);
        text(useSponge ? "Menger Sponge" : "Seirpenski Triangle",10 + (useSponge ? width/2. : 0), height-50 );
      }
     
      if ( animMany > 0.0f)
      {
        int tileSize = 12;
        float spacing = 80;
        int hts = tileSize/2;
        for (int i =0; i < tileSize; i++ )
          for (int j = 0; j < tileSize; j++)
            if ( i !=hts || j!= hts )
            {
              PVector [] cs = cols[(int)floor(random(0,2.9))];
              float px = (float)(i- hts)*spacing;
              float py = (float)(j- hts)*spacing;         
              drawFractal( cpos, px,py, animMany-random(0,10.0f), random(0,2)>1.0f, cs);
            }
      }
      //text("fps: "+(int)frameRate +" Depth : "+maxDepth ,10,40 );
    }
    
     
    
     
    PVector addCol( PVector ncol,float dcol, PVector modCol)
    {
      return new PVector( min(max( ncol.x + modCol.x*dcol,0.0f),1.0f),
      min(max( ncol.y + modCol.y*dcol,0.0f),1.0f),
      min(max( ncol.z + modCol.z*dcol,0.0f),1.0f));
    }
     
    int colIndices[] = new int[] {
      0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3,0,1,2,3
    };
    // MengerSponge  ----
    class MengerSponge
    {
      PVector[] m_pos;
      int     m_amt;
      PVector[] m_cols;
      PVector[] m_mesh;
      
      public MengerSponge( PVector camDir, float ang, PVector[] colTable )
      {
        float cx = cos(ang) * camDir.x - sin( ang) * camDir.z;
        float cz = cos(ang) * camDir.z + sin( ang) * camDir.x;
        int fci = cx < 0.0f ? 2 : 0;
        int fcj = camDir.y < 0.0f ? 2 : 0;
        int fck = cz < 0.0f ? 2 : 0;
     
        float fx = cx < 0.0f ? 0.5 : -0.5;
        float fy = camDir.y < 0.0f ? 0.5 : -0.5;
        float fz = cz < 0.0f ? 0.5 : -0.5;
     
        m_mesh = new PVector[12];
        // quad 0 facing z  // across in x
        m_mesh[0]= new PVector( -fx, -fy, fz);
        m_mesh[1]= new PVector(  fx, -fy, fz);
        m_mesh[2]= new PVector( fx, fy, fz);
        m_mesh[3]= new PVector( -fx, fy, fz);
        
        // quad 0 facing y
        m_mesh[4]= new PVector( -fx, fy, -fz);
        m_mesh[5]= new PVector(  fx, fy, -fz);
        m_mesh[6]= new PVector( fx, fy, fz);
        m_mesh[7]= new PVector( -fx, fy, fz);
        // quad 0 facing x
        m_mesh[8]= new PVector( fx, -fy, -fz);
        m_mesh[9]= new PVector(  fx, fy, -fz);
        m_mesh[10]= new PVector( fx, fy, fz);
        m_mesh[11]= new PVector( fx, -fy, fz);
    
        // create a packed list of ones to draw to save cpu later
        m_amt = 0;
        int cIdx = 0;
        m_pos = new PVector[27];
        m_cols = new PVector[27];
        for (int i =0; i < 3; i++)
          for (int j =0; j <3; j++ )
            for( int k= 0; k < 3; k++ )
            {
              boolean remove = ( i ==1 && k ==1 ) || ( j ==1 && k ==1 );
              remove = remove || ( j ==1 && i ==1 );
              // remove far corner ( big speed up)
              remove = remove || (j!= fcj && k!= fck && i != fci );
              if ( !remove )
              {
                PVector c0 = new PVector();  // chose colors depenant on direction
                PVector c1 = new PVector();
                PVector c2 = new PVector();
                c0.set(colTable[0]);
                c0.mult( ((float)j-1.f) );
                c1.set(colTable[1]);
                c1.mult( ((float)i-1.f) );
                c2.set(colTable[2]);
                c2.mult( ((float)k-1.f) );
                c0.add(c1);
                c0.add(c2);
                m_cols[m_amt]=  c0;
                m_pos[m_amt++]=new PVector(((float)i-1.f),((float)j-1.),(float)(k-1));
              }
              cIdx++;
            }    
      }
      void Draw( int depth, int maxDepth, float angle, PVector col, float dcol, float finalT)
      {
        if ( depth == maxDepth)
        {
           fill( color(col.x*255.,col.y*255., col.z*255.));
           beginShape( QUADS);
           for ( PVector p : m_mesh )
             vertex(p.x,p.y,p.z);
           endShape();
          return;
        }
        int cnt =0;
        if ( depth > 0  && angle>0.0f)
          rotateY(angle);
        float fs = depth == maxDepth -1 ? finalT : 1.;
        scale(1.0f/lerp(1.0f,3.0f,fs));
        dcol *= 0.5;
        int cIdx =0;
       
        for (int i =0; i < m_amt; i++)
        {
          pushMatrix();
          translate( m_pos[i].x*fs, m_pos[i].y*fs, m_pos[i].z*fs);
          Draw(depth+1, maxDepth, angle, addCol(col,dcol*fs, m_cols[i]), dcol, finalT);
          popMatrix();
        }
      }
    }
    // SeirpenskiTriangle ----
     
    PVector TriOffsets[] = new PVector[] {
      new PVector( -0.25f, 0.0f, -0.25f),
      new PVector( 0.0f, 0.5, 0.0f),
      new PVector( 0.0f,  0.0,  0.25f),
      new PVector( 0.25f, 0.0,  -0.25f),
    };
    void SeirpenskiTriangle( int depth, int maxDepth, float angle, PVector col, float dcol,
    PVector [] colTable, float finalT )
    {
      dcol = pow(dcol,1.5);
      if ( depth >2)
        rotateY(angle);
     
      if ( depth == maxDepth)
      {
        fill( color(col.x*255.,col.y*255., col.z*255.));
        beginShape( TRIANGLE_FAN);
        vertex(0.5f-0.5, 1.0f,0.5f-0.5);
        vertex(0.0f-0.5,0.0f,0.0f-0.5);
        vertex(0.5f-0.5, 0.0f, 1.0f-0.5);
        vertex(1.0f-0.5, 0.0f, 0.0f-0.5);
        vertex(0.0f-0.5,0.0f,0.0f-0.5);
        endShape();
        return;
      }
      float a =  ( depth == maxDepth-1) ? finalT : 1.0f;
      depth++;
     
      for(int i =0; i < 4; i++)
      {
        pushMatrix();
        PVector o = TriOffsets[i];
        translate(o.x*a,o.y*a,o.z*a);
        scale(1.0f - 0.5f*a);
        SeirpenskiTriangle( depth,maxDepth,angle, addCol(col,dcol*a, colTable[i]), dcol,colTable,finalT);
        popMatrix();
      }
    } 
    
     
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    edward Porten

    3D Fractals

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

    Performs animation on 3D recursive fractals. Uses distance based depth selection so many can be rendered at the same time.

    Chapeau bas monsieur!
    jacques maire
    17 Jun 2012
    Superbe!
    You need to login/register to comment.