Bernhard Häussner
Journal: Neueste Artikel erscheinen hier (Seite 12 von 23)

Processing und Blender

17.06.2009, 20:25

Processing ist gut geeignet um Daten und Berechnungen zu visualisieren, Blender übernimmt dafür mehr Material- und Rendering-Aufgaben. Dennoch gibt es Bereiche, in denen sich die Verwendungszwecke überschneiden, zum Beispiel die hier gezeigten Formen.

Das Bild oben ist eine runde zweifache Spirale - Auf der innersten Ebene jeweils zwei gestreckte und zu Spiralen verdrehte Kreise und Quadrate, deren Dehnprodukt sich dann spiralförmig schraubend um einen Kreis windet. Zwar kann Blender auch mit Python gescriptet werden, das habe ich mir aber bisher noch nicht angeschaut, weshalb alles eher in „Handarbeit“ entstanden ist. Die Farben habe ich nachträglich noch ein bisschen mit GIMP verändert. Das ist ein Rendering in Original-Farben und mit einer etwas angehobenen Ebene:

Wenn sich diese Doppelspiralkreise dann wiederum um einen Kreis legen, entsteht das:

Mit Processing geht dieses verdoppeln und drehen alles viel Einfacher. Hier mal ein Bild aus einem nicht wirklich fertigem Projekt:

Es ist ein Versuch eine Art Haarbüschel nach gewissen Expansionsregeln zu erstellen. Die „Haare“ können in der Sketch interaktiv nach oben und unten gebogen werden, was ein recht lustiges Bild ergibt. Vielleicht hier nochmal ein Bild mit besserem Überblick und anderer rendering-Methode:

Ich habe mich auch schon in Processing etwas mit Spiralen auseinandergesetzt, ist aber leider nicht in 3D, aber dank farblicher Überarbeitung doch noch recht interessant geworden:

spiral
spiral

Die Bildungsvorschrift ist übrigens eine Linie von einem Punkt aus im rechten Winkel zum Ursprung bis zu einem bestimmten Winkel und das sehr oft wiederholt. Der Sourcecode beschränkt sich auf wenige Zeilen:

// Initialisieren
size (1800,1100);
smooth();
background(255);
// Setzt den Ursprung des Koordinatensystems auf die Mitte
translate(width/2,height/2);

// 20 Spiralen
for (int k=0; k<20; k++) {
  // Weiterdrehung pro Spiralsegment
  float rotateStep=PI/11.465;
  // Anzahl der Spiralsegmente
  int rotateAnz=200;
  // Startposition
  float len=k; // wird ei jeder Spirale leicht vaiiert
  // Startposition 2
  float prelen=cos(rotateStep)*len;
  
  // Die Spiralensegmente erstellen
  for (int i=0; i<rotateAnz; i++) {
    // für jedes Segment ein Stück weiter drehen
    rotate(rotateStep);
    // Entfernung des Endes des letzten Segments zum Ursrung
    // Verwendet als Entfernung des Anfangs des aktuellen Segments zum U.
    len=prelen/cos(rotateStep);
    // eine Linie vom Ursprung zum Anfang des Segments
    stroke(0,40);
    line(0,0,len,0);
    /* Damit das letzte, nicht abgeschlossene Segment 
     * nicht so hässlich aus der Spirale hängt */
    if (i!=rotateAnz-1) { 
      // Eine Linie vom Anfang zum Ende des Segments
      // Das wird die Spirale
      stroke(0,200);
      line(len,0,len,len*tan(rotateStep));
    }
    prelen=len;
  }
}

Mit den Kommentaren ist es doch ganz ordentlich länger geworden. Vom rechten Winkel sind übrigens nurnoch die Trigonometrischen Funktionen cos und tan übrig: Die Strecke Ursprung-Segmentbeginn ist die Hypotenuse des Segments und wird die (zu unserem Schritt-Rotationswinkel) Ankathede des nächsten.

Kommentare: 2 Einträge

Ein paar Code-Schnipsel

15.06.2009, 19:30
Javascript

