Kurs:Neueste Internet- und WWW-Technologien/3D-Grafik im Browser

Aus Wikiversity

Einführung[Bearbeiten]

Echtzeitfähige 3D-Simulationen im Browser sind ein Thema das schon seit Langem für Diskussionsstoff sorgt. Angefangen in den 90ern, mit der Formulierung erster Beschreibungssprachen für dreidimensionale Welten, bis zur derzeitigen Entwicklung hardwarebeschleunigter Verfahren, hat das Thema bereits eine wechselvolle Geschichte hinter sich. Einige Versuche in Richtung weltweit akzeptierter Standards sind bereits gescheitert, und richtig durchsetzen konnte sich bisher noch keine aktuelle Technologie. Es gibt allerdings seit ein paar Jahren erste Hoffnungszeichen, sodass die Dritte Dimension vielleicht schon bald den Einzug ins Internet nimmt und dessen Wahrnehmung im Alltag bereichert.

Welche Technologien gibt es?[Bearbeiten]

Prozedurale 3D-Programmierung[Bearbeiten]

WebGL
Standardisierte Low-Level 3D API, um über Javascript 3D-Grafiken im Browser ohne Hilfe zusätzlicher Plugins zu rendern.
O3D
Ehemals ein Browser Plugin für 3D-Grafiken im Browser, seit Mai 2011 eine Bibliothek für WebGL
Stage 3D
Feature für den Adobe Flash Player, das in Version 11 hinzugefügt wurde
Shockwave
Schon vor der Entwicklung von Stage 3D bietete Adobe mit dem Shockwave Player die Möglichkeit, 3D-Spiele und andere Anwendungen hardware-beschleunigt darzustellen.
Unity 3D
Proprietäre Spiele-Engine, erlaubt die Entwicklung von Spielen und Anwendungen für Browser mit dem Unity Webplayer Plugin unter den Betriebssystemen Windows und Mac OS

Deklarative 3D-Programmierung[Bearbeiten]

VRML
Web-Standard und Beschreibungsprache, um 3D Grafiken im Browser darzustellen, wurde abgelöst durch X3D
X3D
XML-basierte und standardisierte Beschreibungssprache für 3D Szenegraphen
X3DOM
Open-Source Framework, um X3D Szenen automatisch in WebGL Befehle umzuwandeln.
XML3D
Proprietäres Framework, das genauso wie X3DOM XML-Dokumente in WebGL Befehle umsetzt. Basiert allerdings nicht auf X3D.

Pseudo 3D[Bearbeiten]

QTVR
QuickTime-Dateiformat für Panaromafotos. Es können Kameraschwenks simuliert werden sodass bei dem Betrachter der Eindruck einer Rundumsicht entsteht.

WebGL[Bearbeiten]

WebGl (Web Graphics Library) ist eine Programmierschnittstelle, um in kompatiblen Browsern 3D-Grafiken hardwarebeschleunigt und ohne Plugins zu rendern. WebGL Befehle werden dabei in OpenGL ES 2.0.-Befehle umgewandelt und diese von der Grafikkarte performant verarbeitet. Für die Implementierung der Shader wird ebenso wie für OpenGL ES 2.0 die OpenGL Shading Language verwendet. Mit dem Google-Projekt Angle (Almost Native Graphics Layer Engine) ist es zudem möglich, auf Windows Systemen jene OpenGL ES Aufrufe in entsprechende DirectX Aufrufe zu übersetzen[1].

Der Quelltext eines WebGL-Programms besteht aus Javascript- und Shadercode. Um 3D-Szenen auf einer Website darzustellen dient ein HTML5 Canvas Element als Leinwand, auf dem die Szene abgebildet wird. Dieses Canvas-Element ist dabei das einzige für WebGL notwendige Element, in diesem wird mit Javascript initial ein WebGL-Kontext erzeugt.

Entwicklungsgeschichte von WebGL[Bearbeiten]

WebGL wird von Industriekonsortium Khronos Group spezifiziert. Zu den Mitgliedern der Khronos Group gehören unter anderem die Grafikprozessor-Hersteller ATI Technologies und Nvidia sowie die Browserhersteller Google Inc., Mozilla Foundation, Opera Software und Apple. Die Khronos Group wurde 2000 gegründet[2] und spezifiziert neben WebGL auch OpenGL und OpenGL ES 2.0. WebGL baut auf OpenGL ES 2.0 auf. Der Vorgänger von OpenGL ES und WebGl, OpenGL, wurde ursprünglich 1992 von Silicon Graphics entwickelt[3], die Firma ist heute selbst Mitglied bei der Khronos Group. OpenGL ES (Open Graphics Library for Embedded Systems) ist eine Untermenge von OpenGL und eine spezielle Spezifikation für Endgeräte, die nicht die gleiche Leistungsfähigkeit wie Desktop-PCs aufweisen[4]. Die erste Version von OpenGL ES 2.0 entstand 2005, seit ungefähr 2008 werden Implementationen des Standards in Embedded Systems produziert[4]. Im März 2009 gründet Khronos die Working Group für WebGL[5], welche genau drei Jahre später die erste Version des Standards verabschiedet[6].

