Willkommen auf unserem Seminar-Blog

Immer auf dem aktuellen Stand bleiben

Dieser Seminar-Blog befindet sich noch im Aufbau und wird in den kommenden Tagen entsprechend verfeinert.

Member Login

Lost your password?

Registration is closed

Sorry, you are not allowed to register by yourself on this site!

You must either be invited by one of our team member or request an invitation by email at viad.info {at} zhdk {dot} ch.

Magic Wood

20. September 2013

Nach langem herumprobieren gelang es mir einen Wald zu generieren, welcher einerseits mehrere Reihen Bäume zeichnet, die hinteren dabei immer mehr im 'Dunst des Waldes' verschwinden lässt und dazwischen spriessen zudem kleine Büsche, welche so was wie Kirschblüten tragen. pic Weiteres zum Wald-Applet: Als erstes muss ich sagen, dass ich die Baum-Klasse und die Blüten-Klasse im Netz auf openprocessing heruntergeladen habe. Dabei wird jede Instanz der beiden Pflanzen leicht anders generiert – Farbe, Grösse, Neigung und Verästelung variiert ständig. Ich habe dabei nur einige Anpassungen vorgenommen und diese Pflanzen zu einem Wald 'zusammengefügt'. Eine unscharfe Ellipse sollte eigentlich den Waldboden bedecken. Um diese Ellipse allein verschwimmen zu lassen, war es nötig auf die PGraphics Klasse zurückzugreifen. Dies habe ich auch getan, jedoch wird das Aufbauen des Java-Applets dann viel mehr Zeit benötigt und zudem sieht's auch noch mies aus. Der Code ist aber auskommentiert noch unter draw() zu finden. Ebenfalls zu erwähnen ist vielleicht, dass am Anfang des Codes einige Parameter anders gesetzt werden können:
int amountOfTrees = 140; //change to get a smaller or bigger forest
int treesPerRow = 30; //decrease results in narrower forest
int amountOfBlossoms = 50; //same for the blossom-bushes
float pointOfView = 1.3; //Values between 1 and 2, the higher the number the closer you are to the forest
Die jetzigen Einstellungen generieren jedoch einen mehr oder weniger 'schönen' Wald, soweit das mit diesem Code überhaupt möglich ist. Und hier schliesslich der Code: Der Code der Klassen ist am Ende zu finden.
Branch[] myTrees; //define global Array, where later to create istances of Branches, here called myTrees.
Blossom[] myBlossoms;


PGraphics pg; //initiate PGraphics
float ang; 
color col;
color blossomcol;
int amountOfTrees = 140; //change to get a smaller or bigger forest
int treesPerRow = 30;  //decrease results in narrower forest
int amountOfBlossoms = 50;  //same for the blossom-bushes
int blossomsPerRow = 5;  //dito
 int rowcount = 0;
float pointOfView = 1.3; //Values between 1 and 2, the higher the number the closer you are to the forest


void setup() {
  noLoop(); 
  noStroke();
  smooth();  
  size(1200, 600); 
  background(240);
  pg = createGraphics(width, 500); //create PGraphics canvas with (canvaswidth, canvasheight);
  generateTrees(amountOfTrees); //function generate trees is called, to make several instances of Trees, Parameter = amountOfTrees
}

void draw() {
  scale(pointOfView); //scale whole scenery to simulate another viewpoint
  float yDisplacement = map(pointOfView, 1, 2, -40, -250);
  float xDisplacement = map(pointOfView, 1, 2, 0, -120);
  translate(xDisplacement, yDisplacement);
//too slow and ugly; there uncommented
//  pg.beginDraw();
//  pg.fill(0);
//  pg.ellipse(380, 120, 600, 90);
//  pg.filter(BLUR, 25);  
//  pg.endDraw();
//  image(pg, 40, 0.55*height);

  //  background(240);
  int blossomLoop = 0;
  for (int i = 1; i < myTrees.length; i++) {
    myTrees[i].paint();
    if (i > 100 ) {
      myBlossoms[blossomLoop].render();
      blossomLoop++;
    }

    if ((i % treesPerRow) == 0 && i != 0) { //check if i is a multiple of treesPerRow
      fill(240, 240, 240, 50); 
      rect(0, 0, width, height); //add half transparent rectangle to fade the tree rows at the back.
      fill(0, 0, 0, 50);
      translate(-10, 5);
      scale(1.1);
      //      println("You are my master");
    }
  }
}

void mousePressed() {
  save("pic.jpg");
  //  ang = random(HALF_PI - PI/30,HALF_PI + PI/30);  
  //  root1 = new Branch(new PVector(0.5*width,0.92*height,0),70,20,ang,col);
  //  redraw();
}