Javascript

In diesem Post nur ein paar kleine Code-Auszüge und Techniken für Webanwendungen. Inhalt:

  • Data URI scheme für Favicons & CSS-Farbverläufe
  • HTML-Attribut contenteditable zum einfachen Editieren
  • Javascript: Globale Variablen einfach vermeiden
  • JSON in Script-Tags
  • JSON-Parser bei Bedarf laden
  • jQuery nach hinten verlegen
  • jQuery mouserest-Plugin

Data URI scheme für Favicons & CSS-Farbverläufe

Eine mir bisher unbekannte Funkion moderner Browser (ab IE8) sind data: URLs. Anders als normale http:// oder file:// URLs repräsentieren sie keinen Link, sondern die Daten sind komplett in der URL enthalten. Damit man auch Binärdaten verwenden kann (oder sich das escapen von HTML-Tags, „"“ etc. sparen), ist es möglich optional mit Base64 zu encodieren. Für ein Favicon sieht das dann so aus:

<link rel="shortcut icon" href="data:image/png;base64,iVBORw[...]RK5CYII="/>

Und für eine Graphik im CSS:

body {background:url(data:image/png;base64,iVBORw[...]ElFTkSuQmCC);}

Das lohnt sich bei kleinen Farbverläufen oder Symbolen, da ein zusätzliches Request zum Server mehr Bytes brauchen würde, als die Base64-Codierung produziert. Da bei base64 jeweils 3 Bytes zu 4 werden, sieht die Rechnung für die maximale PNG-Größe so aus:

PNG*(4/3) + 55 B = HTTP-HADER
mit HTTP-HADER:=600B PNG=1635 B

Da man im CSS mittels Sprites sowieso Requests sparen kann und durch Kombination größere PNGs bekommt, lohnt es sich hier also nur bei kleinen Projekten. (Oder bei riesigen Cookies, was die Request-Größe in die Höhe treibt. Da würde ich dann aber eine static-Subdomaine empfehlen. )

Als weiteren Vorteil kann man eine ganze Seite in eine HTML-Datei packen, jedoch kann man auch die Bilder nicht mehr so leicht bearbeiten.

HTML-Attribut contenteditable zum einfachen Editieren

Auch ein spaßiges Feature sind editierbare HTML-Elemente. Man kann das HTML-Attribut contenteditable für einzelne HTML-Elemente setzten oder gleich für die ganze Seite:

<body contenteditable="true">

Das Attribut ist zwar erst mit HTML5 valid, wird aber schon von einigen älteren Browsern unterstützt.

Javascript: Globale Variablen einfach vermeiden

Mit wachsender Zahl an Javascript-Bibliotheken wird die Wahrscheinlichkeit der Kollision globaler Variablen immer größer. Zwar ist es unwahrscheinlich, dass man z.B. $ überschreibt, aber manche Javascript Frameworks haben sich ja sogar zueignen gemacht, die Prototypen der Sprachfunktionen zu erweitern, was natürlich beim Einsatz eigener/anderer Prototypen-Erweiterungen nicht-überschaubare Probleme erzeugen kann. Das lässt sich aber vermeiden, indem man eine Art jQuery für andere Aufgaben erzeugt. Dazu kann man z.B. die ersten ~50 Zeilen von jQuery grob kopieren1, einen eigenen Framework-Namen einsetzen und dann eigene Funkionen einbauen, was man dann z.B. so verwenden kann:

var foo=Array(1,2,3,4);
alert(myFW(foo).contains(4));

Hier benutzt man dass die Funktion myFW einen Weiteren Konstruktor aus sich selbst aufrufen kann.

Es gilt zusätzlich globale Variablen zu vermeiden. Doch man kann für einzelne Komponenten Kürzel als Arrays verwenden, die dann die Globalen speichern. So kann man auch im DOM-Explorer von Firebug einen Überblick über globale Variablen behalten und die Komponenten können kommunizieren.

1 Ich vermute, wer den ganzen jQuery-Code aufmerksam gelesen hat, kann mehr als man in allen Javascript Büchern zusammen lernt.