Browser Unterstützung[Bearbeiten]

Die meisten verbreiteten Browser unterstützen zurzeit WebGL (Stand Juli 2012)[7]. Die Browser Firefox (seit Version4) und Chrome (seit Version 9) unterstützen den Standard. Bei Opera (seit Version 11) und Safari (seit Version 5.1) ist die Unterstützung für WebGL implementiert, per default allerdings ausgeschaltet. Der Internet Explorer unterstützt WebGL nicht, Microsoft nennt Sicherheitsbedenken als Begründung für die fehlende Implementierung[8].

Hinweise zu WebGL in Chrome/Chromium[Bearbeiten]

Im Gegensatz zu Chrome ist bei Chromium die Unterstützung für WebGL per default deaktiviert. Es gibt zwei Möglichkeiten, um WebGL in Chromium zu aktivieren: Entweder in die Adresszeile about:flags eingeben und das entsprechende Flag setzen oder den Browser über die Kommandozeile starten und dabei den Parameter --enable-webgl angeben. Außerdem setzen Chrome und Chromium für manche Betriebssysteme einige Grafikkarten und Treiber auf eine Blacklist[9]. Um diese zu ignorieren muss auf der Kommandozeile der Parameter --ignore-gpu-blacklist mit angegeben werden.

Beispiel für Chromium unter Linux mit einer nicht unterstützten Grafikkarte:

chromium-browser --enable-webgl --ignore-gpu-blacklist

Stage 3D[Bearbeiten]

Stage 3D codename Molehill ist ein Feature für den Adobe Flash Player, das in Version 11 hinzugefügt wurde[10]. Ähnlich wie in WebGL werden 3D-Elemente hardware-unterstützt gerendert, dazu greift Stage 3D auf DirectX (Windows) und OpenGL (Linux, Max OS) zu. Stage3D benutzt mehrere Schichten (Stages) zur Tiefenwirkung. So können zweidimensionale Objekte einfach über dreidimensionale Szenen hinweg gezeichnet werden[11]

In Stage3D wird ebenso wie in WebGL auf prozedurale Weise programmiert. Adobe bietet zur einfacheren Handhabung eine Reihe von 2D- und 3D-Frameworks zum Download an[12].

Adobe hat die Entwicklung des Flash Player für mobile Endgeräte eingestellt, sodass in Zukunft keine Stage-3D-Anwendungen auf Smartphones und Tablets laufen werden[13].

VRML[Bearbeiten]

VRML Virtual Reality Modeling Language ist eine deklarative Beschreibungssprache für 3D-Szenen. Version 1.0 wurde schon 1995 von Silicon Graphics entwickelt und zwei Jahre später ISO-standardisiert. Damit gehört VRML zu den ältesten Standards für 3D-Technologien im Browser. VRML-Dateien, sogenannte Worlds (Datei-Endung .wrl), sind einfache Klartext-Dateien. Sie sind hierarchisch aufgebaut und enthalten Knoten für geometrische Grundformen (Würfel, Kegel, Kugel ...), die wiederum Materialeigenschaften besitzen können (Texturen). Mehrere solcher Knoten können zu Transform-Knoten zusammengefasst werden, auf denen z.B. Verschiebungen und Rotationen angewendet werden können. Die wenigsten Browser unterstützen VRML nativ, deswegen wird meistens ein Plugin benötigt.

Beispiel einer VRML World:

#VRML V2.0 utf8
# A Cylinder
Shape {
    appearance Appearance {
        material Material { }
    }
    geometry Cylinder {
        height 2.0
        radius 1.5
    }
}

X3D[Bearbeiten]

X3D Extensible 3D ist der Nachfolger von VRML. Im Gegensatz zu VRML basiert X3D auf XML. X3D wird vom Konsortium Web3D entwickelt und wurde im Jahr 2001 als offizieller W3C-Standard verabschiedet, seit 2004 ist X3D auch ISO-Standard. Um X3D Dateien im Browser darzustellen wird meistens ein Plugin benötigt.

