TICKTOO Systems | Schöne Dinge. Für das Internet und darüber hinaus.

3D in Webanwendungen

Sebastian Kraus — 08.12.2011

Im Rahmen von Recherchearbeiten für ein Projekt sind wir auf eine Bibliothek gestoßen, die das rendern von 3D-Bildern in PHP ermöglicht und somit diesen Themenbereich, mit gewissen Einschränkungen, für die Welt der Web-Projekte eröffnet.

Da die Dokumentation für diese 3D-Rendering-Bibliothek etwas veraltet und unvollständig ist, möchten wir an dieser Stelle einen kleinen Überblick über die Bibliothek und das Herumspielen mit 3D-Objekten geben.

Image_3D: 3D Arbeitsbereich erstellen

require_once('Image/3D.php');

// Create the blank three-dimensional space
$world = new Image_3D();
$world->setColor(new Image_3D_Color(0xFF, 0xFF, 0xFF));

// A red light
$light1 = $world->createLight('Light', array(0,100,1000));
$light1->setColor(new Image_3D_Color(0xFF, 0x00, 0x00));

// Add Cone object and do things with it
$obj = $world->createObject('cone', array('detail' => 128));
$obj->setColor(new Image_3D_Color(0xFF, 0xFF, 0xFF));
$obj->transform($world->createMatrix('Scale', array(70, 220, 70)));
$obj->transform($world->createMatrix('Rotation', array(100, 100, 270)));
$obj->transform($world->createMatrix('Move', array(0 , 95, 0)));

// Render and save the 2-D image
$world->createRenderer('perspectively');
$world->createDriver('ZBuffer');
$world->render(540, 260, 'object.png');

Was passiert hier?

  • Zeile 4 und 5 erstellt einen neuen, virtuellen 3D Raum, der zunächst vollständig leer ist. Mit der Angabe eines Farbwertes (Zeile 5) kann dieser eingefärbt werden.
  • In Zeile 8 und 9 wird diesem Raum eine Lichtquelle hinzugefügt. Ein 3D-Raum kann beliebig viele Lichtquellen enthalten. In vielen Fällen ist das auch notwendig, um komplexe oder große Objekte korrekt auszuleuchten. In diesem Fall fällt das Licht aus 0,100,1000 in den Raum. Die Zahlen entsprechen einem X/Y/Z-Koordinatensystem. X=0 bedeutet, dass die Lichtquelle auf der horizontalen Achse genau mittig positioniert wird. Y=100 bedeutet, dass das Licht leicht von oben einfällt. Z=1000 setzt das Licht weit hinter das Auge des Betrachters, sodass das Objekt relativ gleichmäßig ausgeleuchtet ist.
  • Zeile 12: Hier wird ein neues Objekt des Typs "Cone", also "Kegel" erstellt. Die Angabe "detail" definiert, aus wie vielen Polygonen dieser Kegel bestehen soll. Eine größere Anzahl von Polygonen verlängert die Zeit, das Bild zu rendern, erzielt aber eine bessere Qualität des Objektes. Ein Wert von 4 würde beispielsweise eine Pyramide erzeugen, da der Kegel nur 4 Kanten hätte. Richtig "rund" bekommt man den Kegel theoretisch nie, man kann sich aber so weit annähern, dass man die Kanten nicht mehr sieht.
  • Zeile 14: In einem leeren 3D-Raum sind die Größenverhältnisse noch völlig undefiniert. Der Renderer weiß nicht, ob der Kegel 4 Millimeter oder 200 Kilometer hoch ist. Dementsprechend müssen wir diesen Kegel den räumlichen Verhältnissen anpassen und können ihn noch in den Proportionen ändern.
  • Zeile 15: Durch die Rotation wird definiert, in welche Richtung der Kegel zeigt. Man kann den Kegel direkt von unten (90/180/0) betrachten, was zur Folge hätte, dass nur ein roter Kreis sichtbar wäre. Hier werden die X/Y/Z-Werte in Grad angegeben.
  • Zeile 16: Hiermit wird die "Kamera", mit der das 3D-Bild später in ein 2D-Bild umgewandelt wird, verschieben. Die Y-Achse wird um 95 Pixel nach unten verschoben, sodass die Spitze des Kegels noch im Bild zu sehen ist. Andernfalls wäre der Kegel oben abgeschnitten.
  • Zeile 19: Es gibt verschiedene Möglichkeiten, auf so einen 3D-Raum zu schauen. "Perspectively" berücksichtig hier eine perspektivische Verzerrung. "Isometric" würde Ähnliches bewirken, wie wenn das Bild mit einem Weitwinkelobjektiv aufgenommen werden würde.
  • Zeile 20: Image_3D stellt verschiedene "renderer" zur Verfügung. Enthaltene Engines wären beispielsweise "GD", "SVG", "ZBuffer" oder "ASCII". Es gibt noch weitere, und die meisten sind für Webanwendungen völlig ungeeignet. Relevant sind definitiv ZBuffer, der beim Rendern die Kollision von Polygonen berücksichtigt und bessere Ergebnisse erzielt als die GDLib, allerdings signifikant länger zur Berechnung braucht.
  • Zeile 21 speichert das Bild mit einer Größe von 540 x 260 Pixeln in eine Datei. Eine Änderung der Bildgröße ändert zwar die Dimension des Bildes, die gerenderte Szenerie ändert sich aber nicht in der Größe. Hierfür muss man die Objekte beim "scalen" auf die gewünschte Größe bringen.