Um den Speicherbedarf nicht unnötig in die Höhe zu treiben kann man die Variablen-Sichtbarkeit immer recht klein halten, damit die GC die Daten wieder fressen kann, wenn sie nicht mehr gebraucht werden. In JS sind übrigens auch Funktionen nicht global und löschbar. Funktionen, die nur beim Initialisieren gebraucht werden, kann man also mit delete funktionsName; wieder aus dem Speicher nehmen.

Ähnlich der main()-Funktion in anderen Programmiersprachen kann man in Javascript den Code zusätzlich in eine gleich aufgerufene, anonyme Funktion hüllen:

(function(){
  var nichtglobal;
  // code
})();

So kann man ganz normal „globale“ Variablen und Funktionen verwenden, aber ein anderes Script bemerkt davon nichts.

JSON in Script-Tags

Wenn man für Javascript Daten übertragen will, dann bietet sich JSON an, da es einfach Daten austauschen kann und in vielen Programmiersprachen implementiert ist. Da gibt es die eine Methode, JSONP, welche die Daten in einer Variable speichert, bzw. an ein Callback übergibt. Alternativ kann man auch die Daten in <script type="text/x-json" id="dafaultData">-Tags im DOM platzieren und dann mit Javascript auslesen und parsen

JSON-Parser bei Bedarf laden

Da moderne Browser jetzt native JSON-Parser bekommen, muss man den JSON-Parser nicht immer laden. Das könnte man so lösen:

<script>
  if(!this.JSON||typeof JSON.stringify !== 'function'||typeof JSON.parse !== 'function'){
    document.write("<scr"+"ipt type=\"text/javascript\" src=\"json2.js\"></scr"+"ipt>");
  }
</script>

jQuery nach hinten verlegen

Ganz praktisch hat es sich erwiesen, das Javascript nach dem meisten Markup zu laden. So wird durch CSS und HTML schonmal die Seite aufgebaut und dann erst werden die Javascript-Verbesserungen geladen.

Viele Webanwendungen, z.B. Google Mail, zeigen zunächst einen Ladebildschirm. Dadurch fühlt sich die Anwendung gleich viel langsamer an. Schneller wird die Anwendung wenn zunächst der grobe Aufbau steht, mit HTML und CSS zuerst geladen, dann ein kleines Skript erste Programmteile implementiert, sodass die Optik fertig erscheint. Dann läd man jQuery und dann erst weitere Javascripts (die auf jQuery basieren). So kann sich die Seite blitzschnell aufbauen, ohne dass erst jQuery geladen werden muss.

jQuery mouserest-Plugin

Nicht wirklich ein „Plugin“ aber eine kleine Hilfsfunktion. Sie führt ein Callback aus, nachdem die Maus einige Zeit auf dem Element war:

jQuery(function(){ // plugins
  jQuery.fn.mouserest=function (callback,time) {
    jQuery(this).mouseenter(function(e){
      this.dsthTo=setTimeout(function (obj){callback.apply(obj)},time,this);
    }).mouseleave(function(){
      clearTimeout(this.dsthTo);
    });
  }
});

Das ist ganz praktisch, denn wenn man die Zeit (in ms) auf 200 setzt, lässt sich verhindern, dass bestimmte Effekte beim bloßen Überfahren auftreten. Sondern der Event wird erst ausgelößt, wenn die Maus eine kurze Zeit auf dem Element war. Im callback kann man übrigens durch das apply() mit this auf das DOM-Element zugreifen, wie es in jQuery üblich ist.

Kommentare: 2 Einträge

jQuery Shortcuts (hoverfade Plugin)

01.06.2009, 15:53
jQuery hoverfade Plugin

jQuery hoverfade Plugin