Beispiel einer X3D-Datei:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.2//EN"
  "http://www.web3d.org/specifications/x3d-3.2.dtd">
 <X3D profile='Immersive' version='3.2'
      xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance'
      xsd:noNamespaceSchemaLocation='http://www.web3d.org/specifications/x3d-3.2.xsd'>
 <head>
 </head>
 <Scene>
    <!-- Scene graph with a single red ball -->
    <Shape>
      <Sphere radius='2.0'/>
      <Appearance>
         <Material diffuseColor='1.0 0.0 0.0'/>
      </Appearance>
    </Shape>
 </Scene>
</X3D>

X3DOM[Bearbeiten]

X3DOM ist ein Framework, um X3D-Dateien automatisch mithilfe von WebGL zu rendern[14]. Für WebGL inkombatible Browser wird stattdessen Adobe Flash ab der Version 11 verwendet. Serverseitig wird für X3DOM nur eine Javascript-Bibliothek und die Flash-Integration benötigt[15]. Außerdem muss Python installiert sein. Um zu überprüfen, ob der Browser X3DOM unterstützt gibt es einen Online-Check. Der große Vorteil bei X3DOM ist, dass der Nutzer im Gegensatz zu X3D und VRML kein zusätzliches Plugin installieren muss. Selbst wenn der Browser, zum Beispiel der Internet Explorer, WebGL nicht unterstützt, können X3D-Szenen mit dem Flash-Player dargestellt werden.

Die Software wird seit 2009 vom Fraunhofer-Institut für Graphische Datenverarbeitung entwickelt[16].

Praxisbeispiel für WebGL[Bearbeiten]

Eine sehr gute Einführung in die Programmierung mit WebGL bieten die Online-Kurse von Giles Thomas auf dessen Blog Learning WebGL. Im Folgenden wird eine modifizierte Zusammenfassung der Lessons 1-5 verwendet.

Der Quellcode für die Kurse von Giles Thomas ist verfügbar auf github: https://github.com/gpjt/webgl-lessons.git

Grundgerüst einer WebGL Website[Bearbeiten]

Dieser Abschnitt baut auf dem ersten Kurs von Giles Thomas auf.

Um 3D-Grafiken zu rendern, ist als einziges Element im HTML-Rumpf einer Website das HTML5 Canvas Element erforderlich.

<body onload="webGLStart();">
    <canvas id="canvas" style="border: none;" width="500" height="500"></canvas>
</body>

Dieses Canvas Element definiert die Breite und Höhe der Szene. Außerdem erhält es eine ID (in diesem Fall "canvas"), mit der es über Javascript referenziert werden kann. Die Javascript Methode webGLStart() führt den vorhandenen WebGL-Code aus, der die eigentlichen 3D-Anweisungen enthält. Die Methode wird hier direkt beim Laden der Seite durch den Browser ausgeführt (onload).

function webGLStart() {
        var canvas = document.getElementById("canvas");
        initGL(canvas);
        initShaders();
        initBuffers();
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.enable(gl.DEPTH_TEST);
        drawScene();
    }

Die Methode webGLStart() führt eine Reihe von Schritten aus. Wichtig ist zunächst, dass das Element mit der ID "canvas" (nämlich genau das Canvas Element s.o.) als Variable canvas referenziert wird und der Methode initGL(canvas) als Parameter übergeben wird.

var gl;
    function initGL(canvas) {
        try {
            gl =canvas.getContext("webgl") || canvas.getContext("experimental-webgl");  
            gl.viewportWidth = canvas.width;
            gl.viewportHeight = canvas.height;
        } catch (e) {
        }
        if (!gl) {
            alert("Could not initialise WebGL, sorry :-(");
        }
    }

Die Methode initGL(canvas) initialisiert den WebGL-Kontext im Canvas-Element. Dazu wird eine globale Variable namens gl definiert. In ihr wird der Rückgabewert der Methode canvas.getContext(context) gespeichert. Der Parameter context ist hierbei ein Standard Kontextname, im Beispielcode "webgl" oder "experimental-webgl". Für die Entwicklunszeit der WebGL Spezifikation ist "experimental-webgl" der gültige Kontextname, für zukünftige Versionen ist "webgl" als Kontextname vorgesehen[17]. Die Variable gl bietet globalen Zugriff auf die Kernfunktionalitäten von WebGL. Sollte der anzeigende Browser nicht WebGL kompatibel sein, ist die Variable gl nach dem Methodenaufruf immer noch null. In diesem Fall kann eine Warnung angezeigt werden, dass WebGL nicht initialisiert werden konnte.

Schritt 1: Zeichnen eines Objektes im Raum[Bearbeiten]

Dieses Beispiel basiert ebenfalls auf dem ersten Kurs von Giles Thomas.

Um 3D-Objekte zu zeichnen, sind einige Informationen zu definieren: Wo befinden sich die Koordinaten eines Objekts? Welche Punkte bilden eine Oberfläche? Wie soll eine Oberfläche aussehen?

