Bernhard Häussner
Tags: Artikel mit dem Tag «CG» durchstöbern

3D-Tagcloud mit Processing

25.05.2009, 18:55

Ich habe ja schon etwas mathematisches und recht interaktives mit Processing gemacht. Jetzt wollte ich noch eine kleine Daten-Visualisierung basteln. Da ich wenig Lust habe tagelang irgendwelche tweets zu analysieren und ich mich nicht in die Musik-Librarys von Processing einarbeiten wollte, habe ich meine Blogeinträge und die dazugehörigen Tags als Datenset hergenommen, was auch noch eine recht überschaubare Datenmenge ist, und sie in einer Art 3D-Netz angeordnet. Video:


Zunächst einmal habe ich die Daten als .csv aus der Datenbank exportiert. Dieses Dateiformat ist zum Glück einfach mit Processing einzulesen. Daraus habe ich ein paar Objekte erstellt. Hier war ich mir ein bisschen unsicher, wie das zu realisieren sei. Im Endeffekt habe ich 3 Arrays von Objekten, einer enthält alle Tags, einer alle Blogeinträge und ein dritter alle Verbindungen. Zusätzlich bekommen alle Tags noch eine ArrayList mit ihren zugeordneten Blogeinträgen, um das aktivieren (röten) einfacher zu machen.

Dann haben die 3 Objekte (Eintrag, Tag, Verbindung) erstmal jeweils eine rendering-Methode bekommen. Die Einträge und Tags zeigen einfach ihr Label an, und beginnen auf einer Ebene mit (mehr oder weniger) zufälliger Position. die Verbindungen, die jeweils einen Pointer auf einen Eintrag und einen Tag speichern, rendern sich als Linie zwischen den Positionen der beiden. Zusätzlich habe ich noch eine Szene implementiert, die von der aktuellen Framezahl die Kameraposition und das aktivierte Tag bestimmt.

Eine rein zufällige Anordnung ist allerdings nicht wirklich zufriedenstellend. Deshalb beginnen nun die Tags als nächstes sich dem Schwerpunkt ihrer zugehörigen Blogeinträge zu nähern und die Blögeinträge nähern sich dem Schwerpunkt ihrer Tags. Aus Spaß habe ich das einmal laufen lassen, natürlich kollidiert das ganze recht zielstrebig. Als zweiter Bewegungsparameter kommt hinzu, dass, wenn ein gewisser Mindestabstand unterschritten wird, sich die Blogeinträge und Tabs auch gegenseitig abstoßen. Hier musste ich die Parameter recht fein abstimmen.

Damit nicht der Expansionscharakter die Überhand bekommt (wie bei unserem Universum?), habe ich auch noch eine Arena eingeführt: Wenn die Schriftposition aus einem Zylinder in der Mitte des Bildschirms heraus wandert, greift ein „Sheepdog“, der das Bewegungsverhalten überschreibt und die Tags bzw. Einträge zurück zum Mittelpunkt zieht, bis sie wieder im Rahmen sind. Da die Blogeinträge sowieso etwas unter Druck stehen, sorgt das dafür, dass alles schön zentriert bleibt und ein bisschen in ein Raster gepresst wird.

Je nach Anfangsposition funktioniert der Algorithmus mal besser und mal schlechter, vielleicht müsste ich noch etwas an den Parametern schrauben. Es ist auch schwer zu sagen, was gut und schlecht ist, aber hin und wieder gehen Tag-Eintrag-Verbindungen über den halben Zylinder („mangelnder Ellbogen-Einsatz“?) und bei manchen Durchläufen werden z.B. einige einfache Verbindungen recht schön kurz.

Das ganze lief mit dem P3D-Renderer eigentlich ganz ordentlich, doch dank diesem Tutorial zu Additive Blending mit OpenGL wird jetzt auch mit dem OpenGL-Renderer der Text ohne die weißen Flächen in den Buchstaben gerendert. Ich musste nur alles auf schwarz umstellen, was allerdings auch nicht schlecht aussieht. Jetzt läuft die Animation mit Kantenglättung (smooht() und P3D läuft bei mir sehr sehr langsam) weich wie Butter. Und so sieht alles in schwarz aus:

Mit einer netten Textur und frei drehbar im neuen Style:

Irgendwie interessiert mich als nächstes „Magnetismus“. Man liest recht viel darüber, mal sehen was genau man sich darunter vorzustellen hat.

Kommentare: keine

Malen mit Planetenpartikeln

23.05.2009, 19:35
„Processing Red“
„Processing Red“

Nachdem ich mit Processing nach erstaunlich kurzer Zeit einen kleinen Planeten, der um die Maus kreist, hin bekommen habe, der immer mit einer Kraft proportional zur Wurzel der Entfernung angezogen wird, dachte ich mir, dass man dieses Prinzip noch etwas ausbauen kann.