Als ich zum Ferienbeginn ein paar Sachen an meinem Blog gerichtet habe, habe ich zum ersten mal die Plugin-Funktion von jQuery (aktiv) benutzt. Es gibt bestimmte Javascript-Effekte, die man immer wieder benutzt. In jQuery sind einige davon schon Enthalten. Doch man baut dann im Endeffekt doch immer einige jQuery-Funktionen zusammen. Ich z.B. „verstecke“ gerne Dinge auf Webseiten, indem ich sie leicht transparent mache und dann bei Mouseover wieder voll anzeigen lasse. Deshalb habe ich dafür ein jQuery „Plugin“ gebastelt:

jQuery.fn.hoverfade = function(hvspeed,hvopacity,uhspeed,uhopacity) {
  return this.each(function(){
    jQuery(this).css({
      opacity:uhopacity
    }).hover(function(){ 
      jQuery(this).stop().fadeTo(hvspeed,hvopacity);
    },function(){ 
      jQuery(this).stop().fadeTo(uhspeed,uhopacity);
    });
  });
};

Man kann es natürlich kaum Plugin nennen, sondern eher ein kleiner Shortcut, sodass man nicht immer schreiben muss:

$("selector").css({
   opacity:0.3
}).hover(function(){ 
   $(this).fadeTo("fast", 1);
},function(){ 
   $(this).fadeTo("slow", 0.3);
});

Sondern nur noch folgendes braucht:

$("selector").hoverfade("fast",1,"slow",0.3);

Wie man sieht ist das Erstellen von solch kleinen Plugins recht einfach: man hängt einfach in das jQuery.fn-Objekt die Funktion ein, die dann den häufig verwendeten Code enthält, und schon kann man sie als Makro auf alle jQuery-Elemente anwenden. Natürlich kann man auch Parameter an die Funktion übergeben, um eine gewisse Konfiguration zuzulassen.

Außerdem empfiehlt es sich in Plugins statt dem kurzen $ das explizite jQuery zu verwenden, damit man das Plugin auch verwenden kann, wenn $ z.B. ein anderes JS-Frameworks ist. In der Plugin-Funktion ist this das jQuery-Objekt auf das das Plugin angewendet wurde. Damit der Code immer klappt, sollte man noch mit each über die enthaltenten Elemente loopen. Im each-Closure zeigt this dann allerdings auf das DOM-Element, weshalb man es (meistens) mit $(this) wieder zu einem jQuery-Objekt machen muss. Damit das Plugin auch wirklich immer läuft, sollte man es vielleicht auch noch von JSLint checken lassen.

OT: andere Änderungen an der Seite

Ich habe übrigens neben den Icons für die Social Networks (Damit die Blogeinträge weiter oben stehen) auch noch ein paar andere Sachen verändert: Die automatischen ids, die nur die <input> mit den <label> verbinden, habe ich verkürzt, damit sie nicht immer so hässlich im Markup stehen. Dann habe ich im CSS alle Schriftgrößen auf Pixel umgestellt. Ich hoffe jetzt natürlich, dass meine Seite weiterhin in allen Browsern (fast) gleich aussieht.

Meine Editor-Toolbar wird auch immer voller. Jetzt habe ich mir noch Buttons dazu gemacht, um encodeierte <> und [] einzufügen. Außerdem habe ich endlich (halb) vimeo-Support im CMS. Ist ja grausam immer diesen ganzen <embed>-Kram erstmal in valides HTML umzuschreiben und dann hat man immer sehr viel HTML-Code zwischen dem Text. Außerdem kann ich so jetzt z.B. ganz einfach mal die Schriftfarbe von allen eingebetteten vimeo-Videos ändern.

Eigentlich sollte es ja so sein, dass im Content der Blogposts nichts ist, das die Darstellung beeinflusst, doch man braucht bei eingebetteten Videos offensichtlich immer Breite (ist fest) und Höhe (leider nicht fest), weshalb ich dann habe: [[vimeo:4767190|338|]]. Um alles 100%ig zu machen müsste ich natürlich aus der oEmbed API die genauen Video-Daten holen, aber das ist dann fast doch ein bisschen zu viel Aufwand. Was mich allerdings wundert: Während diese seltsame embed-Box auf der vimeo-Seite nicht-valides HTML ausspuckt, gibt die API, z.B. http://vimeo.com/api/oembed.xml?url=http%3A//vimeo.com/4767190&width=540 schönes valides HTML XHTML heraus.