In WebGL werden die Koordinaten von Punkten als ArrayBuffer gespeichert, also ganz gewöhnliche ungetypte Javascript-Arrays. Im Beispiel bilden die vier Punkte eines Quadrats zwei Dreieicke, dessen Koordinaten in der Methode initBuffers initialisiert werden.

var squareVertexPositionBuffer;
    function initBuffers() {
        squareVertexPositionBuffer = gl.createBuffer();
        vertices = [
             1.0,  1.0,  0.0,
            -1.0,  1.0,  0.0,
             1.0, -1.0,  0.0,
            -1.0, -1.0,  0.0
        ];
        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        squareVertexPositionBuffer.itemSize = 3;
        squareVertexPositionBuffer.numItems = 4;
    }

Das Javascript-Array wird global als squareVertexPositionBuffer deklariert. Mit der WebGL Methode createBuffer() wird das Array als ArrayBuffer initialisiert. Die eigentlichen Punkte speichert das Array vertices zwischen und nachdem mit bindBuffer(. .) der Browser angewiesen wird, den ArrayBuffer auf die Grafikkarte zu schreiben, wird dieser über die Methode bufferData(. . .) mit den Koordinaten als Float-Array befüllt. Anschließend wird für den Buffer mitgespeichert, wie viele Dimensionen (nämlich 3) die Koordinaten besitzen und wie viele Punkte es insgesamt gibt (genau 4), damit WebGL später korrekt über das Array iterieren kann.

In der Methode webGLStart() wird mit

var squareVertexPositionBuffer;
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);

festgelegt, dass die Hintergrundfarbe des Canvas schwarz ist und vordere Objekte die dahinterliegenden Objekte verdecken.

Es gibt noch eine weitere sehr grundlegende Informationen, nämlich die Definition der Perspektive, also wie ein dreidimenionaler Raum auf eine zweidimenionale Leinwand projiziert wird. Die default-Einstellung in WebGL ist die Orthogonalperspektive. Damit 3D-Objekte perspektivisch verzerrt dargestellt werden, so wie das menschliche Auge die Umgebung wahrnimmt, muss die Zentralperspektive eingestellt werden. Dies geschieht in der Methode drawScene() mit dem Funktionsaufruf mat4.perspective(. . . . .)

    function drawScene() {
        gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
        [...]
    }

Die globale Variable mat4 wird in einer externen Bibliothek[18] definiert, die geometrische Basismethoden für Vektoren und Matritzen zur Verfügung stellt. Mit der Methode mat4.perspective(. . . . .) werden jene Parameter übergeben, die den sichtbaren Raum einer 3D-Szene darstellen, auch genannt Frustum. Bei einer rechteckigen Leinwand hat das Frustum die Form eines Pyramidenstumpfes, dieser ist variabel im Winkel, in der Gesamthöhe und der Schnitthöhe des Stumpfes, sowie der Fläche des oberen Abschnittes, welche gleich der Fläche der Leinwand ist. Im Beispiel wird ein 45° Zentralperspektive eingestellt und die Höhe und Breite des Canvas als Abschnittsfläche. Die Tiefe des sichtbaren Raumes soll 100 Einheiten betragen und der Raum unmittelbar vor dem Betrachter von 0 bis 0,1 Einheiten ist nicht sichtbar.

Im zweiten Teil der Javascript-Methode drawScene() wird die eigentliche Szene gezeichnet und dabei auf den vordefinierten Buffer zurückgegriffen.

    function drawScene() {
        [...]
        mat4.identity(mvMatrix);
        mat4.translate(mvMatrix, [1.0,1.0,-7]);
        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
        setMatrixUniforms();
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
    }

Wie bereits beschrieben, bietet die Variable mat4 globalen Zugriff auf geometrische Basisoperationen. Dazu gehört unter anderem die Verschiebung und Drehung von Punkten im Raum. In der Computergrafik werden solche Operationen performant mit Matrizenmultiplikationen auf einer Menge von Vektoren bzw. Punkten durchgeführt. Hier führt die mvMatrix Model-View Matrix eine Translation durch, mit jeweils einer Einheit in Richtung der x- und y- Achse und sieben Einheiten auf der z-Achse. Mit der Methode setMatrixUniforms() werden die Matrizen an die Grafikkarte weitergereicht.