void generateTrees(int amountOfTrees) {

  myBlossoms = new Blossom[amountOfBlossoms]; 
  myTrees = new Branch[amountOfTrees]; //Number is the amount of tree pushed in the array.

  for (int i = 0; i < amountOfTrees; i++) { //generate all the Tree instances and push into Array
    rowcount += 1;

    if (rowcount == treesPerRow) {
      println(rowcount);
      rowcount = 0; // reset rowcount, to start new row
    }

    ang = random(HALF_PI - PI/30, HALF_PI + PI/30);  
    col = color(random(100, 140), random(60, 90), random(10, 30)); // make new random colors for each tree instance
    myTrees[i] = new Branch(new PVector(180+(rowcount*(random(10, 15))), 0.55*height+random(-10, 10), 0), 35, 4, ang, col);
  }

  for (int i = 0; i < amountOfBlossoms; i++) { //generate all the Blossom instances and push into Array
    rowcount += 1;
    if (rowcount == blossomsPerRow) {
      rowcount = 0; // reset rowcount, to start new row
    }

    myBlossoms[i] = new Blossom(random(150, 500), 0.53*height+random(-10, 30), random(40, 90), 10); // (X-pos, height(?), ~size(?), branches(?))
  }


  //  println(myTrees); //print Array
}

--------------------------- Slider_Wood_Jones Stunden danach: Geplant war, dass man sich dem Wald nähern kann. Also habe ich je nachdem, welchen Faktor man zu Beginn eingibt die Position des Betrachters verändert. Mal ist man näher am Wald, mal nicht. Um das ganze nun direkt im Applet zu verstellen, habe ich die controlP5-Klasse heruntergeladen, welche verschiedene Controller zur Verfügung stellt. Den Slider konnte ich dann zwar einfügen, jedoch zeigte er keinerlei Wirkung auf mein Interagieren. Nach langem Probieren und Kopfzerbrechen dann die erste Einsicht. mit noLopp() wird es schwierig eine Reaktion auf dem Bildschirm zu sehen. Also raus damit (was auch wieder einige Probleme mit dem Wald mit sich trug, was jedoch zu beheben war). Trotzdem funktionierte der Slider noch immer nicht. Lesen in den References von controlP5, herunterladen von Beispielen auf openprocessing, Analyse derer, wieder lesen – trotz allem wollte es nicht klappen. Irgendwann kam ich der Sache dann auf die Spur. In meinem inzwischen doch recht unübersichtlichen Code hat es sehr viele Koordinatensystem Verschiebungen und Skalierungen. Diese scheinen den Controller in seiner Funktion zu stören. Keine Ahnung weshalb. Der Slider ist zwar nun verstellbar, das ganze funktioniert aber nur mit einer tiefen frame rate und der Slider skaliert sich selber immer wieder. Naja, keine Zeit mehr, um dies zu beheben. Das nächste Mal von Beginn sauberer Code schreiben! Mein Verdacht ist eben, dass es von Vorteil wäre, wenn ich bei jedem Verstellen des Koordinatensystems auch wieder zurück zum Ursprung ginge, damit ich mir unter den Koordinaten etwas vorstellen kann. Sonst ist eine genaue Eingabe nicht mehr möglich. Hier noch der Code. Funktioniert wie gesagt nur beschränkt...
import controlP5.*;    // import controlP5 library
ControlP5 controlP5;   // global controlP5 object

Branch[] myTrees; //define global Array, which later containes istances of Branches, here called myTrees.
Blossom[] myBlossoms;


PGraphics pg; //initiate PGraphics
float ang; 
color col;
color blossomcol;
int amountOfTrees = 140; //change to get a smaller or bigger forest
int treesPerRow = 30;
int amountOfBlossoms = 50;
int blossomsPerRow = 5;
int rowcount = 0;
float pointOfView = 1.3; //Values between 1 and 2, the higher the number the closer you are to the forest
float Distance = 1;

void setup() {
//  noLoop(); 
  noStroke();
  smooth();  
  size(1200, 600); 
  background(240);
  pg = createGraphics(width, 500); //create PGraphics canvas with (canvaswidth, canvasheight);
  generateTrees(amountOfTrees); //function generate trees is called, to make several instances of Trees, Parameter = amountOfTrees
  controlP5 = new ControlP5(this);
  controlP5.addSlider(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;Distance&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;)
    .setPosition(300, 100)
    .setRange(1,2)
    ;
}