Kommentare: keine

Selbstorganisierendes 3D-Clustering

28.05.2009, 19:33

Und wieder einmal ein bisschen mit Processing herum gespielt: Da meine 3D-Tagcloud ja noch recht wechselhafte Ergebnisse geliefert hat, habe ich nun die Erkenntnisse aus der Magnetismus-Implementierung in Processing verwendet, um die Blogposts noch besser anzuordnen. Sie ziehen sich zusammen, wenn sie ähnliche Themen behandeln, was wiederum anhand der gemeinsamen Tags festgemacht wird. Video:


Selbstorganisierender 3D-Cluster aus Blogposts basierend auf gemeinsamen Tags

Zunächst habe ich den Code aus den beiden erwähnten alten Sketches zusammen kopiert. Leider musste noch einiges geändert werden: Die Tags führen nicht länger ein Eigenleben, sondern dienen nur als Berechnungsgrundlage für die gegenseitige Anziehung der Blogeinträge. Zwar läd die Routine wieder die selbe .csv-Datei, doch diesmal legt sie nur einen Array von Blogeinträgen an, die jeweils eine Liste ihrer Tags speichern.

Daraufhin folgt eine kleine Erweiterung meiner „Magnetismus“-Partikel. die Anziehung wird nicht mehr durch eine Ladung bestimmt, sondern durch die Anzahl der gemeinsamen Tags. Sollte diese Anzahl 0 sein, erfahren die Blogeinträge eine kleine Abstoßung. Sollte die Anzahl 1 sein, ist die „Ladung“ 1, sollte sie 5 sein, ist die Ladung 5100, also vergleichsweise groß. Das sorgt dafür, dass sich die Partikel gerne „durchkämpfen“. Dann haben die Partikel an sich immer die Ladung 1, weil es ja eine symmetriche Bindung ist. Es gibt wieder eine „Pauli-Kraft“, sodass die Partikel nicht wie ein Zelt zusammenfallen. Damit sie sich aber nicht unendlich abstoßen, habe ich auch noch eine weitere Kraft zum Zentrum hin hinzugefügt, die sich kontrollieren lässt, sodass manchmal die Blogeinträge etwas lockerer auseinander fallen und sich aber auch in der Mitte zu einem Ball zusammenfinden. Sehr eindrucksvoll finde ich wie bestimmte Themenkomplexe bei geringer „Zentripetalkraft“ in Kristall-artigen Strukturen zusammen bleiben.

Beim Rendering habe ich wieder ein bisschen neuen Code ausprobiert. Die Linien repräsentieren nun die Stärke der gegenseitigen Anziehung (nicht wie vorher die Entfernung) und die Partikel haben einen DOF-Effekt bekommen: Eine Textur, die sich je nach Entfernung zur Kamera verändert, zu einer weich gezeichneten Version der Textur.

Kommentare: keine

Magnetismus und Processing

26.05.2009, 20:02

Wenn man ein bisschen interessantere Partikel-Effekte haben will, als konstante Geschwindigkeit oder Beschleunigung, so wie Selbstorganisation, dann kann man ziemlich gut die Prinzipien von Feldern, wie Magnetismus (so heißt das irgendwie bei Processing, läuft aber auf Elektrostatik hinaus) oder Gravitation benutzen. Hier mal ein Video von meinen Magnetismus-Partikeln:


504 Magnetische Partikel. Die großen Gelben habe ich für das Video „manuell“ bewegt.

Die großen gelben Partikel haben eine recht große positive Ladung und auch eine große Masse, sodass sie sich nicht so schnell abstoßen. Die kleinen Partikel haben eine kleine Masse und kleinere negative Ladung, sodass sie schön in der Gegend herum fliegen und sich nicht so stark abstoßen.

Bei Magnetismus und Gravitation sieht die Grundgleichung so aus:

E = Q * ( D / |D|^3 )