Zu guter Letzt wird die Oberfläche des Quadrates definiert. Räumliche Oberflächen werden in der Computergrafik in Primitive, meistens Dreiecke zerlegt, dieser Schritt heißt Tesselation. Für solche Primitive existieren hochperformante Rasterisierungsalgorithmen, die durch die Hardware umgesetzt werden. Beim Methodenaufruf gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems) werden alle grafischen Primitive der Szene mit einem sogenannten "Dreiecksstreifen" implizit definiert. Ein Dreieckstreifen wird durch eine Liste von mindestens 3 Punkten definiert, wobei das erste Dreieck aus den ersten drei Punkten besteht. Zu jedem folgenden Dreieck gehören die letzten beiden Punkte des vorherigen Dreiecks und der darauffolgende Punkt. Die Punkte eines Quadrats im Zickzack (wie in der Methode initBuffers) als Dreiecksstreifen zu definieren, ist also eine einfache Möglichkeit, die Flächen eines Quadrates mit zwei Dreiecken festzulegen.

Schritt1: So sieht das Canvas Element in einem WebGL-kompatiblen Browser aus

Schritt2: Bewegung und Textur[Bearbeiten]

Dieses Beispiel basiert auf dem ersten, dritten und fünften Kurs von Giles Thomas.

Um die Oberfläche des Quadrats etwas ausgefallener zu gestalten, wird in diesem Beispiel der Einsatz von Texturen erläutert. Außerdem wird gezeigt wie eine Szene in WebGL animiert werden kann.

Bei Texturen müssen zwei Dinge definiert werden:

  • Das zweidimensionale Bild, das als Textur verwendet werden soll
  • Die Zuordnung von räumlichen Koordinaten zu Texturkoordinaten und deren Position auf der zweidimensionalen Textur

Für den ersten Punkt wird im zweiten Beispiel beim Aufruf der Seite die Methode initTexture() aufgerufen:

var webglLogo;
    function initTexture() {
        webglLogo = gl.createTexture();
        webglLogo.image = new Image();
        webglLogo.image.onload = function () {
            handleLoadedTexture(webglLogo)
        }
        webglLogo.image.src = "webglLogo.png";
    }

Hier wird ein Bild aus einer Datei im Stammverzeichnis namens "webglLogo.png" geladen und als Textur in der globalen Variable webglLogo gespeichert. Außerdem wird der Textur ein Callback übergeben, welcher wiederum eine Methode namens handleLoadedTexture(webglLogo) mit der Textur als Parameter ausführt.

    function handleLoadedTexture(texture) {
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.bindTexture(gl.TEXTURE_2D, null);
    }

Dabei wird unter anderem mit gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true) das Koordinatensystem des Bildes an das räumliche WebGL Koordinatensystem angepasst (bei zweidimensionalen Bildern verläuft die y-Achse von oben nach unten, in einem räumlichen Koordinatensystem stünde das Bild auf dem Kopf). Um zu Vektorkoordinaten die entsprechenden Texturkoordinaten zu zuordnen, wird ein zweiter ArrayBuffer initialisiert. Die Zuordnung geschieht dabei durch die parallele Reihenfolge in den ArrayBuffern, d.h. die x-te Punktkoordinate gehört zur x-ten Texturkoordinate.

function initBuffers() {
        [...]
        squareTextureCoord = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, squareTextureCoord);
        var textureCoords = [
          1.0, 1.0,
          0.0, 1.0,
          1.0, 0.0,
          0.0, 0.0,
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
        squareTextureCoord.itemSize = 2;
        squareTextureCoord.numItems = 4;
}

Die Texturkoordinaten definieren die Position eines räumlichen Punktes in der zweidimensionalen Textur, deshalb besitzen diese Koordinaten auch nur zwei Dimensionen.

Um eine 3D-Szene zu animieren wird die Methode requestAnimFrame(.) verwendet. Es handelt sich um eine Methode aus einer externen Bibliothek[19], um funktional identische aber browserabhängige Methoden zu kapseln. Diese Methode erwartet einen Callback als Parameter, der genau dann aufgerufen wird, wenn der Browser die Szene erneut rendert. Wird dabei wieder die Methode requestAnimFrame(.) aufgerufen, so handelt es sich um eine absichtliche Endlosschleife, wobei neben dem erneuten Zeichnen der Szene auch zusätzliche Programmlogik ausgeführt werden kann.

    function tick() {
        requestAnimFrame(tick);
        drawScene();
        animate();
    }

Zum Beispiel kann bei jeder Ausführung in der Methode animate() ein Wert erhöht werden, um in Abhängigkeit dieses Wertes die Szene zu bewegen.

var lastTime = 0;
var r = 0;
    function animate() {
        var timeNow = new Date().getTime();
        if (lastTime != 0) {
            var elapsed = timeNow - lastTime;
            r +=  elapsed / 10.0;
        }
        lastTime = timeNow;
    }