void draw() {
  pushMatrix();
  scale(pointOfView); //scale whole scenery to simulate another viewpoint
  float yDisplacement = map(pointOfView, 1, 2, -40, -250);
  float xDisplacement = map(pointOfView, 1, 2, 0, -120);
  translate(xDisplacement, yDisplacement);
  popMatrix();
  background(240);
  
//too slow and ugly; therefor uncommented
//  pg.beginDraw();
//  pg.fill(0);
//  pg.ellipse(380, 120, 600, 90);
//  pg.filter(BLUR, 25);  
//  pg.endDraw();
//  image(pg, 40, 0.55*height);
  int blossomLoop = 0;
  pushMatrix();
  for (int i = 1; i &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; myTrees.length; i++) {
    myTrees[i].paint();
    if (i &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; 100 ) { // as soon as 100 trees are planted, the blossoms start to shoot...
      myBlossoms[blossomLoop].render();
      blossomLoop++; //just a count, here without effect, cause I did not implement the 'blossomsPerRow'.
    }

    if ((i % treesPerRow) == 0 &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; i != 0) { //check if i is a multiple of treesPerRow
      fill(240, 240, 240, 50); 
//      rect(0, 0, width, height); //add half transparent rectangle to fade the tree rows at the back.
      fill(0, 0, 0, 50);
      translate(-10, 5);
      scale(1.1);
      // println(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;You are my master&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;);
    }
  }
  popMatrix();
  
}

void mousePressed() {
//  save(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;pic.jpg&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;);
  //  ang = random(HALF_PI - PI/30,HALF_PI + PI/30);  
  //  root1 = new Branch(new PVector(0.5*width,0.92*height,0),70,20,ang,col);
  scale(Distance);
  redraw();
}

void generateTrees(int amountOfTrees) {

  myBlossoms = new Blossom[amountOfBlossoms]; 
  myTrees = new Branch[amountOfTrees]; //Number is the amount of tree pushed in the array.
  
  for (int i = 0; i &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; amountOfBlossoms; i++) { //generate all the Blossom instances and push into Array
    rowcount += 1;
    if (rowcount == blossomsPerRow) {
      rowcount = 0; // reset rowcount, to start new row
    }

    myBlossoms[i] = new Blossom(random(150, 500), 0.57*height+random(-10, 10), random(60, 70), 5); // (X-pos, height(?), ~size(?), branches(?))
  }


  for (int i = 0; i &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;lt; amountOfTrees; i++) { //generate all the Tree instances and push into Array
    rowcount += 1;

    if (rowcount == treesPerRow) {
      println(rowcount);
      rowcount = 0; // reset rowcount, to start new row
    }

    ang = random(HALF_PI - PI/30, HALF_PI + PI/30);  
    col = color(random(100, 140), random(60, 90), random(10, 30)); // make new random colors for each tree instance
    myTrees[i] = new Branch(new PVector(180+(rowcount*(random(10, 15))), 0.55*height+random(-10, 10), 0), 35, 4, ang, col);
  }

  
}

void controlEvent(ControlEvent theEvent) {  // listener for all the user elements -&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;gt; check if slider is used
  /* events triggered by controllers are automatically forwarded to 
     the controlEvent method. by checking the name of a controller one can 
     distinguish which of the controllers has been changed.
  */ 
 
  /* check if the event is from a controller otherwise you'll get an error
     when clicking other interface elements like Radiobutton that don't support
     the controller() methods
  */
  if(theEvent.isController()) { 
    
    print(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;control event from : &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;+theEvent.controller().name());
    println(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;, HEHEvalue : &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;+theEvent.controller().value());
    
    if(theEvent.controller().name()==&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;slider2&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;) {
      println(&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;Hey You controller&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;);
    }
    
  }
}

Und hier die Klassen: Blossom-Class
class Blossom {
  float x, y;
  float h;
  float steps;
  
  Blossom() {
    x = 0;
    y = 0;
    h = 0;
    steps = 0;
  }
  
  Blossom(float x_, float y_, float h_, float s_) {
    x = x_;
    y = y_;
    h = map(h_, 0, height, 0, 160);
    steps = s_;
  }
  
  void render() {
//    stroke(32);
    branch(x, y, -HALF_PI, h);
  }
  
  void branch(float x_, float y_, float a_, float s_) {
    strokeWeight(s_/32);
    float a = random(-PI/16, PI/16)+a_;
    float nx = cos(a)*s_+x_;
    float ny = sin(a)*s_+y_;
    stroke(40, 16*s_);
    line(x_, y_, nx, ny);
    if (s_&amp;amp;amp;amp;amp;amp;gt;10) {
      branch(nx, ny, a_-random(PI/4), s_*random(0.6, 0.8));
      branch(nx, ny, a_, s_*random(0.6, 0.8));
      branch(nx, ny, a_+random(PI/4), s_*random(0.6, 0.8));
    } else {
      float w = random(155, 255);
      stroke(255, w, w, random(90, 192));
      strokeWeight(random(0, 8));
      point(nx+random(-2, 2), ny+random(-2, 2));
      noStroke(); //stroke wieder entfernen
    }
  }
}
und die Baum-Klasse