Zunächst hatte ich nur den einen Planeten, dann wurden es 10. Eigentlich habe ich ihnen nur eine „Spur“ verpassen wollen, doch dann habe ich beschlossen, den Bildschirm einfach nicht nach jedem Frame zu löschen (oder z.B. mit 20% weiß zu über pinseln, sodass die Partikel eine Spur hinterlassen) sondern die Partikel einfach weiter ohne löschen zu rendern, wodurch dann Linien entstehen.

Da die ganzen Planeten/Partikel dann schwierig zu kontrollieren waren, habe ich noch die Funktion hinzugefügt, dass sie vor der Maus fliehen, wenn ich die Maustaste drücke und dann ihr Gravitationsverhalten so geändert, dass sie einen Widerstand erfahren, ähnlich Luftreibung, und nicht direkt von der Maus angezogen werden, sondern auf einem Ring in einem kleinen Abstand bleiben, damit sie nicht irgendwann alle auf der Mausposition landen, denn dann ließen sie sich nicht mehr trennen. Das sah dann so aus:

„Processing Gravity“ einer der ersten Versuche
„Processing Gravity“ einer der ersten Versuche

Jetzt wurde es Zeit etwas mehr Komplexität hinzuzufügen. Also habe ich den Hauptpartikeln noch andere Partikel delegiert, die wiederum den Hauptpartikel mit ähnlichem Gravitationsverhalten folgen. Und diese wurden dann wieder von anderen Partikeln verfolgt usw. Zuletzt hatte ich 75 Partikel die sich auf unübersichtliche Weise gegenseitig verfolgen, aber im Endeffekt immer der Maus folgen.

Außerdem haben meine Partikel noch verschiedene Renderer zugeordnet bekommen. Die Hauptpartikel blieben große schwarze Punkte (allerdings habe ich die Transparenz erhöht), die Trabanten der Hauptpartikel wurden klein und schwarz und diese wurden wiederum von hellgrünen bzw. hellroten Partikeln verfolgt.

Diese farbigen Partikel werden dann noch von Spezialpartikeln verfolgt, die sich ihre letzte Position merken und dann eine Linie zu ihrer aktuellen Position zeichnen, sodass ganz feine Linien möglich sind.

Dann musste ich noch eine Geschwindigkeitsbegrenzung einführen. Denn sonst fliegen die Trabanten zweiter und dritter Ordnung nach kurzer Zeit so schnell, dass sie nicht nur den Bildschirm weit verlassen, sondern auch keine schönen Linien mehr zeichnen. Außerdem habe ich die Startpositionen von einer einfachen Aufreihung am Bildschirmrand zu einem Raster in der Mitte der Zeichenfläche geändert, sodass der Start nicht immer zu sehen ist. Dann konnte ich anfangen zu malen:

Interessant ist auch, dass manche Kreationen trotzt reinem 2D-Rendering einen räumlichen Eindruck hinterlassen.

Die Ästhetik wird entscheidend von der Mausführung des Künstlers geprägt.

Irgendwann wurde grün langweilig...

Ich weiß natürlich dass mancher ähnliche generative Algortihmen auch mit Musik steuert o.ä. aber mit Processing auch wirklich Daten (außer der Mausbewegung) zu visualisieren, damit beschäftigt sich mein nächster Blogpost (Der Algorithmus ist schon fertig, aber ich darf erst am Donnerstag wieder ein HD-Video zu vimeo hoch laden...).

Kommentare: keine

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.

Kommentare: keine

Wellen mit PHP rendern

30.04.2009, 19:52

Da ich heute mal wieder etwas Zeit zum Programmieren hatte (bzw. zum was-ich-will-Programmieren) habe ich unseren aktuellen Physik-Stoff visualisiert und zwar mit PHP und GD.

Ich habe ja schon vorher ein wenig mit SVG herumexperimentiert. Das war allerdings alles etwas krum und schief und ganz ohne Mathematik per Hand zusammengebastelt:


interference

Jetzt musste natürlich ein Algorithmus her. Eigentlich sind es nur 2 Klassen, die festlegen, wie eine Welle aussieht und was passiert, wenn sie von einem Zentrum ausgeht. Und zwar werden zyklische Wellenfronten von verschiedenen Zentren aus übereinandergelegt. Schwer zu erklären, einfacher im PHP-Code zu sehen:

class Wave {
  function __construct($length,$amplitude) {
    $this->length=$length;
    $this->amplitude=$amplitude;
  }
  function getPhaseAtLength($s) {
    $phase=($s%$this->length)/$this->length;
    $phaseWithDelta=fmod($phase+(isset($this->phase)?$this->phase:0)+1,2)-1;
    return $phaseWithDelta;
  }
  function getAmplitudeAtLength($s) { //sinuswelle
    $A=sin(deg2rad($this->getPhaseAtLength($s)*360))*$this->amplitude;
    return $A;
  }
  function setPhase($phase) {
    $this->phase=$phase;
    return $this;
  }
}