Hier wird bei jeder Ausführung des Code die Differenz zwischen dem Zeitpunkt der letzten Ausführung und dem aktuellen Zeitpunkt gebildet. Proportional zu dieser Differenz wird die globale Variable r erhöht. Das hat den Sinn, dass unabhängig von der Auslastung des Browsers oder der Grafikkarte die Szene in gleichbleibender Geschwindigkeit bewegt wird. Nun kann z.B. eine Rotation in Abhängigkeit von r in der Methode drawScene() ausgeführt werden.

function drawScene() {
        [...]
        mat4.identity(mvMatrix);
        mat4.translate(mvMatrix, [0.0, 0.0, -5.0]);
        mat4.translate(mvMatrix, [0.0,0.0,-1.0]);
        mat4.rotate(mvMatrix, r, [0.0,1.0,0.0]);
        [...]
    }

Schritt 2: So sieht das Quadrat mit einer Textur aus.

Schritt 3: Körper mit vielen Oberflächen[Bearbeiten]

Dieses Beispiel basiert auf dem dritten, vierten und fünften Kurs von Giles Thomas.

In diesem Beispiel wird erläutert, wie räumliche Objekte mit WebGL gezeichnet werden können, die nicht notwendigerweise aus einer einzigen Oberfläche bestehen.

Ein Würfel z.B. hat eine einzige Oberfläche (die Abwicklung des Würfels). Es ist aber ziemlich schwierig (wohl aber möglich[20]), alle sechs Seiten implizit durch einen Dreiecksstreifen zu definieren. Das Problem ist ganz ähnlich zum Haus vom Nikolaus: Vier Seiten des Würfels im Zickzack zu definieren ist einfach, allerdings fehlen dann immer noch die Vorder- und die Rückseite des Würfels.

Ein zweites Problem: Jeder Eckpunkt des Würfels müsste für jede Seite des Würfels die an die Ecke stößt jeweils drei unterschiedliche Texturkoordinaten bekommen. Betrachtet man einen Würfel von einer bestimmten Seite, so hat der rechte obere Eckpunkt für die Vorderseite die Texturkoordinate ganz oben rechts, also (1,1). Auf der Oberseite hat der Punkt jedoch die Texturkoordinate ganz unten rechts, also (1,0). Und auf der rechten Seite befindet sich der Punkt in der Textur ganz links oben (0,1).

Um beide Probleme zu lösen, gibt es in WebGL die Möglichkeit alle Punkte explizit zu definieren, die zusammen ein grafisches Primitiv bilden. Dazu wird der Würfel nicht mehr durch acht Punkte, sondern durch 24 Punkte dargestellt. Jeder dieser Punkte gehört nur noch zu einer Oberfläche. Zwar haben dadurch immer drei Punkte die exakt gleichen räumlichen Koordinaten, aber stets unterschiedliche Texturkoordinaten.

function initBuffers() {
       [...]
        vertices = [
            // Front face
            -1.0, -1.0,  1.0,
             1.0, -1.0,  1.0,
             1.0,  1.0,  1.0,
            -1.0,  1.0,  1.0,
            // Back face
            -1.0, -1.0, -1.0,
            -1.0,  1.0, -1.0,
             1.0,  1.0, -1.0,
             1.0, -1.0, -1.0,
            // Top face
            [...]
            // Bottom face
            [...]
            // Right face
            [...]
            // Left face
            [...]
        ];
        [...]
        var textureCoords = [
          // Front face
          0.0, 0.0,
          1.0, 0.0,
          1.0, 1.0,
          0.0, 1.0,
          // Back face
          1.0, 0.0,
          1.0, 1.0,
          0.0, 1.0,
          0.0, 0.0,
          // Top face
          [...]
          // Bottom face
          [...]
          // Right face
          [...]
          // Left face
          [...]
        ];
        [...]
    }

Um festzulegen, welche Punkte zusammen ein grafisches Primitiv bilden (in unserem Fall ein Dreieck), wird ein dritter ArrayBuffer definiert. In Dreierschritten speichert dieser Buffer die Indexnummer von allen Punkten eines neuen Dreiecks, d.h. die ersten drei Punkte bilden ein Dreieck, die folgenden drei Punkte das zweite Dreieck und so weiter.

function initBuffers() {
        [...]
        cubeVertexIndexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
        var cubeVertexIndices = [
            0, 1, 2,      0, 2, 3,    // Front face
            4, 5, 6,      4, 6, 7,    // Back face
            8, 9, 10,     8, 10, 11,  // Top face
            12, 13, 14,   12, 14, 15, // Bottom face
            16, 17, 18,   16, 18, 19, // Right face
            20, 21, 22,   20, 22, 23  // Left face
        ];
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW);
        cubeVertexIndexBuffer.itemSize = 1;
        cubeVertexIndexBuffer.numItems = 36;
    }