Image_3D: Lichtquellen

require_once('Image/3D.php');

// Create the blank three-dimensional space
$world = new Image_3D();
$world->setColor(new Image_3D_Color(0xFF, 0xFF, 0xFF));

// A red light
$light1 = $world->createLight('Light', array(0,100,1000));
$light1->setColor(new Image_3D_Color(0xFF, 0x00, 0x00));

$light2 = $world->createLight('Light', array(100,0,0));
$light2->setColor(new Image_3D_Color(0xFF, 0xFF, 0x00));
...

Mehrere Lichtquellen

Ab Zeile 11 fügen wir hier eine zweite Lichtquelle hinzu. Es soll gelbes Licht von der linken Seite auf das Objekt fallen. Das Ergebnis: Links Gelb, ein Farbverlauf nach rechts über Orange bis Rot.

Image_3D: Kugel

...
$obj = $world->createObject('sphere', array('r'=>100, 'detail' => 5));
$obj->setColor(new Image_3D_Color(0xFF, 0xFF, 0xFF));
$obj->transform($world->createMatrix('Move', array(0 , 0, 0)));		
...

Am Beispiel einer Kugel verdeutlicht sich das Problem mit den Polygonen und der Render-Zeit. $r ist hier der Radius der Kugel, also die relative Größe zum 3D-Raum. Detail gibt auch hier die Granularität der Polygone an.

Ein Wert von 4 ergäbe ein Objekt, welches eher einem Golfball als einer Kugel ähnelt. Allerdings verbraucht dieser Golfball bereits 1024 Polygone (beim Kegel waren es "nur" 128). Der Wert 5 kommt einer Kugel schon näher. Betrachtet man aber auch dieses Objekt von "Nahem", erinnert es, trotz 4096 Polygonen, eher einer Orange. $detail = 7 erzeugt 65536 Polygone und braucht auf einer 3 GHz-CPU bereits 30 Sekunden zum rendern. Man wird also eher versuchen, durch geschickte Positionierung der Lichtquellen die Kugel so ungünstig auszuleuchten, dass bei einem Detailfaktor von 5 die "Ecken" an der Kugel nicht zu sehr störend wirken.

Image_3D: .3DS-Importieren

...
$light = $world->createLight('Light', array(-1000,-100,1000));
$light->setColor(new Image_3D_Color(0xFF, 0xFF, 0xFF));

$light2 = $world->createLight('Light', array(1000,100,1000));
$light2->setColor(new Image_3D_Color(0xA0, 0xA0, 0xA0));

$obj = $world->createObject('3ds', 'testhead2.3ds');
$obj->setColor(new Image_3D_Color(0xFF, 0xFF, 0xFF));
$obj->transform($world->createMatrix('Rotation', array(90,0,0)));
$obj->transform($world->createMatrix('Scale', array(100,100,100)));
$obj->transform($world->createMatrix('Move', array(0,-30,0)));
...

Ein besonders cooles Feature der Image_3D-Bibliothek ist die Möglichkeit, ganze 3D-Studio Dateien direkt zu importieren. Hier wurden die Lichtquellen angepasst, um das Objekt besser auszuleuchten. Durch das Hinzufügen weiterer Lichtquellen kann man hier noch deutlich bessere Ergebnisse erzielen.

Die hier abgebildete Skulptur besteht aus 3120 Polygonen und ist entsprechend grobschlächtig. Man sollte sich keine großen Hoffnungen machen, eine .3ds-Datei mit 100.000 Polygonen performant mit dieser Bibliothek rendern zu können. Dieser Quellcode brauchte so auf unserer 3GHz-Maschine aber nur ca 1 Sekunde zum Berechnen. Mittels der "Rotate"- Funktion (Zeile 15) kann der Kopf in alle Richtungen gedreht werden und so sowohl von der Seite, von unten, oder von hinten betrachtet werden.

Installation der Bibliothek

Die Bibliothek ist als PEAR-Paket recht einfach mittels

pear install -f Image_3D

auf jedem System installierbar, welches die pear-Bibliotheken installiert hat. Auf Ubuntu- bzw. Debian-Systemen geschieht das mittels

sudo apt-get install php-pear

Weiterführende, hilfreiche Links

pear.php.net
Offizielle Dokumentation der Bibliothek. Leider nicht ganz auf dem aktuellen Stand, vermittelt aber doch einen brauchbaren Überblick über die Funktionalität und das Featureset.

ibm.com/developerworks/
Sehr hilfreiche Beschreibung der grundlegenden Funktionen mit Code-Schnippseln und Illustrationen.

 

Sharing is Caring Facebook | Twitter | Google | LinkedIn