class Wavecenter {
  function __construct(Wave $wave,Point $center) {
    $this->wave=$wave;
    $this->center=$center;
  }
  function getAmplitudeAtPoint(Point $point) {
    $distance=$this->center->getDistance($point);
    $amp=$this->wave->getAmplitudeAtLength($distance);
    return $amp;
  }
}

Und mit ein bisschen anderem Code, der das ganze Visualisiert, entsteht dann sowas, wie die roten Wellen oben.

Das erste ist natürlich keine Sinuswelle: Am Anfang hat meine Point::getDistance() nicht funktioniert (^ statt pow()), so dass diese seltsame Figur entstanden ist. Interessant ist, dass man bereits zwei überlagerte Wellen sieht (daher die Symmetrie), diese jedoch seltsam deformiert sind.

Da ich gerade noch eine Phasenverschiebung dazu gezimmert habe, kann ich die Wellen auch noch animieren, also nicht nur in der Position des Mittelpunkts, sondern sie auch wandern lassen. Das sieht dann so aus:

Als kleinen Nachtrag noch ein paar Überlagerung einer Welle und anderen mit kleinerer Wellenlänge, wobei die Wellenlängen in (anfangs) kleinen ganzzahligen Verhältnissen stehen. Daher kann man sie auch recht leicht in der Musik finden. Die oberste Reihe wäre demnach das Schallbild, wenn man 1, 2, und 3 mal den selben Ton spielt, nur eben in der anderen Oktave. Das hört man normalerweise recht einfach, aber beim Sehen ist es etwas anders:

Jetzt wäre es natürlich irgendwie cool, auch einzelne Wellen irgendwie umher wandern zu lassen, um Doppler-Effekt und Reflexion etc. zu zeigen, aber da wären etwas kompliziertere Models nötig.

Nachtrag 26. Mai 2009: OpenGL

Da ich vor kurzem begonnen habe mit Processing Grafiken zu basteln, habe ich Processing auch gleich mal für das Wellen-Darstellen benutzt. Und das funktioniert sehr gut: Processing bietet die Grundlagen, sodass man leicht eine Welle, die von einem Zentrum ausgeht rendern kann. Das macht man dann z.B. mit 10 Frames, immer mit leichter Phasenverschiebung. Das könnte man dann einfach animieren. Wesentlich ansehnlicher ist es aber, wenn man die gerenderte Welle als animierte Textur in eine OpenGL-Szene mit additiver Überblendung einsetzt. Dann entstehen nämlich die oben gezeigten Bilder in realtime. Abgesehen vom anfänglichen Rendern und dem Laden in den Graphikspeicher der 10 2000x2000 Pixel Texturen. Screenshot:

Vor allem wenn man mehr Wellenzentren man hat, übernimmt OpenGL viele Berechnungen, weshalb man die Wellenzentren ohne Wartezeiten einfach mit der Maus verschieben kann.

Kommentare: keine

Fraktale klicken

27.03.2009, 14:22
DHML fun

DHML fun

Letzte Woche bin ich über I could not stop auf dhteumeuleu gestolpert, wo es auch noch ein paar andere nette Javascript (DHTML) Spielereien zu sehen gibt. Mir waren diese roten und schwarzen Kacheln des Originals etwas zu langweilig, und so habe ich beschlossen (da die Demo ja auch unter einer CC-Lizenz steht) mal ein paar andere Bilder aus zu testen, die lustige Muster ausspucken.

Zuerst hatte ich vor etwas ähnliches wie das hier zu basteln, doch das stellte sich als nicht zu einfach heraus, da die schrägen Linien beim Unterteilen nicht richtig aneinander passen. Darum habe ich zunächst einen Rand und ein paar vertikale und horizontale Streben eingebaut, die sich dann immer weiter unterteilen Lassen.

» Demo

Dann wollte ich etwas Farbe ins Spiel bringen und habe noch die bisher weißen Zwischenfelder mit (sehr) bunten Farbvariationen gefüllt. Das ergibt dann ein paar nette, mehr oder weniger zufällig angeordnete Farbkacheln.

» Demo

Wenn sich das Ganze mit Farbe abspielt, kann man die inneren Verzweigungen eigentlich auch weg lassen. Das Ergebnis sind noch buntere Bilder. Leider hat man kaum noch Kontrolle über die Farbkomposition.

» Demo

Am Ende habe ich dann noch, nur um zu sehen, wie sich Schrägen machen, ein weiteres Derivat erstellt. Diesmal sind die Quadrate in zwei Dreiecke unterteilt und unterteilen sich bei Mausklick noch weiter. Im Endeffekt entsteht ein total zufälliger Mix aus Dreieckflächen, der ein wenig an Tangram erinnert.

» Demo

Die Muster sind dann so etwas wie teils zufällige, teils interaktiv gestaltete Fraktale.

Kommentare: 4 Einträge
 
Χρόνογραφ
© 2008-2012 by Bernhard Häussner - Impressum - Login
Kurz-Link zur Homepage: http://1.co.de/