Mit Ladung des anderen Partikels Q und Differenz der Ortsvektoren D. Hat man mehrere Partnerpartikel, addiert man diesen Feldvektor E von jedem Einzelpartikel und teilt dann durch die Anzahl. Bei der Gravitation wäre Q die Masse, es beschriebt also so etwas wie den Partikelspezifischen Wirkungsgrad.

Dann berechnet man die Coulomb-Kraft, die dieses Feld auf den Partikel auswirkt mit:

F = ε * q * E

Wobei q die Ladung des Partikels ist und ε eine Konstante, die bewirkt, dass die Feldkraft in ordentlicher Proportion ist mit anderen Kräften, die auf den Partikel wirken. Denn jetzt benötigt man noch ein paar mehr Felder oder Kräfte, damit die Partikel nicht unendlich weit abgestoßen werden bzw. aufeinander prallen. Da würde sich die Gravitation als Ergänzung zum Magnetismus eignen oder eine sog. „Pauli-Kraft“ (12er Teil vom Lennard-Jones-(12,6)-Potential), die statt dem ^3 ein ^12 hat. Das ^12 bewirkt eine große Erhöhung der Kraft, wenn die Partikel sich näher kommen, sind sie jedoch weiter entfernt, wirkt die Kraft kaum noch. Für die Pauli-Kraft musste ich ε recht hoch wählen, damit sie in Konkurrenz mit dem Magnetismus treten kann. Für Flüssigkeiten wäre statt einem weiteren Feld aber z.B. auch eine Konstante Beschleunigung nach unten in Kombination mit einem Eimer o.ä. möglich.

a = ΣF / m

Hat man alle Felder berechnet, addiert man die Kräfte, und dividiert die Kraft durch die Masse, damit hat man die Beschleunigung. Die Beschleunigung addiert man zur Geschwindigkeit und die Geschwindigkeit multipliziert man mit einer Reibungszahl und dann addiert man sie zum Ort. (Euler-Verfahren/Methode der kleinen Schritte) Damit hat man eine halbwegs brauchbares Partikelsystem.

Kleine Ergänzungen könnten noch sein ein Timer, sodass die fps keine Einwirkung auf die Geschwindigkeit haben, erfahrungsgemäß bleiben sie aber mehr oder weniger konstant. Was extrem zur Geschwindigkeit beiträgt ist das Verwerfen von kleinen Feldkräften. Man kann mit Ladung, Masse und Entfernung schon grob bestimmen, ob sich die Partikel überhaupt groß beeinflussen werden und sich dann die Berechnung der genauen Feldkraft sparen, was schon sehr viel Geschwindigkeit einspart. Hier z.B. mal ein Screenshot aus meinem für Echtzeit optimiertem Algorithmus, wo nur die auch wirklich berechneten Beeinflussungen zwischen den kleinen Partikeln als rote Linien eingezeichnet sind:

In diesem high-fps-Modus habe ich auch das Text-Rendering deaktiviert, da das doch alles deutlich verlangsamt hat. Nötig wäre auch eine bessere Methode also das simple Geschwindigkeit addieren. Ich habe gelesen man kann Integrieren. Oder man addiert einfach nur z.B. ein viertel der Geschwindigkeit und berechnet alles viermal pro gerendertem Frame, was eigentlich ganz gut funktioniert, aber eben nicht immer, es fliegen doch hin und wieder Teilchen in den Äther. Ein Geschwindigkeitslimit wäre vielleicht auch hilfreich.

Was auch noch interessant werden könnte, das ganze mit verschiedenen Ladungsarten? Das Prinzip lässt sich auf jeden Fall erweitern. Schließlich gibt es ein Wikibook über Teilchenphysik aus dem man sich einiges an Inspiration holen kann, oder man experimentiert, so wie ich bei der 3D-Tagcloud mit Processing. Hat man das ganze Buch implementiert und den Algorithmus 100% perfektioniert, ist man wohl bei so etwas wie der „Weltformel“, was definitiv interessant wäre.

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