class Branch {
  PVector pos;
  float branchSize, diam, ang;
  color col;

  Branch extremeBranch, middleBranch;
  PVector extreme, middle;
  float branchSizeExtreme, branchSizeMiddle;
  float diamExtreme, diamMiddle;
  float angExtreme, angMiddle;
  color colSon;
  boolean withExtreme = false;
  boolean withMiddle = false;
  float sign, diamTop;
  
  Branch(PVector posTemp, float branchSizeTemp, float diamTemp, float angTemp, color colTemp) {
    pos = posTemp.get();
    branchSize = branchSizeTemp;
    diam = diamTemp;
    ang = angTemp;
    col = colTemp;
    
    if(branchSize &amp;amp;amp;amp;amp;amp;gt; 30){
      colSon = color(red(col)*1.04,green(col)*1.02,blue(col)*1.01);
    }
    else{
      colSon = color(red(col)*0.8,green(col),blue(col)*0.9);
    }
    
    if((branchSize &amp;amp;amp;amp;amp;amp;gt; 8) &amp;amp;amp;amp;amp;amp;amp;amp; (random(0,1) &amp;amp;amp;amp;amp;amp;lt; 0.9)){
      withExtreme = true;
      if(branchSize &amp;amp;amp;amp;amp;amp;gt; 30){
        branchSizeExtreme = random(0.85,0.95)*branchSize;
        diamExtreme = random(0.75,0.85)*diam;
        angExtreme = ang + random(-PI/7,PI/7);
        if(angExtreme &amp;amp;amp;amp;amp;amp;gt; PI - 0.1*PI){
          angExtreme = angExtreme - random(PI*0.15,PI*0.3);
        }
        if(angExtreme &amp;amp;amp;amp;amp;amp;lt; 0.1*PI){
          angExtreme = angExtreme + random(PI*0.15,PI*0.3);
        }
      }
      else{
        branchSizeExtreme = random(0.75,0.85)*branchSize;
        diamExtreme = 0.65*diam;
        angExtreme = ang + random(-PI/4,PI/4);
      }
      extreme = PVector.add(pos,new PVector(branchSize*cos(ang),-branchSize*sin(ang),0));
      extremeBranch = new Branch(extreme,branchSizeExtreme,diamExtreme,angExtreme,colSon);
    }

    if((branchSize &amp;amp;amp;amp;amp;amp;gt; 8) &amp;amp;amp;amp;amp;amp;amp;amp; (random(0,1) &amp;amp;amp;amp;amp;amp;lt; 40/branchSize) &amp;amp;amp;amp;amp;amp;amp;amp; (random(0,1) &amp;amp;amp;amp;amp;amp;lt; 0.9)){
      withMiddle = true;
      if(branchSize &amp;amp;amp;amp;amp;amp;gt; 30){
        branchSizeMiddle = random(0.85,0.95)*branchSize;
        diamMiddle = random(0.75,0.85)*diam;
        sign = random(-1,1);
        sign = sign/abs(sign);
        angMiddle = ang + sign*random(PI/8,PI/5);
      }
      else{
        branchSizeMiddle = random(0.75,0.9)*branchSize;
        diamMiddle = random(0.65,0.75)*diam;
        sign = random(-1,1);
        sign = sign/abs(sign);
        angMiddle = ang + sign*random(PI/9,PI/4);
      }
      float frac = random(0.6,0.9);
      middle = PVector.add(pos,new PVector(frac*branchSize*cos(ang),-frac*branchSize*sin(ang),0));
      middleBranch = new Branch(middle,branchSizeMiddle,diamMiddle,angMiddle,colSon);
    }
  }
  
  void paint() {
    fill(col);
    if(withExtreme){
      diamTop = diamExtreme;
    }
    else if(withMiddle){
      diamTop = diamMiddle;
    }
    else{
      diamTop = diam*0.5;
    }
    pushMatrix();
      translate(pos.x,pos.y);
      rotate(HALF_PI- ang);
      beginShape();
        vertex(-diam/2,0);
        vertex(-diamTop/2,-1.05*branchSize);
        vertex(diamTop/2,-1.05*branchSize);
        vertex(diam/2,0);
      endShape();
    popMatrix();
    if(withExtreme){
      extremeBranch.paint();
    }
    if(withMiddle){
      middleBranch.paint();
    }
  }
  
}