Wichtig dabei ist, dass diese Indexnummern als ELEMENT_ARRAY_BUFFER gespeichert werdern, da WebGL für Indexnummern separate Buffer verwaltet.


Einsatz von 3D-Modellierungsprogrammen[Bearbeiten]

Eine komplexere 3D-Szene textuell zu beschreiben ist sehr aufwendig, sowohl auf deklarative Art und Weise mit X3D und besonders auf prozedurale Weise mit Befehlen in WebGL. Um 3D-Modelle zu erstellen werden üblicherweise für diesen Zweck geeignete Programme wie zum Beispiel Blender oder Autodesk Maya verwendet. Einige dieser Programme unterstützen den Export von 3D-Modellen zu X3D-Dateien, z.B. exportiert Blender nativ X3D-Dateien und mit dem Plugin Rawkee kann auch Maya 3D-Modelle zu X3D-Dateien exportieren[21]. Für Maya existiert außerdem das Plugin Inka3D um 3D-Modelle nach WebGL zu exportieren[22]. Mit Blender erstellte 3D-Modelle, gespeichert als Blender Scene-Dateiformat, können nachträglich mit entsprechender Software in WebGL-Befehle konvertiert werden[23].

Praxisrelevante Anwendungsbeispiele[Bearbeiten]

Die Einsatzmöglichkeiten von 3D-Technologie im Browser sind enorm. Denkbare Anwendungen würden sich in den Bereichen Augmented Reality, 3D-Visualisierungen von Geodaten, medizinische und naturwissenschaftliche Visualisierungen, Internetwerbung und Internetshopping, 3D-Modelle von archäologischen Objekten, sowie natürlich in der Computerspiele-Branche finden.

Unzählige Experimente mit WebGL hat Google auf der Seite Chrome Experiments zur Verfügung gestellt. Historiker und Archäologen auf der ganzen Welt können archäologische Objekte online in 3D anschauen, zum Beispiel die Ausgrabungsstätte Mes-Aynak. Wer die Alpenzüge der Schweiz dreidimensional im Browser erleben möchte, für den bietet die Fachhhochschule der Nordwestschweiz eine Applikation. Empfehlenswert ist auch die anatomische Darstellung des menschlichen Körpers, ein Projekt von Google namens Zygote Body. Schüler und Studenten, denen es schwer fällt, sich zweidimensionale Molekül-Darstellungen an der Tafel dreidimensional vorzustellen, werden sich sicher über Molgrabber freuen. Und falls zuhause kein Rubikwürfel zur Hand ist, kann diese Denksportaufgabe auch virtuell im Browser gelöst werden.

Citroën zeigt ein 3D-Modell des Citroën DS3 in Stage3D. Die Entwickler von X3DOM bieten einige experimentelle Praxisbeispiele, etwa der interaktive Produktkatalog eines Online-Shops.

Natürlich sind dies nur die ersten Beispiele junger Standards. Aufgrund der vergleichsweise hohen Akzeptanz der Industrie, insbesondere von WebGL, sind der Kreativität der Entwickler nun aber keinerlei technische Grenzen mehr gesetzt. In Zukunft wird es viele weitere Websites mit 3D-Anwendungen geben, die womöglich ein breites Publikum finden und auch für ganz alltägliche Zwecke geschaffen sind.

Diskussion[Bearbeiten]

VRML und X3D haben sich auf dem Markt nicht richtig durchsetzen können, obwohl ihre Entwicklung enthusiastisch begrüßt wurde[24]. Ein Grund ist sicher, dass der Nutzer zusätzliche Plugins für den Browser installieren muss. Es gibt bis heute kaum VRML- und X3D-Anwendungen, weswegen die Zahl der Nutzer mit einem VRML/X3D kompatiblen Browser nicht sonderlich gewachsen ist[25]. Dadurch fehlt es Webseitenbetreibern an Motivation, 3D-Anwendungen in Websiten einzubinden, weil kein großes Publikum erreicht werden kann - ein klassisches Henne-Ei Problem. Die verfrühte Entwicklung und die fehlende marktwirtschaftliche Motivation machten die Entwickler von VRML bereits 2004 als Ursache für das Scheitern von VRML verantwortlich:

"The hardware wasn't ready; the network wasn't ready; most importantly, the consumers weren't ready." (deutsch: "Die Hardware war nicht bereit, die Internet-Infrastruktur war nicht bereit, am Wichtigsten: Die Verbraucher waren nicht bereit.") Tony Parisi[26]

