Bernhard Häussner

Processing: 3D-Koch-Kurve mit Sierpinski-Dreieck

23.05.2009, 17:34

Nachdem ich mich jetzt mal an Processing heran gewagt habe, habe ich auch gleich mal einen fraktalen Körper basteln müssen. Es handelt sich um eine Art dreidimensionale Koch-Schneeflocke.

Die Koch-Schneeflocke an sich ist eigentlich recht simpel, habe ich schon in Logo und PHP implementiert. Es wird eine Linie jeweils durch eine Linie mit einem Dreieck darin ersetzt. Auf den Raum übertragen heißt das dann eine Dreieckfläche bekommt einen Tetraeder eingesetzt. Dies wird dann mit den Flächen des Tetraeders rekursiv wiederholt, sodass dann ungefähr so etwas entsteht:

Es entsteht eigentlich eine etwas andere Form, die allerdings nicht sehr interessant anzusehen ist, nämlich ein Tetraeder, der in viele kleine Tetraeder zerlegt ist. Damit der strenge Tetraeder etwas aufgelockert wird, habe ich die neuen Tetraeder immer um 70% skaliert. Es sind also keine Tetraeder mehr, sondern, je tiefer die Rekursion geht, immer schiefere Pyramiden.

Außerdem habe ich nicht mit nur einem Dreieck begonnen, sondern mit einem Tetraeder, sodass ein Körper ensteht, ähnlich wie wenn man in 2D mit dem Dreieck beginnt. Bei 6 Rekursionsschritten ergeben sich dann 66*4 = 186 624 Dreiecke. Die werden dann von Processing z.B. mit 7%iger Transparenz gerendert, damit es etwas schöner aussieht und so kann dann dieses Video entstehen:


Interessant ist eigentlich auch, dass der Rest, der vom ursprünglichen Dreieck bleibt, wenn man die ganzen Tetraeder heraus nimmt, genau dem Sierpinski-Dreieck entspricht. So sieht der Code aus:

fraqTriang trs[]=new fraqTriang[4];

void setup(){
  size(640, 480, P3D);
  noStroke();
  fill(150,150,150,20);
  int bigrad=200;
  int req=6;
  
  PVector A=new PVector(-bigrad,0,0);
  PVector B=new PVector(bigrad/2,0,-173.21);
  PVector C=new PVector(bigrad/2,0,173.21);
  PVector D=new PVector(0,-bigrad*(sqrt(6)/3),0);
  
  trs[0]=new fraqTriang(A,B,C,req);
  trs[1]=new fraqTriang(A,D,B,req);
  trs[2]=new fraqTriang(A,C,D,req);
  trs[3]=new fraqTriang(B,D,C,req);
}


void draw(){
  background(255);
  lights();
  
  float winkel=(mouseX/float(width))*TWO_PI;
  float xpos=cos(winkel);
  float ypos=sin(winkel);
  float radius=300.000;
  camera(xpos*radius, mouseY, ypos*radius, // eyeX, eyeY, eyeZ
         0.0, -50.0, 0.0, // centerX, centerY, centerZ
         0.0, -1.0, 0.0); // upX, upY, upZ
      
  for (int i=0;i<trs.length;i++) {
    trs[i].display();
  }
  //saveFrame("frames/koch3d-####.png"); //uncomment to record
}

class fraqTriang{
  PVector PointA;
  PVector PointB;
  PVector PointC;
  fraqTriang recTris[]=new fraqTriang[6];
  int rec;
  float scaling;
  
  fraqTriang(PVector A,PVector B,PVector C, int recursion){
    scaling=0.7;
    PointA=A;
    PointB=B;
    PointC=C;
    rec=recursion;
    applyRecursion ();
  }
    
  void applyRecursion () {
    if (rec!=0) {
      PVector PointAB2=PVector.add(PointA,PointB);
      PointAB2.div(2);
      PVector PointAC2=PVector.add(PointA,PointC);
      PointAC2.div(2);
      PVector PointBC2=PVector.add(PointB,PointC);
      PointBC2.div(2);
      
      PVector PointZ=PVector.add(PointA,PointB);
      PointZ.add(PointC);
      PointZ.div(3);
      PVector PointAB=PVector.sub(PointA,PointB);
      PVector PointAC=PVector.sub(PointA,PointC);
      PVector PointH=PointAB.cross(PointAC);
      PointH.normalize();
      PVector PointAAB2=PVector.sub(PointA,PointAB2);
      float a=PointAAB2.mag();
      float pheight=a*(sqrt(6)/3)*scaling;
      PointH.mult(-pheight);
      PVector PointZH=PVector.add(PointZ,PointH);
      
      recTris[0]=new fraqTriang(PointA,PointAB2,PointAC2,rec-1);
      recTris[1]=new fraqTriang(PointB,PointBC2,PointAB2,rec-1);
      recTris[2]=new fraqTriang(PointC,PointAC2,PointBC2,rec-1);
      
      recTris[3]=new fraqTriang(PointZH,PointAC2,PointAB2,rec-1);
      recTris[4]=new fraqTriang(PointZH,PointAB2,PointBC2,rec-1);
      recTris[5]=new fraqTriang(PointZH,PointBC2,PointAC2,rec-1);
    }
  }  
  
  void display () {
    if (rec==0) {
      beginShape();
      vertex(PointA.x, PointA.y ,PointA.z);
      vertex(PointB.x, PointB.y ,PointB.z);
      vertex(PointC.x, PointC.y ,PointC.z);
      endShape(CLOSE);
    } else {
      for (int i=0; i<recTris.length;i++) {
        recTris[i].display();
      }
    }
  }
  
}

Man sieht dem Code an, wie schnell man mit Processing Graphiken erstellen kann, ohne sich mit komplizierteren APIs herumzuschlagen. Durch die vielen Beispiele, die Processing beiliegen und die übersichtliche API-Dokumentation kann man innerhalb von kurzer Zeit schon recht hübsche Ergebnisse erzielen. Viel Synatax muss man auch nicht lernen, da die Processing-Synatx mehr oder weniger der von Java entspricht.

Kurze URL http://1-co.de/b/13. Post to twitter

Kommentare

keine





 
Χρόνογραφ
© 2008-2017 by Bernhard Häussner - Impressum - Login
Kurz-Link zu dieser Seite: http://1-co.de/b/13