"There was never a push to make VRML games-ready or even games-capable, because there were no market-driven demands for it. Instead, we saw an endless array of "science experiments" (to quote a famous venture capitalist) which showed how interesting VRML could be. But never, ever, how lucrative." (deutsch: "Es gab nie einen Schub, um VRML spielefähig zu machen, weil es einfach kein marktwirtschaftliches Bedürfnis dafür gab. Stattdessen sahen wir eine Aneinanderreihung von "wissenschaftlichen Experimenten" (in den Worten eines bekannten Venture-Kapitalisten), die zeigten wie interessant VRML sein könnte. Aber niemals wie lukrativ.") Marc Pesco[24]

Dass Browser den jüngsten Standard WebGL ohne zusätzliche Plugins implementieren, ist die Vielzahl an bereits bestehenden Anwendungen zu verdanken. Dankbarerweise profitiert auch X3D von der Entwicklung von WebGL, weil X3D-Szenen mit Software wie X3DOM plötzlich auch ohne Plugins von den meisten Browsern dargestellt werden können.

Die Frage der Abstraktionshöhe, also ob 3D-Anwendungen hardware-nah in WebGL implementiert werden, oder deklarativ auf einer höheren Abstraktionsebene, hängt vom Anwendungsfall ab. Zu den Vorteilen deklarativer Beschreibung gehört, dass 3D-Szenen menschenverständlicher sind und leichter manipuliert werden können. Der große Vorteil bei XML-Dokumenten wie X3D-Dateien ist, dass die gesamte Szene allein mit DOM-Manipulationen verändert werden kann. Es existiert für diesen Zweck bereits bewährte Software, die dadurch auch für 3D-Modellierung verwendet werden kann. In Javascript geschriebene DOM-Manipulationen können so z.B. eine Szene animieren. Zu den Nachteilen deklarativer Programmierung gehören oftmals Leistungseinbußen, die dem Overhead durch Transformationen in prozedurale Befehle geschuldet sind. Bei besonders resourcenlastigen 3D-Anwendungen, zum Beispiel bei Browser-Computerspielen, ist daher die aufwendigere Low-Level Programmierung mit WebGL von Vorteil.

Aus Gründen des Wettbewerbs sind bei Basis-Technologien, von denen ganze Sparten in der IT-Industrie abhängen, freie Standards vorzuziehen. Deswegen ist es wünschenswert, dass sich WebGL und X3D gegen die unzähligen proprietären Technologien wie Stage 3D, Shockwave, XML3D und Unity 3D durchsetzt. Glücklicherweise lässt die inzwischen breite Akzeptanz der Industrie genau darauf hoffen.

Weblinks[Bearbeiten]

Einzelnachweise[Bearbeiten]

  1. [1] angleproject
  2. [2] About the Khronos Group
  3. [3] OpenGL Developed by Silicon Graphics
  4. 4,0 4,1 [4] OpenGL ES - The Standard for Embedded Accelerated 3D Graphics
  5. [5] Khronos Launches Initiative to Create Open Royalty Free Standard for Accelerated 3D on the Web (abgerufen am 16. Juli 2012)
  6. [6] Khronos Releases Final WebGL 1.0 Specification (abgerufen am 16. Juli 2012)
  7. [7] Browser Implementierung laut englischer Wikipedia
  8. [8] Microsoft hält WebGL für zu unsicher Heise Developer, 17. Juni 2011 (abgerufen am 16. Juli 2012)
  9. [9] WebGL and 3D graphics
  10. [10] Adobe Flash Player 11 / Features
  11. [11] Marco Scabia: Stage3D: The stage behind the stage
  12. [12] Stage3D
  13. [13] crn.de:Adobes mobiler Flash-Player eingestellt
  14. [14] About X3DOM
  15. [15] Getting Started - Downloading X3DOM
  16. [16] Visual Computing System Technologies
  17. [17] Getting Started with WebGL - Creating a WebGL Context Mozilla Developer Network (abgerufen am 17. Juli 2012)
  18. [18] gl-matrix Javascript Matrix and Vector library for High Performance WebGL apps
  19. [19] webgl-utils WebGL Samples, Google Inc.(abgeufen am 17. Juli 2012)
  20. [20] Francine Evans, Steven Skiena, Amitabh Varshney: Optimizing Triangle Strips for Fast Rendering State University of New York at Stony Brook
  21. [21] Rawkee - An open-source plugin for Maya
  22. [22] Inka3D
  23. [23] Blender WebGl Exporter
  24. 24,0 24,1 [24] Mark Pesco: VRML - The first ten years
  25. [25] 'Download-Statistik des VRML/X3D kompatiblen Browsers FreeWRL auf SourceForge
  26. [26] Tony Parisi: The VRML Equinox, Ten Years Later

Literatur[Bearbeiten]

  • Katrin Honauer: WebGL-basiertes Rendering von interaktiven Graphvisualisierungen Bachelorarbeit Hasso-Plattner-Institut, Potsdam 2009, S.11-17