From 4ab365b110f2f1f2b736326b7059244a32115089 Mon Sep 17 00:00:00 2001 From: Florian Merz Date: Thu, 11 Feb 2021 14:45:38 +0100 Subject: unslug de: move --- .../3d-objekte_mit_webgl_erstellen/index.html | 126 ----------- .../index.html | 238 +++++++++++++++++++++ .../animating_objects_with_webgl/index.html | 118 ++++++++++ .../animating_textures_in_webgl/index.html | 89 ++++++++ .../animierte_texturen_in_webgl/index.html | 89 -------- .../tutorial/beleuchtung_in_webgl/index.html | 172 --------------- .../creating_3d_objects_using_webgl/index.html | 126 +++++++++++ .../einf\303\274hrung_in_webgl/index.html" | 73 ------- .../index.html" | 97 --------- .../tutorial/getting_started_with_webgl/index.html | 73 +++++++ .../index.html" | 238 --------------------- .../tutorial/lighting_in_webgl/index.html | 172 +++++++++++++++ .../objekte_mit_webgl_animieren/index.html | 118 ---------- .../texturen_in_webgl_verwenden/index.html | 159 -------------- .../index.html | 97 +++++++++ .../tutorial/using_textures_in_webgl/index.html | 159 ++++++++++++++ 16 files changed, 1072 insertions(+), 1072 deletions(-) delete mode 100644 files/de/web/api/webgl_api/tutorial/3d-objekte_mit_webgl_erstellen/index.html create mode 100644 files/de/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html create mode 100644 files/de/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html create mode 100644 files/de/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html delete mode 100644 files/de/web/api/webgl_api/tutorial/animierte_texturen_in_webgl/index.html delete mode 100644 files/de/web/api/webgl_api/tutorial/beleuchtung_in_webgl/index.html create mode 100644 files/de/web/api/webgl_api/tutorial/creating_3d_objects_using_webgl/index.html delete mode 100644 "files/de/web/api/webgl_api/tutorial/einf\303\274hrung_in_webgl/index.html" delete mode 100644 "files/de/web/api/webgl_api/tutorial/farben_mittels_shader_in_einen_webgl-kontext_hinzuf\303\274gen/index.html" create mode 100644 files/de/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html delete mode 100644 "files/de/web/api/webgl_api/tutorial/hinzuf\303\274gen_von_2d_inhalten_in_einen_webgl-kontext/index.html" create mode 100644 files/de/web/api/webgl_api/tutorial/lighting_in_webgl/index.html delete mode 100644 files/de/web/api/webgl_api/tutorial/objekte_mit_webgl_animieren/index.html delete mode 100644 files/de/web/api/webgl_api/tutorial/texturen_in_webgl_verwenden/index.html create mode 100644 files/de/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html create mode 100644 files/de/web/api/webgl_api/tutorial/using_textures_in_webgl/index.html (limited to 'files/de/web/api/webgl_api') diff --git a/files/de/web/api/webgl_api/tutorial/3d-objekte_mit_webgl_erstellen/index.html b/files/de/web/api/webgl_api/tutorial/3d-objekte_mit_webgl_erstellen/index.html deleted file mode 100644 index d3a21591fd..0000000000 --- a/files/de/web/api/webgl_api/tutorial/3d-objekte_mit_webgl_erstellen/index.html +++ /dev/null @@ -1,126 +0,0 @@ ---- -title: 3D-Objekte mit WebGL erstellen -slug: Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL ---- -

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren", "Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden")}}

- -

Bringen wir unser Quadrat in die dritte Dimension, indem wir fünf oder mehr Flächen hinzufügen und daraus einen Würfel machen. Um das effizient zu machen, wechseln wir vom Zeichnen direkt über die Vertices zur gl.drawArray() Methode, um den Vertex-Array als eine Tabelle zu verwenden und die einzelnen Vertices in dieser Tabelle als Referenz für Positionen jeder Fläche zu definieren, indem wir gl.drawElements() aufrufen.

- -

Bedenken Sie: Jede Fläche benötigt vier Vertices, die diese definieren, aber jeder Vertex wird von drei Flächen verwendet. Wir können eine Menge Daten sparen, indem wir eine Liste aller 24 Vertices erstellen und uns dann auf jeden Vertex durch dessen Index in der Liste beziehen, anstatt den gesamten Koordinatensatz zu verwenden.

- -

Die Vertex-Positionen des Würfels definieren

- -

Zunächst wollen wir den Positionsspeicher der Vertices erstellen, indem wir den Code in initBuffers() ändern. Das geschieht genau so wie für das Quadrat, allerdings haben wir hier ein paar Datensätze mehr, da wir 24 Vertices (4 pro Seite) haben müssen:

- -
  var vertices = [
-    // vordere Fläche
-    -1.0, -1.0,  1.0,
-     1.0, -1.0,  1.0,
-     1.0,  1.0,  1.0,
-    -1.0,  1.0,  1.0,
-
-    // hintere Fläche
-    -1.0, -1.0, -1.0,
-    -1.0,  1.0, -1.0,
-     1.0,  1.0, -1.0,
-     1.0, -1.0, -1.0,
-
-    // obere Fläche
-    -1.0,  1.0, -1.0,
-    -1.0,  1.0,  1.0,
-     1.0,  1.0,  1.0,
-     1.0,  1.0, -1.0,
-
-    // untere Fläche
-    -1.0, -1.0, -1.0,
-     1.0, -1.0, -1.0,
-     1.0, -1.0,  1.0,
-    -1.0, -1.0,  1.0,
-
-    // rechte Fläche
-     1.0, -1.0, -1.0,
-     1.0,  1.0, -1.0,
-     1.0,  1.0,  1.0,
-     1.0, -1.0,  1.0,
-
-    // linke Fläche
-    -1.0, -1.0, -1.0,
-    -1.0, -1.0,  1.0,
-    -1.0,  1.0,  1.0,
-    -1.0,  1.0, -1.0
-  ];
-
- -

Die Farben der Vertices definieren

- -

Außerdem müssen wir einen Array für die Farben der 24 Vertices erstellen. Dieser Code definiert zunächst die Farben für jede Fläche und verwendet dann eine Schleife, um jeden der Vertices mit einer Farbe zu bestücken.

- -
  var colors = [
-    [1.0,  1.0,  1.0,  1.0],    // vordere Fläche: weiß
-    [1.0,  0.0,  0.0,  1.0],    // hintere Fläche: rot
-    [0.0,  1.0,  0.0,  1.0],    // obere Fläche: grün
-    [0.0,  0.0,  1.0,  1.0],    // untere Fläche: blau
-    [1.0,  1.0,  0.0,  1.0],    // rechte Fläche: gelb
-    [1.0,  0.0,  1.0,  1.0]     // linke Fläche: violett
-  ];
-
-  var generatedColors = [];
-
-  for (j=0; j<6; j++) {
-    var c = colors[j];
-
-    for (var i=0; i<4; i++) {
-      generatedColors = generatedColors.concat(c);
-    }
-  }
-
-  cubeVerticesColorBuffer = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer);
-  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(generatedColors), gl.STATIC_DRAW);
-
- -

Das Element-Array definieren

- -

Sobald die Vertex-Arrays generiert worden sind, müssen wir das Element-Array erstellen.

- -
  cubeVerticesIndexBuffer = gl.createBuffer();
-  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
-
-  // Dieser Array definiert jede Fläche als zwei Dreiecke über die Indizes
-  // im Vertex-Array, um die Position jedes Dreiecks festzulegen.
-
-  var cubeVertexIndices = [
-    0,  1,  2,      0,  2,  3,    // vorne
-    4,  5,  6,      4,  6,  7,    // hinten
-    8,  9,  10,     8,  10, 11,   // oben
-    12, 13, 14,     12, 14, 15,   // unten
-    16, 17, 18,     16, 18, 19,   // rechts
-    20, 21, 22,     20, 22, 23    // links
-  ]
-
-  // Sende nun das Element-Array zum GL
-
-  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
-      new WebGLUnsignedShortArray(cubeVertexIndices), gl.STATIC_DRAW);
-
- -

Das cubeVertexIndices Array definiert jede Fläche als ein paar von Dreiecken, alle Vertices des Dreiecks werden als ein Index im Vertex-Array des Würfels festgelegt. Daher ist der Würfel aus einer Sammlung von 12 Dreiecken beschrieben.

- -

Den Würfel zeichnen

- -

Als nächstes müssen wir etwas Code zur drawScene() Funktion hinzufügen, um über den Indexspeicher des Würfels zu zeichnen. Wir fügen neue bindBuffer() und drawElements() Aufrufe hinzu:

- -
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
-  setMatrixUniforms();
-  gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
-
- -

Da jede Seite unseres Würfels aus zwei Dreiecken besteht, gibt es 6 Vertices pro Seite, oder 36 Vertices im Würfel, obwohl einige davon doppelt sind. Da unser Index-Array jedoch aus einfachen Integern besteht, stellt dies keinen unkoordinierbaren Betrag an Daten dar, welcher für jeden Frame der Animation durchgegangen werden muss.

- -

Jetzt haben wir einen animierten Würfel, welcher herum springt, rotiert und über sechs unterschiedliche Seiten verfügt. Wenn Ihr Browser WebGL unterstützt, schauen Sie sich hier die Demo in Aktion an.

- -

{{PreviousNext("Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren", "Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden")}}

diff --git a/files/de/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html b/files/de/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html new file mode 100644 index 0000000000..56c267f394 --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html @@ -0,0 +1,238 @@ +--- +title: Hinzufügen von 2D Inhalten in einen WebGL-Kontext +slug: Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext +tags: + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Einführung_in_WebGL", "Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen")}}

+ +

Sobald der WebGL-Kontext erfolgreich erstellt wurde, können wir anfangen darin zu rendern. Am einfachsten beginnen wir mit einem einfachen, zweidimensionalen, untextuierten Objekt. Fangen wir also damit an, ein Stück Code zu schreiben, um ein Quadrat zu zeichnen.

+ +

Hinweis zur deutschen Übersetzung dieses Abschnitts

+ +

Die deutsche Übersetzung bezieht sich auf ältere Version des Beispielcodes als der englische Originaltext. Der im deutschen Text beschriebene Code hat einige Probleme:

+ + + +

Um das Beispiel selber nachzuprogrammieren ist es daher empfehlenswert, auf die englische Version des Tutorials zu wechseln. Vielleicht haben Sie ja auch Lust, diese Version ins Deutsche zu übersetzen?

+ +

Beleuchtung der Szene

+ +

Das Wichtigste, das wir verstehen müssen bevor wir anfangen können, ist, dass wir, uns bereits in einer dreidimensionalen Umgebung befinden, obwohl wir nur ein zweidimensionales Objekt in diesem Beispiel rendern wollen. Das heißt, wir müssen jetzt bereits Shader einsetzen, die unsere einfache Szene beleuchten und solche erstellen, die unser Objekt zeichnen. Diese Shader werden festlegen wie unser Quadrat später beleuchtet sein wird.

+ +

Initialisierung der Shader

+ +

Shader sind durch die OpenGL ES Shading Language (pdf) spezifiziert. Damit es einfacher ist unsere Inhalte zu warten und zu aktualisieren, können wir unseren Code so schreiben, dass die Shader im HTML Dokument gefunden werden, anstatt alles mittels JavaScript zu bauen. Werfen wir einen Blick auf unsere initShaders() Routine, welche diese Aufgabe übernimmt:

+ +
function initShaders() {
+  var fragmentShader = getShader(gl, "shader-fs");
+  var vertexShader = getShader(gl, "shader-vs");
+
+  // Erzeuge Shader
+
+  shaderProgram = gl.createProgram();
+  gl.attachShader(shaderProgram, vertexShader);
+  gl.attachShader(shaderProgram, fragmentShader);
+  gl.linkProgram(shaderProgram);
+
+  // Wenn die das Aufrufen der Shader fehlschlägt,
+  // gib eine Fehlermeldung aus:
+
+  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+    alert("Initialisierung des Shaderprogramms nicht möglich.");
+  }
+
+  gl.useProgram(shaderProgram);
+
+  vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+  gl.enableVertexAttribArray(vertexPositionAttribute);
+}
+
+
+ +

Es werden zwei Shader in dieser Routine geladen; der Erste, der fragmentShader, wird vom script Element mit der Id "shader-fs" geladen. Der Zweite, der vertexShader, wird vom script Element mit der Id "shader-vs" geladen. Wir werden im nächsten Abschnitt noch näher auf die getShader() Funktion eingehen. Diese Routine holt sich dann die Shader aus dem DOM.

+ +

In diesem Teil erstellen wir noch das Shaderprogramm, in dem wir die Funktion createProgram() aufrufen, die beiden Shader anhängen und das Shaderprogramm verlinken. Danach wird der Zustand des LINK_STATUS Parameters überprüft, um sicher zu gehen, dass das Programm erfolgreich verlinkt wurde. Wenn das der Fall ist, aktivieren wir das neue Shaderprogramm.

+ +

Shader aus dem DOM laden

+ +

Die getShader() Routine ruft ein Shaderprogramm mit dem festgelegtem Namen aus dem DOM auf, gibt das kompilierte Shaderprogramm zurück oder ist leer, wenn nichts geladen oder kompiliert worden konnte.

+ +
function getShader(gl, id) {
+  var shaderScript = document.getElementById(id);
+
+  if (!shaderScript) {
+    return null;
+  }
+
+  var theSource = "";
+  var currentChild = shaderScript.firstChild;
+
+  while(currentChild) {
+    if (currentChild.nodeType == 3) {
+      theSource += currentChild.textContent;
+    }
+
+    currentChild = currentChild.nextSibling;
+  }
+ +

Wenn das Element mit der festgelegten Id gefunden wurde, wird der Text in die Variable theSource gespeichert.

+ +
  var shader;
+
+  if (shaderScript.type == "x-shader/x-fragment") {
+    shader = gl.createShader(gl.FRAGMENT_SHADER);
+  } else if (shaderScript.type == "x-shader/x-vertex") {
+    shader = gl.createShader(gl.VERTEX_SHADER);
+  } else {
+    return null;  // Unbekannter Shadertyp
+  }
+ +

Jetzt wo der Code für die Shader gelesen wurde, können wir uns die MIME Typen der Shader angucken, um festzulegen, ob es ein Vertex-Shader (MIME Typ: "x-shader/x-vertex") oder ein Fragment-Shader (MIME Typ: "x-shader/x-fragment") ist. Danach werden dann die entsprechenden Shadertypen erstellt.

+ +
  gl.shaderSource(shader, theSource);
+
+  // Kompiliere das Shaderprogramm
+
+  gl.compileShader(shader);
+
+  // Überprüfe, ob die Kompilierung erfolgreich war
+
+  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+    alert("Es ist ein Fehler beim Kompilieren der Shader aufgetaucht: " + gl.getShaderInfoLog(shader));
+    return null;
+  }
+
+  return shader;
+}
+
+ +

Schließlich wird der Shader kompiliert. Falls ein Fehler während der Kompilierung auftritt, zeigen wir die Fehlermeldung an und geben null zurück. Andernfalls wird der kompilierte Shader zurückgegeben.

+ +

Die Shader

+ +

Nun müssen wir die eigentlichen Shaderprogramme in unser HTML schreiben. Wie genau diese Shader arbeiten, übersteigt das Ziel dieses Tutorials, wir gehen daher nur auf das Wesentliche ein.

+ +

Fragment-Shader

+ +

Jeder Pixel in einem Vieleck wird Fragment in der GL-Fachsprache genannt. Die Aufgabe des Fragment-Shaders ist es, die Farbe für jeden Pixel bereitzustellen. In unserem Fall ordnen wir einfach jedem Pixel eine weiße Farbe zu.

+ +

gl_FragColor ist eine eingebaute GL Variable, die für die Farbe des Fragments verwendet wird.

+ +
<script id="shader-fs" type="x-shader/x-fragment">
+
+  void main(void) {
+    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+  }
+</script>
+
+ +

Vertex-Shader

+ +

Der Vertex-Shader definiert die Position und Form von jedem Punkt.

+ +
<script id="shader-vs" type="x-shader/x-vertex">
+  attribute vec3 aVertexPosition;
+
+  uniform mat4 uMVMatrix;
+  uniform mat4 uPMatrix;
+
+
+  void main(void) {
+    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+  }
+</script>
+
+ +

Das Objekt erstellen

+ +

Bevor wir unser Quadrat rendern können, müssen wir einen Puffer erstellen, der unsere Punkte enthält. Das werden wir mittels einer Funktion machen, die wir initBuffers() nennen. Wenn wir zu mehr fortgeschrittenen WebGL-Konzepten kommen, wird diese Routine vergrößert, um mehr - und komplexere - 3D-Objekte zu erstellen.

+ +
var horizAspect = 480.0/640.0;
+
+function initBuffers() {
+  squareVerticesBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+
+  var 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.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+}
+
+ +

Diese Routine ist, durch die einfache Art der Szene in diesem Beispiel, sehr einfach gehalten. Es geht los mit dem Aufruf der createBuffer() Methode, die einen Puffer erstellt in dem wir die Punkte speichern können. Der Puffer wird, durch Aufrufen der bindBuffer() Methode, mit dem Kontext verbunden.

+ +

Wenn das erledigt ist, erstellen wir einen JavaScript Array, der die Koordinaten für jeden Punkt des Quadrats enthält. Dieser wird dann in einen WebGL FloatArray umgewandelt und durch die bufferData() Methode werden die Punkte für das Objekt festgelegt.

+ +

Die Szene zeichnen

+ +

Jetzt sind die Shader aufgebaut und das Objekt ist erstellt. Wir können die Szene rendern lassen. Da wir in dieser Szene nichts animieren, ist unsere drawScene() Funktion sehr einfach. Es werden einige nützliche Routinen verwendet, die wir uns kurz anschauen.

+ +
function drawScene() {
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+  perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0);
+
+  loadIdentity();
+  mvTranslate([-0.0, 0.0, -6.0]);
+
+  gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+  setMatrixUniforms();
+  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+}
+
+ +

Als Erstes wird der Kontext auf unsere Hintergrundfarbe gesetzt und die Kameraperspektive festgelegt. Wir definieren ein Blickfeld von 45°, mit einem Höhen-/Breitenverhältnis von 640 zu 480 (die Größe unseres Canvas). Außerdem legen wir fest, dass wir nur Objekte zwischen 0.1 und 100 Einheiten gerendert haben wollen.

+ +

Dann wird die Position des Quadrats, über das Laden der ursprünglichen Position und der Verschiebung um 6 Einheiten von der Kamera weg, ermittelt. Danach, verbinden wir den Puffer des Quadrats mit dem Kontext, konfigurieren es, und zeichnen das Objekt, in dem wir die drawArrays() Methode aufrufen.

+ +

Das Ergebnis kann hier ausprobiert werden, wenn Sie einen Browser verwenden, der WebGL unterstützt.

+ +

Matrix Operationen

+ +

Matrix Operationen sind schon kompliziert genug. Keiner möchte wirklich den ganzen Code selbst schreiben, der benötigt wird um die Berechnungen selber durchzuführen. Glücklicherweise gibt es Sylvester, eine sehr handliche Bibliothek, die bestens mit Vektor und Matrix Operationen in JavaScript umgehen kann.

+ +

Die glUtils.js Datei, die in dieser Demo benutzt wird, wird bei einer ganzen Reihe von WebGL-Demos, die Web zu finden sind, verwendet. Keiner scheint sich völlig sicher zu sein, woher diese Bibliothek ursprünglich herkommt, aber es vereinfacht den Gebrauch von Sylvester noch weiter, in dem Methoden hinzugefügt werden, die auch spezielle Matrizentypen ermöglichen und HTML ausgegeben werden kann, um die Matrizen anzeigen zu lassen.

+ +

Zusätzlich, definiert diese Demo ein paar hilfreiche Routinen, um an diese Bibliothek für spezielle Aufgaben anzukoppeln. Was genau gemacht wird, ist kein Teil dieses Artikels, aber es gibt einige gute Referenzen zu Matrizen, die online verfügbar sind. Siehe unter Siehe auch, um ein paar aufzulisten.

+ +
function loadIdentity() {
+  mvMatrix = Matrix.I(4);
+}
+
+function multMatrix(m) {
+  mvMatrix = mvMatrix.x(m);
+}
+
+function mvTranslate(v) {
+  multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
+}
+
+function setMatrixUniforms() {
+  var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
+  gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten()));
+
+  var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+  gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));
+}
+
+ +

Siehe auch

+ + + +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Einführung_in_WebGL", "Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen")}}

diff --git a/files/de/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html b/files/de/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html new file mode 100644 index 0000000000..a9eafed6db --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html @@ -0,0 +1,118 @@ +--- +title: Objekte mit WebGL animieren +slug: Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen", "Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen") }}

+ +

Unser Code vom vorherigen Beispiel ist bereits so konfiguriert, dass die WebGL-Szene alle 15 Millisekunden neu gezeichnet wird. Bis jetzt wird zu jeder Zeit das gleiche Bild immer neu gezeichnet. Das wollen wir nun ändern, sodass sich unser Quadrat auf der Bildfläche bewegt.

+ +

In diesem Beispiel rotieren und verschieben wir unser Quadrat in alle drei Dimensionen, sodass es schon in einem 3D Raum existieren kann (obwohl wir bisher nur ein 2D-Objekt erstellt haben).

+ +

Das Quadrat rotieren lassen

+ +

Fangen wir damit an, das Quadrat im Raum zu rotieren. Als erstes brauchen wir dazu eine Variable in welche wir die Rotation des Quadrats verfolgen können:

+ +
var squareRotation = 0.0;
+
+ +

Jetzt müssen wir die drawScene() Funktion ändern, um die aktuelle Rotation auf das Quadrat anzuwenden, wenn dies gezeichnet werden soll. Nach der Umrechnung der Startposition für das Quadrat, wenden wir eine Rotation wie diese an:

+ +
mvPushMatrix();
+mvRotate(squareRotation, [1, 0, 1]);
+
+ +

Das speichert die aktuelle Model-View Matrix und rotiert die Matrix mit dem aktuellen Wert von squareRotation um die X und Z Achsen.

+ +

Nach dem Zeichen müssen wir die Originalmatrix wiederherstellen:

+ +
mvPopMatrix();
+
+ +

Wir speichern und stellen die Originalmatrix dann wieder her, um zu verhindern, dass die Rotation auf andere Objekte angewendet wird, die wir vielleicht später noch zeichnen wollen.

+ +

Um letztendlich etwas zu animieren, brauchen wir noch ein paar Zeilen Code, welcher den Wert von squareRotation über die Zeit verändert. Dafür erstellen wir eine neue Variable, die die Zeit aufzeichnet, welche wir zuletzt animiert haben (wir nennen diese lastSquareUpdateTime), dann fügen wir den folgenden Code an das Ende der drawScene() Funktion:

+ +
var currentTime = (new Date).getTime();
+if (lastSquareUpdateTime) {
+  var delta = currentTime - lastSquareUpdateTime;
+  squareRotation += (30 * delta) / 1000.0;
+}
+lastSquareUpdateTime = currentTime;
+
+ +

Dieser Code benutzt den Betrag der Zeit, die vergangen ist, seitdem wir zum letzten Mal den Wert von squareRotation geändert haben, um festzustellen wie weit das Quadrat rotiert werden soll.

+ +

Das Quadrat bewegen

+ +

Wir können das Quadrat auch verschieben indem wir eine unterschiedliche Position berechnen lassen, bevor wir es zeichnen. Dieses Beispiel zeigt wie eine grundlegende Animation gemacht werden kann. Allerdings möchten Sie in einer echten Anwendung wohl eher etwas weniger Irrsinniges machen.

+ +

Verfolgen wir die Abstände zu jeder Achse für unsere Verschiebung in drei neuen Variablen:

+ +
var squareXOffset = 0.0;
+var squareYOffset = 0.0;
+var squareZOffset = 0.0;
+
+ +

Und den Betrag, welcher unsere Postion auf jeder Achse verändern soll, in diesen Variablen:

+ +
var xIncValue = 0.2;
+var yIncValue = -0.4;
+var zIncValue = 0.3;
+
+ +

Nun können wir einfach diesen Code zum vorherigen Code, der die Rotation aktualisiert, hinzufügen:

+ +
squareXOffset += xIncValue * ((30 * delta) / 1000.0);
+squareYOffset += yIncValue * ((30 * delta) / 1000.0);
+squareZOffset += zIncValue * ((30 * delta) / 1000.0);
+
+if (Math.abs(squareYOffset) > 2.5) {
+  xIncValue = -xIncValue;
+  yIncValue = -yIncValue;
+  zIncValue = -zIncValue;
+}
+
+ +

Das bringt unser Quadrat dazu seine Größe zu verändern, sich willkürlich auf der Fläche zu verschieben, sich vom Betrachter weg und zum Betrachter hin zu bewegen und das alles während das Quadrat auch noch rotiert. Das sieht dann schon eher wie ein Bildschirmschoner aus.

+ +

Wenn Ihr Browser WebGL unterstützt, ist hier das Beispiel in Aktion.

+ +

Weitere Matrixoperationen

+ +

Dieses Beispiel verwendet einige zusätzliche Matrixoperationen, darunter zwei Routinen, die die Matrizen verschieben, wiederherstellen und in einem Stack aufbewahren und eine Routine, die die Matrix um eine gewissen Anzahl von Grad rotiert:

+ +
var mvMatrixStack = [];
+
+function mvPushMatrix(m) {
+  if (m) {
+    mvMatrixStack.push(m.dup());
+    mvMatrix = m.dup();
+  } else {
+    mvMatrixStack.push(mvMatrix.dup());
+  }
+}
+
+function mvPopMatrix() {
+  if (!mvMatrixStack.length) {
+    throw("Can't pop from an empty matrix stack.");
+  }
+
+  mvMatrix = mvMatrixStack.pop();
+  return mvMatrix;
+}
+
+function mvRotate(angle, v) {
+  var inRadians = angle * Math.PI / 180.0;
+
+  var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();
+  multMatrix(m);
+}
+
+ +

Diese Routinen wurden von einem Beispiel ausgeliehen, welches von Vlad Vukićević geschrieben wurde.

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen", "Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen") }}

diff --git a/files/de/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html b/files/de/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html new file mode 100644 index 0000000000..bfeb362b8e --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html @@ -0,0 +1,89 @@ +--- +title: Animierte Texturen in WebGL +slug: Web/API/WebGL_API/Tutorial/Animierte_Texturen_in_WebGL +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL +--- +

{{WebGLSidebar("Tutorial") }} {{Previous("Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

+ +

In dieser Demo bauen wir auf das vorherige Beispiel auf, indem wir die statischen Texturen mit den Frames eines OGG-Video ersetzen. Das ist nicht sehr schwer zu schreiben, sieht aber umso besser aus. Fangen wir an.

+ +

Zugang zum Video

+ +

Zunächst müssen wir etwas HTML hinzufügen, um das video Element zu erstellen, welches wir verwenden, um die Video-Frames zu erhalten:

+ +
<video id="video" src="Firefox.ogv" autobuffer='true'">
+  Ihr Browser scheint das HTML5 <code>&lt;video&gt;</code> Element nicht zu unterstützen.
+</video>
+
+ +

Das erstellt einfach ein Element, um die Video-Datei "Firefox.ogv" abzuspielen. Wir benutzen CSS, um zu verhindern, dass das Video angezeigt wird:

+ +
video {
+  display: none;
+}
+
+ +

Dann schenken wir dem JavaScript Code wieder unsere Aufmerksamkeit und fügen eine neue Zeile zur start() Funktion hinzu, um einen Bezug zum Video-Element herzustellen:

+ +
videoElement = document.getElementById("video");
+
+ +

Und wir ersetzen den Code, der die Intervall-gesteuerten Aufrufe von drawScene() setzt, mit diesem Code:

+ +
videoElement.addEventListener("canplaythrough", startVideo, true);
+videoElement.addEventListener("ended", videoDone, true);
+
+ +

Die Idee ist hier, dass wir die Animation nicht starten wollen, bevor das Video nicht ausreichend zwischengespeichert wurde, sodass es dann ohne Unterbrechung abgespielt werden kann. Wir fügen also einen Event-Listener hinzu, um auf das video Element zu warten bis es uns mitteilt, dass genug zwischengespeichert wurde und das komplette Video ohne Pause abgespielt werden kann. Wir fügen außerdem einen zweiten Event-Listener hinzu, sodass wir die Animation stoppen können, wenn das Video beendet ist und wir so nicht unnötig den Prozessor belasten.

+ +

Die startVideo() Funktion sieht so aus:

+ +
function startVideo() {
+  videoElement.play();
+  videoElement.addEventListener("timeupdate", updateTexture, true);
+  setInterval(drawScene, 15);
+}
+
+ +

Hier wird einfach das Video gestartet und ein Event-Handler bereitgestellt, der aufgerufen wird, wenn ein neuer Frame des Videos verfügbar ist. Dann werden die Intervall-gesteuerten Aufrufe der drawScene() Funktion eingerichtet, um den Würfel zu rendern.

+ +

Die videoDone() Funktion ruft einfach {{ domxref("window.clearInterval") }} auf, um die Intervallaufrufe zu beenden, die die Animation aktualisieren.

+ +

Die Video-Frames als Textur verwenden

+ +

Die nächste Änderung erhält die initTexture() Funktion, welche viel einfacher wird, weil kein Bild mehr geladen werden muss. Stattdessen muss nun das Textur-Mapping aktiviert werden und ein leeres Textur-Objekt zum späteren Gebrauch erstellt werden:

+ +
function initTextures() {
+  gl.enable(gl.TEXTURE_2D);
+  cubeTexture = gl.createTexture();
+}
+
+ +

So sieht die updateTexture() Funktion aus. Hier wird wirklich Arbeit verrichtet:

+ +
function updateTexture() {
+  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+  gl.texImage2D(gl.TEXTURE_2D, 0, videoElement, true);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+  gl.generateMipmap(gl.TEXTURE_2D);
+  gl.bindTexture(gl.TEXTURE_2D, null);
+}
+
+ +

Sie kennen diesen Code bereits. Es ist fast identisch zur handleTextureLoaded() Routine im vorherigen Beispiel, mit der Ausnahme, dass wir texImage2D() nicht mit einem Image Objekt sondern mit dem video Element aufrufen.

+ +

updateTexture() wird jedes Mal aufgerufen, wenn sich das timeupdate Event vom video Element meldet. Dieses Event wird gesendet, wenn sich die Zeit des aktuellen Frames ändert, sodass wir wissen, dass wir unsere Textur nur dann aktualisieren müssen, wenn neue Daten verfügbar sind.

+ +

Das war alles! Wenn Sie eine Browser mit Unterstützung von WebGL verwenden, können Sie sich das Beispiel in Aktion ansehen.

+ +

Siehe auch

+ + + +

{{Previous("Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

diff --git a/files/de/web/api/webgl_api/tutorial/animierte_texturen_in_webgl/index.html b/files/de/web/api/webgl_api/tutorial/animierte_texturen_in_webgl/index.html deleted file mode 100644 index bfeb362b8e..0000000000 --- a/files/de/web/api/webgl_api/tutorial/animierte_texturen_in_webgl/index.html +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: Animierte Texturen in WebGL -slug: Web/API/WebGL_API/Tutorial/Animierte_Texturen_in_WebGL -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL ---- -

{{WebGLSidebar("Tutorial") }} {{Previous("Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

- -

In dieser Demo bauen wir auf das vorherige Beispiel auf, indem wir die statischen Texturen mit den Frames eines OGG-Video ersetzen. Das ist nicht sehr schwer zu schreiben, sieht aber umso besser aus. Fangen wir an.

- -

Zugang zum Video

- -

Zunächst müssen wir etwas HTML hinzufügen, um das video Element zu erstellen, welches wir verwenden, um die Video-Frames zu erhalten:

- -
<video id="video" src="Firefox.ogv" autobuffer='true'">
-  Ihr Browser scheint das HTML5 <code>&lt;video&gt;</code> Element nicht zu unterstützen.
-</video>
-
- -

Das erstellt einfach ein Element, um die Video-Datei "Firefox.ogv" abzuspielen. Wir benutzen CSS, um zu verhindern, dass das Video angezeigt wird:

- -
video {
-  display: none;
-}
-
- -

Dann schenken wir dem JavaScript Code wieder unsere Aufmerksamkeit und fügen eine neue Zeile zur start() Funktion hinzu, um einen Bezug zum Video-Element herzustellen:

- -
videoElement = document.getElementById("video");
-
- -

Und wir ersetzen den Code, der die Intervall-gesteuerten Aufrufe von drawScene() setzt, mit diesem Code:

- -
videoElement.addEventListener("canplaythrough", startVideo, true);
-videoElement.addEventListener("ended", videoDone, true);
-
- -

Die Idee ist hier, dass wir die Animation nicht starten wollen, bevor das Video nicht ausreichend zwischengespeichert wurde, sodass es dann ohne Unterbrechung abgespielt werden kann. Wir fügen also einen Event-Listener hinzu, um auf das video Element zu warten bis es uns mitteilt, dass genug zwischengespeichert wurde und das komplette Video ohne Pause abgespielt werden kann. Wir fügen außerdem einen zweiten Event-Listener hinzu, sodass wir die Animation stoppen können, wenn das Video beendet ist und wir so nicht unnötig den Prozessor belasten.

- -

Die startVideo() Funktion sieht so aus:

- -
function startVideo() {
-  videoElement.play();
-  videoElement.addEventListener("timeupdate", updateTexture, true);
-  setInterval(drawScene, 15);
-}
-
- -

Hier wird einfach das Video gestartet und ein Event-Handler bereitgestellt, der aufgerufen wird, wenn ein neuer Frame des Videos verfügbar ist. Dann werden die Intervall-gesteuerten Aufrufe der drawScene() Funktion eingerichtet, um den Würfel zu rendern.

- -

Die videoDone() Funktion ruft einfach {{ domxref("window.clearInterval") }} auf, um die Intervallaufrufe zu beenden, die die Animation aktualisieren.

- -

Die Video-Frames als Textur verwenden

- -

Die nächste Änderung erhält die initTexture() Funktion, welche viel einfacher wird, weil kein Bild mehr geladen werden muss. Stattdessen muss nun das Textur-Mapping aktiviert werden und ein leeres Textur-Objekt zum späteren Gebrauch erstellt werden:

- -
function initTextures() {
-  gl.enable(gl.TEXTURE_2D);
-  cubeTexture = gl.createTexture();
-}
-
- -

So sieht die updateTexture() Funktion aus. Hier wird wirklich Arbeit verrichtet:

- -
function updateTexture() {
-  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
-  gl.texImage2D(gl.TEXTURE_2D, 0, videoElement, true);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-  gl.generateMipmap(gl.TEXTURE_2D);
-  gl.bindTexture(gl.TEXTURE_2D, null);
-}
-
- -

Sie kennen diesen Code bereits. Es ist fast identisch zur handleTextureLoaded() Routine im vorherigen Beispiel, mit der Ausnahme, dass wir texImage2D() nicht mit einem Image Objekt sondern mit dem video Element aufrufen.

- -

updateTexture() wird jedes Mal aufgerufen, wenn sich das timeupdate Event vom video Element meldet. Dieses Event wird gesendet, wenn sich die Zeit des aktuellen Frames ändert, sodass wir wissen, dass wir unsere Textur nur dann aktualisieren müssen, wenn neue Daten verfügbar sind.

- -

Das war alles! Wenn Sie eine Browser mit Unterstützung von WebGL verwenden, können Sie sich das Beispiel in Aktion ansehen.

- -

Siehe auch

- - - -

{{Previous("Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

diff --git a/files/de/web/api/webgl_api/tutorial/beleuchtung_in_webgl/index.html b/files/de/web/api/webgl_api/tutorial/beleuchtung_in_webgl/index.html deleted file mode 100644 index bd65b5bb40..0000000000 --- a/files/de/web/api/webgl_api/tutorial/beleuchtung_in_webgl/index.html +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Beleuchtung in WebGL -slug: Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Lighting_in_WebGL ---- -

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden", "Web/API/WebGL_API/Tutorial/Animierte_Texturen_in_WebGL")}}

- -

Als Erstes sollten wir verstehen, dass WebGL nicht wie OpenGL über eine eigene Unterstützung für die Beleuchtung verfügt. Das müssen wir selbst machen. Glücklicherweise ist es nicht sehr schwer und dieser Artikel versucht Ihnen die Grundlagen dazu näher zu bringen.

- -

Beleuchtung und Schattierung simulieren

- -

Obwohl wir nicht weiter ins Detail über die Theorie hinter simulierter Beleuchtung in 3D Grafiken gehen wollen, was außerdem weit über diesen Artikel hinaus gehen würde, ist es gut zu wissen wie es ungefähr funktioniert. Anstatt hier nun in aller Tiefe zu diskutieren, sollten Sie einen Blick auf den »Phong Shading« Artikel auf Wikipedia werfen, welcher einen guten Überblick über das meist genutzte Beleuchtungsmodell liefert.

- -

Es gibt drei grundlegende Typen zur Beleuchtung:

- -

Umgebungslicht ist das Licht, das die Szene umgibt. Es weist in keine Richtung und bestrahlt jede Oberfläche in gleicher Weise, egal in welche Richtung es zeigt.

- -

Gerichtetes Licht ist das Licht, das von einer festgelegten Richtung ausgestrahlt wird. Dieses Licht ist so weit weg, sodass sich jeder Photon parallel zu jedem anderen Photon bewegt. Sonnenlicht ist zum Beispiel gerichtetes (direktionales) Licht.

- -

Punktbeleuchtung ist das Licht, das von einem Punkt ausgestrahlt wird und von dort radial in alle Richtungen verläuft. So funktionieren zum Beispiel die Glühbirnen im Alltag.

- -

Für unsere Zwecke vereinfachen wir das Beleuchtungsmodell, indem wir nur gerichtetes Licht und Umgebungslicht betrachten. Wir haben hier keine Highlights, die wir mit Punktbeleuchtung oder Glanzlicht in dieser Szene hervorheben wollen. Stattdessen werden wir Umgebungslicht mit einem einzelnen, gerichteten Licht verwenden, welches auf den rotierenden Würfel aus der vorherigen Demo zeigt.

- -

Wenn Sie die Konzepte der Punktbeleuchtung und des Glanzlichtes hinter sich gelassen haben, gibt es dennoch zwei kleine Informationen, die Sie benötigen werden, wenn wir unser gerichtetes Licht implementieren:

- -
    -
  1. Wir müssen die Oberflächennormale mit jedem Vertex verbinden. Das ist ein Vektor, der senkrecht zur Oberfläche des Vertex ist.
  2. -
  3. Wir müssen die Richtung in welche das Licht strahlt wissen. Diese wird durch den Richtungsvektor angegeben.
  4. -
- -

Dann aktualisieren wir den Vertex-Shader, um die Farbe jedes Vertices, unter Berücksichtigung des Umgebungslichts und dem Effekt des gerichteten Lichts (sowie dessen Winkel mit dem es auf die Oberfläche trifft), einzustellen. Wir werden sehen, wie genau wir das machen, wenn wir einen Blick auf den Code für den Shader werfen.

- -

Die Normalen für die Vertices erstellen

- -

Als Erstes müssen wir einen Array für die Normalen für alle Vertices erstellen, die unseren Würfel umfassen. Da ein Würfel ein sehr einfaches Objekt ist, ist dies auch sehr einfach zu erstellen. Für komplexere Objekte wird das Berechnen der Normalen schon umfassender.

- -
  cubeVerticesNormalBuffer = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);
-
-  var vertexNormals = [
-    // vorne
-     0.0,  0.0,  1.0,
-     0.0,  0.0,  1.0,
-     0.0,  0.0,  1.0,
-     0.0,  0.0,  1.0,
-
-    // hinten
-     0.0,  0.0, -1.0,
-     0.0,  0.0, -1.0,
-     0.0,  0.0, -1.0,
-     0.0,  0.0, -1.0,
-
-    // oben
-     0.0,  1.0,  0.0,
-     0.0,  1.0,  0.0,
-     0.0,  1.0,  0.0,
-     0.0,  1.0,  0.0,
-
-    // unten
-     0.0, -1.0,  0.0,
-     0.0, -1.0,  0.0,
-     0.0, -1.0,  0.0,
-     0.0, -1.0,  0.0,
-
-    // rechts
-     1.0,  0.0,  0.0,
-     1.0,  0.0,  0.0,
-     1.0,  0.0,  0.0,
-     1.0,  0.0,  0.0,
-
-    // links
-    -1.0,  0.0,  0.0,
-    -1.0,  0.0,  0.0,
-    -1.0,  0.0,  0.0,
-    -1.0,  0.0,  0.0
-  ];
-
-  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertexNormals), gl.STATIC_DRAW);
-
- -

Das sollte Ihnen schon bekannt vorkommen: Wir erstellen einen neuen Buffer, verknüpfen den Array damit und senden dann unseren Vertex-Normalen-Array in den Buffer, indem wir bufferData() aufrufen.

- -

Dann fügen wir Code zu drawScene() hinzu, um das Normalen-Array mit einem Shader-Attribut zu verknüpfen, sodass der Shader-Code darauf zugreifen kann:

- -
  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);
-  gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
-
- -

Schließlich müssen wir den Code aktualisieren, welcher die Einheitsmatrizen erstellt, um eine Normalenmatrix zu generieren und zum Shader auszuliefern. Diese wird verwendet, um die Normalen umzuwandeln, wenn die aktuelle Orientierung des Würfels in Beziehung zur Lichtquelle behandelt wird:

- -
  var normalMatrix = mvMatrix.inverse();
-  normalMatrix = normalMatrix.transpose();
-  var nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");
-  gl.uniformMatrix4fv(nUniform, false, new WebGLFloatArray(normalMatrix.flatten()));
-
- -

Die Shader aktualisieren

- -

Jetzt sind alle Daten, die von den Shadern gebraucht werden, verfügbar. Wir müssen nun den Code in den Shadern selbst aktualisieren.

- -

Der Vertex-Shader

- -

Zunächst aktualisieren wir den Vertex-Shader, sodass dieser einen Schattenwert für jeden Vertex auf Basis des Umgebungslichts sowie des direktionalen Lichts berechnet. Werfen wir einen Blick auf den Code:

- -
    <script id="shader-vs" type="x-shader/x-vertex">
-      attribute vec3 aVertexNormal;
-      attribute vec3 aVertexPosition;
-      attribute vec2 aTextureCoord;
-
-      uniform mat4 uNormalMatrix;
-      uniform mat4 uMVMatrix;
-      uniform mat4 uPMatrix;
-
-      varying vec2 vTextureCoord;
-      varying vec3 vLighting;
-
-      void main(void) {
-        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
-        vTextureCoord = aTextureCoord;
-
-        // Beleuchtungseffekt anwenden
-
-        vec3 ambientLight = vec3(0.6, 0.6, 0.6);
-        vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);
-        vec3 directionalVector = vec3(0.85, 0.8, 0.75);
-
-        vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
-
-        float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
-        vLighting = ambientLight + (directionalLightColor * directional);
-      }
-    </script>
-
- -

Sobald die Position des Vertex berechnet wurde und wir die Koordinaten des Texels (welcher passend zum Vertex ist) erhalten haben, können wir den Schatten für den Vertex berechnen.

- -

Als Erstes wandeln wir die Normale auf Basis der aktuellen Position und Orientierung des Würfels um, indem wir die Normale des Vertexes mit der Normalenmatrix multiplizieren. Dann können wir den Betrag an direktionalem Licht, welcher auf den Vertex angewendet werden soll, berechnen, indem wir das Skalarprodukt der umgewandelten Normalen und des direktionalen Vektors (Richtung aus der das Licht kommt) bilden. Wenn dieser Wert kleiner als Null ist, setzen wir den Wert auf Null fest, da man nicht weniger als Null Licht haben kann.

- -

Wenn der Betrag des direktionalen Lichts berechnet wurde, können wir den Beleuchtungswert generieren, indem wir das Umgebungslicht nehmen und das Produkt der Farbe des direktionalen Lichts und den Betrag an direktionalem Licht bereitstellen. Als Ergebnis haben wir nun einen RGB-Wert, welcher vom Fragment-Shader verwendet wird, um die Farbe jedes Pixels den wir rendern einzustellen.

- -

Der Fragment-Shader

- -

Der Fragment-Shader muss nun aktualisiert werden, um den berechneten Beleuchtungswert vom Vertex-Shader zu berücksichtigen:

- -
    <script id="shader-fs" type="x-shader/x-fragment">
-      varying vec2 vTextureCoord;
-      varying vec3 vLighting;
-
-      uniform sampler2D uSampler;
-
-      void main(void) {
-        vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
-
-        gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);
-      }
-    </script>
-
- -

Hier erhalten wir nun die Farbe des Texels, genau so wie wir es im vorherigen Beispiel getan haben. Bevor wir die Farbe der Fragmente aber festlegen, multiplizieren wir die Texel-Farbe mit dem Beleuchtungswert, um die Texel-Farbe so einzustellen, dass diese den Effekt der Lichtquelle berücksichtigt.

- -

Und das war's! Wenn Sie einen Browser verwenden, der WebGL unterstützt, können Sie einen Blick auf die Live-Demo werfen.

- -

Übungen für den Leser

- -

Dies ist natürlich ein sehr einfaches Beispiel, welches eine Beleuchtung pro Vertex implementiert. Für fortgeschrittene Grafiken, möchten Sie sicher eine Beleuchtung pro Pixel implementieren, aber dies wird Sie in die Richtung leiten.

- -

Sie können nun also versuchen mit der Richtung der Lichtquelle zu experimentieren, die Farbe der Leuchtquelle zu ändern und so weiter.

- -

{{PreviousNext("Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden", "Web/API/WebGL_API/Tutorial/Animierte_Texturen_in_WebGL")}}

diff --git a/files/de/web/api/webgl_api/tutorial/creating_3d_objects_using_webgl/index.html b/files/de/web/api/webgl_api/tutorial/creating_3d_objects_using_webgl/index.html new file mode 100644 index 0000000000..d3a21591fd --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/creating_3d_objects_using_webgl/index.html @@ -0,0 +1,126 @@ +--- +title: 3D-Objekte mit WebGL erstellen +slug: Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren", "Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden")}}

+ +

Bringen wir unser Quadrat in die dritte Dimension, indem wir fünf oder mehr Flächen hinzufügen und daraus einen Würfel machen. Um das effizient zu machen, wechseln wir vom Zeichnen direkt über die Vertices zur gl.drawArray() Methode, um den Vertex-Array als eine Tabelle zu verwenden und die einzelnen Vertices in dieser Tabelle als Referenz für Positionen jeder Fläche zu definieren, indem wir gl.drawElements() aufrufen.

+ +

Bedenken Sie: Jede Fläche benötigt vier Vertices, die diese definieren, aber jeder Vertex wird von drei Flächen verwendet. Wir können eine Menge Daten sparen, indem wir eine Liste aller 24 Vertices erstellen und uns dann auf jeden Vertex durch dessen Index in der Liste beziehen, anstatt den gesamten Koordinatensatz zu verwenden.

+ +

Die Vertex-Positionen des Würfels definieren

+ +

Zunächst wollen wir den Positionsspeicher der Vertices erstellen, indem wir den Code in initBuffers() ändern. Das geschieht genau so wie für das Quadrat, allerdings haben wir hier ein paar Datensätze mehr, da wir 24 Vertices (4 pro Seite) haben müssen:

+ +
  var vertices = [
+    // vordere Fläche
+    -1.0, -1.0,  1.0,
+     1.0, -1.0,  1.0,
+     1.0,  1.0,  1.0,
+    -1.0,  1.0,  1.0,
+
+    // hintere Fläche
+    -1.0, -1.0, -1.0,
+    -1.0,  1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0, -1.0, -1.0,
+
+    // obere Fläche
+    -1.0,  1.0, -1.0,
+    -1.0,  1.0,  1.0,
+     1.0,  1.0,  1.0,
+     1.0,  1.0, -1.0,
+
+    // untere Fläche
+    -1.0, -1.0, -1.0,
+     1.0, -1.0, -1.0,
+     1.0, -1.0,  1.0,
+    -1.0, -1.0,  1.0,
+
+    // rechte Fläche
+     1.0, -1.0, -1.0,
+     1.0,  1.0, -1.0,
+     1.0,  1.0,  1.0,
+     1.0, -1.0,  1.0,
+
+    // linke Fläche
+    -1.0, -1.0, -1.0,
+    -1.0, -1.0,  1.0,
+    -1.0,  1.0,  1.0,
+    -1.0,  1.0, -1.0
+  ];
+
+ +

Die Farben der Vertices definieren

+ +

Außerdem müssen wir einen Array für die Farben der 24 Vertices erstellen. Dieser Code definiert zunächst die Farben für jede Fläche und verwendet dann eine Schleife, um jeden der Vertices mit einer Farbe zu bestücken.

+ +
  var colors = [
+    [1.0,  1.0,  1.0,  1.0],    // vordere Fläche: weiß
+    [1.0,  0.0,  0.0,  1.0],    // hintere Fläche: rot
+    [0.0,  1.0,  0.0,  1.0],    // obere Fläche: grün
+    [0.0,  0.0,  1.0,  1.0],    // untere Fläche: blau
+    [1.0,  1.0,  0.0,  1.0],    // rechte Fläche: gelb
+    [1.0,  0.0,  1.0,  1.0]     // linke Fläche: violett
+  ];
+
+  var generatedColors = [];
+
+  for (j=0; j<6; j++) {
+    var c = colors[j];
+
+    for (var i=0; i<4; i++) {
+      generatedColors = generatedColors.concat(c);
+    }
+  }
+
+  cubeVerticesColorBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer);
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(generatedColors), gl.STATIC_DRAW);
+
+ +

Das Element-Array definieren

+ +

Sobald die Vertex-Arrays generiert worden sind, müssen wir das Element-Array erstellen.

+ +
  cubeVerticesIndexBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
+
+  // Dieser Array definiert jede Fläche als zwei Dreiecke über die Indizes
+  // im Vertex-Array, um die Position jedes Dreiecks festzulegen.
+
+  var cubeVertexIndices = [
+    0,  1,  2,      0,  2,  3,    // vorne
+    4,  5,  6,      4,  6,  7,    // hinten
+    8,  9,  10,     8,  10, 11,   // oben
+    12, 13, 14,     12, 14, 15,   // unten
+    16, 17, 18,     16, 18, 19,   // rechts
+    20, 21, 22,     20, 22, 23    // links
+  ]
+
+  // Sende nun das Element-Array zum GL
+
+  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+      new WebGLUnsignedShortArray(cubeVertexIndices), gl.STATIC_DRAW);
+
+ +

Das cubeVertexIndices Array definiert jede Fläche als ein paar von Dreiecken, alle Vertices des Dreiecks werden als ein Index im Vertex-Array des Würfels festgelegt. Daher ist der Würfel aus einer Sammlung von 12 Dreiecken beschrieben.

+ +

Den Würfel zeichnen

+ +

Als nächstes müssen wir etwas Code zur drawScene() Funktion hinzufügen, um über den Indexspeicher des Würfels zu zeichnen. Wir fügen neue bindBuffer() und drawElements() Aufrufe hinzu:

+ +
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer);
+  setMatrixUniforms();
+  gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+
+ +

Da jede Seite unseres Würfels aus zwei Dreiecken besteht, gibt es 6 Vertices pro Seite, oder 36 Vertices im Würfel, obwohl einige davon doppelt sind. Da unser Index-Array jedoch aus einfachen Integern besteht, stellt dies keinen unkoordinierbaren Betrag an Daten dar, welcher für jeden Frame der Animation durchgegangen werden muss.

+ +

Jetzt haben wir einen animierten Würfel, welcher herum springt, rotiert und über sechs unterschiedliche Seiten verfügt. Wenn Ihr Browser WebGL unterstützt, schauen Sie sich hier die Demo in Aktion an.

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren", "Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden")}}

diff --git "a/files/de/web/api/webgl_api/tutorial/einf\303\274hrung_in_webgl/index.html" "b/files/de/web/api/webgl_api/tutorial/einf\303\274hrung_in_webgl/index.html" deleted file mode 100644 index 5906f95761..0000000000 --- "a/files/de/web/api/webgl_api/tutorial/einf\303\274hrung_in_webgl/index.html" +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Einführung in WebGL -slug: Web/API/WebGL_API/Tutorial/Einführung_in_WebGL -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL ---- -

{{WebGLSidebar("Tutorial")}} {{Next("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext")}}

- -

Mit WebGL steht eine API zur Verfügung, die auf OpenGL ES 2.0 basiert, um 3D Rendering im HTML canvas Element zu ermöglichen. WebGL Programme bestehen aus Steuercode in JavaScript und Shadercode (GLSL), der auf dem Grafikprozessor (GPU) des Computers ausgeführt wird. WebGL Elemente können mit anderen HTML Elementen kombiniert werden.

- -

Dieser Artikel ist eine Einführung in die Grundlagen von WebGL. Es wird vorausgesetzt, dass einige mathematischen Kenntnisse im 3D-Bereich (Matrizen) vorhanden sind. Dieser Artikel wird daher keine 3D-Grafik-Konzepte vermitteln. Es gibt einen anfängergeeigneten Leitfaden mit Programmieraufgaben in unserem Lernbereich: Learn WebGL for 2D and 3D graphics.

- -

DIe hier verwendeten Codebeispiele finden sich auch im webgl-examples GitHub repository.

- -

3D Rendering vorbereiten

- -

Um WebGL benutzen zu können, wird als erstes ein canvas Element benötigt. Der folgende HTML-Code definiert eine canvas Zeichenfläche.

- -
<body>
-  <canvas id="glCanvas" width="640" height="480"></canvas>
-</body>
-
- -

Vorbereitung des WebGL-Kontexts

- -

Die main() Funktion im JavaScript Code wird aufgerufen, nachdem das Dokument geladen wurde. Die Aufgabe der Funktion ist, den WebGL-Kontext festzulegen und mit dem Rendering zu beginnen.

- -
main();
-
-function main() {
-  const canvas = document.querySelector("#glCanvas");
-  // Initialisierung des GL Kontexts
-  const gl = canvas.getContext("webgl");
-
-  // Nur fortfahren, wenn WebGL verfügbar ist und funktioniert
-  if (!gl) {
-    alert("Unable to initialize WebGL. Your browser or machine may not support it.");
-    return;
-  }
-
-  // Setze clear color auf schwarz, vollständig sichtbar
-  gl.clearColor(0.0, 0.0, 0.0, 1.0);
-  // Lösche den color buffer mit definierter clear color
-  gl.clear(gl.COLOR_BUFFER_BIT);
-}
- -

Als erstes verschaffen wir uns eine Referenz zum canvas Element und speichern sie in der canvas Variable.

- -

Sobald wir den Bezug zum canvas haben, versuchen wir einen zugehörigen  WebGLRenderingContext zu erhalten, indem wir getContext aufrufen und dabei den String "webgl" mitgeben. Falls der Browser WebGL nicht unterstützt, wird getContext null zurückgeben, woraufhin wir den Nutzer benachrichtigen und das Script verlassen.

- -

Wenn der Kontext erfolgreich initialisiert wurde, ist gl eine Variable für den Kontext. In diesem Fall setzen wir die clear color auf schwarz, und löschen den zugehörigen Kontext (der canvas wird mit der Hintergrundfarbe neu gezeichnet)

- -

An dieser Stelle ist genug Code vorhanden, um den WebGL-Kontext erfolgreich zu initialisieren. Ein großer, leerer, schwarzer Kasten sollte zu sehen sein, der darauf wartet mit weiteren Inhalten gefüttert zu werden.

- -

{{EmbedGHLiveSample('webgl-examples/tutorial/sample1/index.html', 670, 510) }}

- -

Vollständigen Code ansehen | Demo in neuer Seite öffnen

- -

Siehe auch

- -

 

- - - -

 

- -

{{Next("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext")}}

diff --git "a/files/de/web/api/webgl_api/tutorial/farben_mittels_shader_in_einen_webgl-kontext_hinzuf\303\274gen/index.html" "b/files/de/web/api/webgl_api/tutorial/farben_mittels_shader_in_einen_webgl-kontext_hinzuf\303\274gen/index.html" deleted file mode 100644 index 94068822d5..0000000000 --- "a/files/de/web/api/webgl_api/tutorial/farben_mittels_shader_in_einen_webgl-kontext_hinzuf\303\274gen/index.html" +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Farben mittels Shader in einen WebGL-Kontext hinzufügen -slug: >- - Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL ---- -

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext", "Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren")}}

- -

Wir haben ein simples Quadrat im vorherigen Teil erstellt, im nächsten Schritt wollen wir ein bisschen Farbe ins Spiel bringen. Dafür sind Änderungen an den Shadern erforderlich.

- -

Farben zu den Eckpunkten hinzufügen

- -

In der Computergrafik werden Objekte mit einer Reihe von Punkten erstellt. Jeder Punkt hat eine Position und eine Farbe. Standardmäßig werden alle anderen Pixelfarben (und alle weiteren Attribute, darunter die Position) über eine lineare Interpolation berechnet, die automatisch glatte Verläufe erstellt. Vorher hat unser Vertex-Shader keine festgelegten Farben auf die Punkte (Vertices) angewendet und der Fragment-Shader legte die feste Farbe weiß für jeden Pixel fest, sodass das gesamte Quadrat komplett weiß gezeichnet wurde.

- -

Nun wollen wir in jeder Ecke des Quadrats einen Verlauf in einer unterschiedlichen Farbe rendern: rot, blau, grün und weiß. Als erstes sollten wir daher diese Farben in den vier Eckpunkten einrichten. Um das zu machen, müssen wir zunächst einen Array der Vertex-Farben erstellen und diesen dann in einen WebGL Buffer speichern. Das erreichen wir durch die folgenden Zeilen in unserer initBuffers() Funktion:

- -
var colors = [
-  1.0,  1.0,  1.0,  1.0,    // weiß
-  1.0,  0.0,  0.0,  1.0,    // rot
-  0.0,  1.0,  0.0,  1.0,    // grün
-  0.0,  0.0,  1.0,  1.0     // blau
-];
-
-squareVerticesColorBuffer = gl.createBuffer();
-gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
-gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
-}
-
- -

Dieser Code definiert zuerst einen JavaScript Array, welcher die vier Farb-Vektoren mit jeweils vier Werten für die jeweilige Farbe enthält. Dann wird ein neuer WebGL Buffer angewiesen diese Farben zu speichern und der Array wird in WebGL Floats konvertiert und im Buffer gespeichert.

- -

Um die Farben schließlich zu verwenden, muss der der Vertex-Shader aktualisiert werden, um die entsprechende Farbe vom Farb-Buffer zu erhalten:

- -
<script id="shader-vs" type="x-shader/x-vertex">
-  attribute vec3 aVertexPosition;
-  attribute vec4 aVertexColor;
-
-  uniform mat4 uMVMatrix;
-  uniform mat4 uPMatrix;
-
-  varying vec4 vColor;
-
-  void main(void) {
-    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
-    vColor = aVertexColor;
-  }
-</script>
-
- -

Der wichtigste Unterschied ist hier, dass wir für jeden Punkt (Vertex) die Farbe entsprechend des Farb-Arrays setzen.

- -

Die Fragmente mit Farben versehen

- -

Als Erinnerung, so sah unser Fragment-Shader vorher aus:

- -
<script id="shader-fs" type="x-shader/x-fragment">
-  void main(void) {
-    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
-  }
-</script>
-
- -

Um nun die interpolierte Farbe für jeden Pixel aufzugreifen, müssen wir dies einfach so ändern, dass wir den Wert der vColor Variable erhalten:

- -
<script id="shader-fs" type="x-shader/x-fragment">
-  varying vec4 vColor;
-
-  void main(void) {
-    gl_FragColor = vColor;
-  }
-</script>
-
- -

Das ist eine sehr einfache Änderung. Anstatt des festen Wertes vorher, erhält jedes Fragment jetzt einfach die interpolierte Farbe, basierend auf der Position relativ zu den Kontenpunkten (Vertices).

- -

Mit den Farben zeichnen

- -

Als nächstes ist es nötig, Code zur initShaders() Routine hinzuzufügen, um das Farbattribut für das Shader-Programm zu initialisieren:

- -
  vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
-  gl.enableVertexAttribArray(vertexColorAttribute);
-
- -

Dann wird drawScene() abgeändert, um schließlich die Farben zu verwenden, wenn das Quadrat gezeichnet wird:

- -
  gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
-  gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
-
- -

Jetzt sollten Sie das Beispiel in einem WebGL kompatiblen Browser sehen und Ihre Ausgabe sollte so wie im Bild unten gezeichnet werden (das Quadrat ist innerhalb eines schwarzen Felds zu sehen):

- -

screenshot.png

- -

{{PreviousNext("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext", "Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren")}}

diff --git a/files/de/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html b/files/de/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html new file mode 100644 index 0000000000..5906f95761 --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html @@ -0,0 +1,73 @@ +--- +title: Einführung in WebGL +slug: Web/API/WebGL_API/Tutorial/Einführung_in_WebGL +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{Next("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext")}}

+ +

Mit WebGL steht eine API zur Verfügung, die auf OpenGL ES 2.0 basiert, um 3D Rendering im HTML canvas Element zu ermöglichen. WebGL Programme bestehen aus Steuercode in JavaScript und Shadercode (GLSL), der auf dem Grafikprozessor (GPU) des Computers ausgeführt wird. WebGL Elemente können mit anderen HTML Elementen kombiniert werden.

+ +

Dieser Artikel ist eine Einführung in die Grundlagen von WebGL. Es wird vorausgesetzt, dass einige mathematischen Kenntnisse im 3D-Bereich (Matrizen) vorhanden sind. Dieser Artikel wird daher keine 3D-Grafik-Konzepte vermitteln. Es gibt einen anfängergeeigneten Leitfaden mit Programmieraufgaben in unserem Lernbereich: Learn WebGL for 2D and 3D graphics.

+ +

DIe hier verwendeten Codebeispiele finden sich auch im webgl-examples GitHub repository.

+ +

3D Rendering vorbereiten

+ +

Um WebGL benutzen zu können, wird als erstes ein canvas Element benötigt. Der folgende HTML-Code definiert eine canvas Zeichenfläche.

+ +
<body>
+  <canvas id="glCanvas" width="640" height="480"></canvas>
+</body>
+
+ +

Vorbereitung des WebGL-Kontexts

+ +

Die main() Funktion im JavaScript Code wird aufgerufen, nachdem das Dokument geladen wurde. Die Aufgabe der Funktion ist, den WebGL-Kontext festzulegen und mit dem Rendering zu beginnen.

+ +
main();
+
+function main() {
+  const canvas = document.querySelector("#glCanvas");
+  // Initialisierung des GL Kontexts
+  const gl = canvas.getContext("webgl");
+
+  // Nur fortfahren, wenn WebGL verfügbar ist und funktioniert
+  if (!gl) {
+    alert("Unable to initialize WebGL. Your browser or machine may not support it.");
+    return;
+  }
+
+  // Setze clear color auf schwarz, vollständig sichtbar
+  gl.clearColor(0.0, 0.0, 0.0, 1.0);
+  // Lösche den color buffer mit definierter clear color
+  gl.clear(gl.COLOR_BUFFER_BIT);
+}
+ +

Als erstes verschaffen wir uns eine Referenz zum canvas Element und speichern sie in der canvas Variable.

+ +

Sobald wir den Bezug zum canvas haben, versuchen wir einen zugehörigen  WebGLRenderingContext zu erhalten, indem wir getContext aufrufen und dabei den String "webgl" mitgeben. Falls der Browser WebGL nicht unterstützt, wird getContext null zurückgeben, woraufhin wir den Nutzer benachrichtigen und das Script verlassen.

+ +

Wenn der Kontext erfolgreich initialisiert wurde, ist gl eine Variable für den Kontext. In diesem Fall setzen wir die clear color auf schwarz, und löschen den zugehörigen Kontext (der canvas wird mit der Hintergrundfarbe neu gezeichnet)

+ +

An dieser Stelle ist genug Code vorhanden, um den WebGL-Kontext erfolgreich zu initialisieren. Ein großer, leerer, schwarzer Kasten sollte zu sehen sein, der darauf wartet mit weiteren Inhalten gefüttert zu werden.

+ +

{{EmbedGHLiveSample('webgl-examples/tutorial/sample1/index.html', 670, 510) }}

+ +

Vollständigen Code ansehen | Demo in neuer Seite öffnen

+ +

Siehe auch

+ +

 

+ + + +

 

+ +

{{Next("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext")}}

diff --git "a/files/de/web/api/webgl_api/tutorial/hinzuf\303\274gen_von_2d_inhalten_in_einen_webgl-kontext/index.html" "b/files/de/web/api/webgl_api/tutorial/hinzuf\303\274gen_von_2d_inhalten_in_einen_webgl-kontext/index.html" deleted file mode 100644 index 56c267f394..0000000000 --- "a/files/de/web/api/webgl_api/tutorial/hinzuf\303\274gen_von_2d_inhalten_in_einen_webgl-kontext/index.html" +++ /dev/null @@ -1,238 +0,0 @@ ---- -title: Hinzufügen von 2D Inhalten in einen WebGL-Kontext -slug: Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext -tags: - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context ---- -

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Einführung_in_WebGL", "Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen")}}

- -

Sobald der WebGL-Kontext erfolgreich erstellt wurde, können wir anfangen darin zu rendern. Am einfachsten beginnen wir mit einem einfachen, zweidimensionalen, untextuierten Objekt. Fangen wir also damit an, ein Stück Code zu schreiben, um ein Quadrat zu zeichnen.

- -

Hinweis zur deutschen Übersetzung dieses Abschnitts

- -

Die deutsche Übersetzung bezieht sich auf ältere Version des Beispielcodes als der englische Originaltext. Der im deutschen Text beschriebene Code hat einige Probleme:

- - - -

Um das Beispiel selber nachzuprogrammieren ist es daher empfehlenswert, auf die englische Version des Tutorials zu wechseln. Vielleicht haben Sie ja auch Lust, diese Version ins Deutsche zu übersetzen?

- -

Beleuchtung der Szene

- -

Das Wichtigste, das wir verstehen müssen bevor wir anfangen können, ist, dass wir, uns bereits in einer dreidimensionalen Umgebung befinden, obwohl wir nur ein zweidimensionales Objekt in diesem Beispiel rendern wollen. Das heißt, wir müssen jetzt bereits Shader einsetzen, die unsere einfache Szene beleuchten und solche erstellen, die unser Objekt zeichnen. Diese Shader werden festlegen wie unser Quadrat später beleuchtet sein wird.

- -

Initialisierung der Shader

- -

Shader sind durch die OpenGL ES Shading Language (pdf) spezifiziert. Damit es einfacher ist unsere Inhalte zu warten und zu aktualisieren, können wir unseren Code so schreiben, dass die Shader im HTML Dokument gefunden werden, anstatt alles mittels JavaScript zu bauen. Werfen wir einen Blick auf unsere initShaders() Routine, welche diese Aufgabe übernimmt:

- -
function initShaders() {
-  var fragmentShader = getShader(gl, "shader-fs");
-  var vertexShader = getShader(gl, "shader-vs");
-
-  // Erzeuge Shader
-
-  shaderProgram = gl.createProgram();
-  gl.attachShader(shaderProgram, vertexShader);
-  gl.attachShader(shaderProgram, fragmentShader);
-  gl.linkProgram(shaderProgram);
-
-  // Wenn die das Aufrufen der Shader fehlschlägt,
-  // gib eine Fehlermeldung aus:
-
-  if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
-    alert("Initialisierung des Shaderprogramms nicht möglich.");
-  }
-
-  gl.useProgram(shaderProgram);
-
-  vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
-  gl.enableVertexAttribArray(vertexPositionAttribute);
-}
-
-
- -

Es werden zwei Shader in dieser Routine geladen; der Erste, der fragmentShader, wird vom script Element mit der Id "shader-fs" geladen. Der Zweite, der vertexShader, wird vom script Element mit der Id "shader-vs" geladen. Wir werden im nächsten Abschnitt noch näher auf die getShader() Funktion eingehen. Diese Routine holt sich dann die Shader aus dem DOM.

- -

In diesem Teil erstellen wir noch das Shaderprogramm, in dem wir die Funktion createProgram() aufrufen, die beiden Shader anhängen und das Shaderprogramm verlinken. Danach wird der Zustand des LINK_STATUS Parameters überprüft, um sicher zu gehen, dass das Programm erfolgreich verlinkt wurde. Wenn das der Fall ist, aktivieren wir das neue Shaderprogramm.

- -

Shader aus dem DOM laden

- -

Die getShader() Routine ruft ein Shaderprogramm mit dem festgelegtem Namen aus dem DOM auf, gibt das kompilierte Shaderprogramm zurück oder ist leer, wenn nichts geladen oder kompiliert worden konnte.

- -
function getShader(gl, id) {
-  var shaderScript = document.getElementById(id);
-
-  if (!shaderScript) {
-    return null;
-  }
-
-  var theSource = "";
-  var currentChild = shaderScript.firstChild;
-
-  while(currentChild) {
-    if (currentChild.nodeType == 3) {
-      theSource += currentChild.textContent;
-    }
-
-    currentChild = currentChild.nextSibling;
-  }
- -

Wenn das Element mit der festgelegten Id gefunden wurde, wird der Text in die Variable theSource gespeichert.

- -
  var shader;
-
-  if (shaderScript.type == "x-shader/x-fragment") {
-    shader = gl.createShader(gl.FRAGMENT_SHADER);
-  } else if (shaderScript.type == "x-shader/x-vertex") {
-    shader = gl.createShader(gl.VERTEX_SHADER);
-  } else {
-    return null;  // Unbekannter Shadertyp
-  }
- -

Jetzt wo der Code für die Shader gelesen wurde, können wir uns die MIME Typen der Shader angucken, um festzulegen, ob es ein Vertex-Shader (MIME Typ: "x-shader/x-vertex") oder ein Fragment-Shader (MIME Typ: "x-shader/x-fragment") ist. Danach werden dann die entsprechenden Shadertypen erstellt.

- -
  gl.shaderSource(shader, theSource);
-
-  // Kompiliere das Shaderprogramm
-
-  gl.compileShader(shader);
-
-  // Überprüfe, ob die Kompilierung erfolgreich war
-
-  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
-    alert("Es ist ein Fehler beim Kompilieren der Shader aufgetaucht: " + gl.getShaderInfoLog(shader));
-    return null;
-  }
-
-  return shader;
-}
-
- -

Schließlich wird der Shader kompiliert. Falls ein Fehler während der Kompilierung auftritt, zeigen wir die Fehlermeldung an und geben null zurück. Andernfalls wird der kompilierte Shader zurückgegeben.

- -

Die Shader

- -

Nun müssen wir die eigentlichen Shaderprogramme in unser HTML schreiben. Wie genau diese Shader arbeiten, übersteigt das Ziel dieses Tutorials, wir gehen daher nur auf das Wesentliche ein.

- -

Fragment-Shader

- -

Jeder Pixel in einem Vieleck wird Fragment in der GL-Fachsprache genannt. Die Aufgabe des Fragment-Shaders ist es, die Farbe für jeden Pixel bereitzustellen. In unserem Fall ordnen wir einfach jedem Pixel eine weiße Farbe zu.

- -

gl_FragColor ist eine eingebaute GL Variable, die für die Farbe des Fragments verwendet wird.

- -
<script id="shader-fs" type="x-shader/x-fragment">
-
-  void main(void) {
-    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
-  }
-</script>
-
- -

Vertex-Shader

- -

Der Vertex-Shader definiert die Position und Form von jedem Punkt.

- -
<script id="shader-vs" type="x-shader/x-vertex">
-  attribute vec3 aVertexPosition;
-
-  uniform mat4 uMVMatrix;
-  uniform mat4 uPMatrix;
-
-
-  void main(void) {
-    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
-  }
-</script>
-
- -

Das Objekt erstellen

- -

Bevor wir unser Quadrat rendern können, müssen wir einen Puffer erstellen, der unsere Punkte enthält. Das werden wir mittels einer Funktion machen, die wir initBuffers() nennen. Wenn wir zu mehr fortgeschrittenen WebGL-Konzepten kommen, wird diese Routine vergrößert, um mehr - und komplexere - 3D-Objekte zu erstellen.

- -
var horizAspect = 480.0/640.0;
-
-function initBuffers() {
-  squareVerticesBuffer = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
-
-  var 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.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
-}
-
- -

Diese Routine ist, durch die einfache Art der Szene in diesem Beispiel, sehr einfach gehalten. Es geht los mit dem Aufruf der createBuffer() Methode, die einen Puffer erstellt in dem wir die Punkte speichern können. Der Puffer wird, durch Aufrufen der bindBuffer() Methode, mit dem Kontext verbunden.

- -

Wenn das erledigt ist, erstellen wir einen JavaScript Array, der die Koordinaten für jeden Punkt des Quadrats enthält. Dieser wird dann in einen WebGL FloatArray umgewandelt und durch die bufferData() Methode werden die Punkte für das Objekt festgelegt.

- -

Die Szene zeichnen

- -

Jetzt sind die Shader aufgebaut und das Objekt ist erstellt. Wir können die Szene rendern lassen. Da wir in dieser Szene nichts animieren, ist unsere drawScene() Funktion sehr einfach. Es werden einige nützliche Routinen verwendet, die wir uns kurz anschauen.

- -
function drawScene() {
-  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
-
-  perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0);
-
-  loadIdentity();
-  mvTranslate([-0.0, 0.0, -6.0]);
-
-  gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
-  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
-  setMatrixUniforms();
-  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
-}
-
- -

Als Erstes wird der Kontext auf unsere Hintergrundfarbe gesetzt und die Kameraperspektive festgelegt. Wir definieren ein Blickfeld von 45°, mit einem Höhen-/Breitenverhältnis von 640 zu 480 (die Größe unseres Canvas). Außerdem legen wir fest, dass wir nur Objekte zwischen 0.1 und 100 Einheiten gerendert haben wollen.

- -

Dann wird die Position des Quadrats, über das Laden der ursprünglichen Position und der Verschiebung um 6 Einheiten von der Kamera weg, ermittelt. Danach, verbinden wir den Puffer des Quadrats mit dem Kontext, konfigurieren es, und zeichnen das Objekt, in dem wir die drawArrays() Methode aufrufen.

- -

Das Ergebnis kann hier ausprobiert werden, wenn Sie einen Browser verwenden, der WebGL unterstützt.

- -

Matrix Operationen

- -

Matrix Operationen sind schon kompliziert genug. Keiner möchte wirklich den ganzen Code selbst schreiben, der benötigt wird um die Berechnungen selber durchzuführen. Glücklicherweise gibt es Sylvester, eine sehr handliche Bibliothek, die bestens mit Vektor und Matrix Operationen in JavaScript umgehen kann.

- -

Die glUtils.js Datei, die in dieser Demo benutzt wird, wird bei einer ganzen Reihe von WebGL-Demos, die Web zu finden sind, verwendet. Keiner scheint sich völlig sicher zu sein, woher diese Bibliothek ursprünglich herkommt, aber es vereinfacht den Gebrauch von Sylvester noch weiter, in dem Methoden hinzugefügt werden, die auch spezielle Matrizentypen ermöglichen und HTML ausgegeben werden kann, um die Matrizen anzeigen zu lassen.

- -

Zusätzlich, definiert diese Demo ein paar hilfreiche Routinen, um an diese Bibliothek für spezielle Aufgaben anzukoppeln. Was genau gemacht wird, ist kein Teil dieses Artikels, aber es gibt einige gute Referenzen zu Matrizen, die online verfügbar sind. Siehe unter Siehe auch, um ein paar aufzulisten.

- -
function loadIdentity() {
-  mvMatrix = Matrix.I(4);
-}
-
-function multMatrix(m) {
-  mvMatrix = mvMatrix.x(m);
-}
-
-function mvTranslate(v) {
-  multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
-}
-
-function setMatrixUniforms() {
-  var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
-  gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten()));
-
-  var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
-  gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));
-}
-
- -

Siehe auch

- - - -

{{PreviousNext("Web/API/WebGL_API/Tutorial/Einführung_in_WebGL", "Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen")}}

diff --git a/files/de/web/api/webgl_api/tutorial/lighting_in_webgl/index.html b/files/de/web/api/webgl_api/tutorial/lighting_in_webgl/index.html new file mode 100644 index 0000000000..bd65b5bb40 --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/lighting_in_webgl/index.html @@ -0,0 +1,172 @@ +--- +title: Beleuchtung in WebGL +slug: Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Lighting_in_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden", "Web/API/WebGL_API/Tutorial/Animierte_Texturen_in_WebGL")}}

+ +

Als Erstes sollten wir verstehen, dass WebGL nicht wie OpenGL über eine eigene Unterstützung für die Beleuchtung verfügt. Das müssen wir selbst machen. Glücklicherweise ist es nicht sehr schwer und dieser Artikel versucht Ihnen die Grundlagen dazu näher zu bringen.

+ +

Beleuchtung und Schattierung simulieren

+ +

Obwohl wir nicht weiter ins Detail über die Theorie hinter simulierter Beleuchtung in 3D Grafiken gehen wollen, was außerdem weit über diesen Artikel hinaus gehen würde, ist es gut zu wissen wie es ungefähr funktioniert. Anstatt hier nun in aller Tiefe zu diskutieren, sollten Sie einen Blick auf den »Phong Shading« Artikel auf Wikipedia werfen, welcher einen guten Überblick über das meist genutzte Beleuchtungsmodell liefert.

+ +

Es gibt drei grundlegende Typen zur Beleuchtung:

+ +

Umgebungslicht ist das Licht, das die Szene umgibt. Es weist in keine Richtung und bestrahlt jede Oberfläche in gleicher Weise, egal in welche Richtung es zeigt.

+ +

Gerichtetes Licht ist das Licht, das von einer festgelegten Richtung ausgestrahlt wird. Dieses Licht ist so weit weg, sodass sich jeder Photon parallel zu jedem anderen Photon bewegt. Sonnenlicht ist zum Beispiel gerichtetes (direktionales) Licht.

+ +

Punktbeleuchtung ist das Licht, das von einem Punkt ausgestrahlt wird und von dort radial in alle Richtungen verläuft. So funktionieren zum Beispiel die Glühbirnen im Alltag.

+ +

Für unsere Zwecke vereinfachen wir das Beleuchtungsmodell, indem wir nur gerichtetes Licht und Umgebungslicht betrachten. Wir haben hier keine Highlights, die wir mit Punktbeleuchtung oder Glanzlicht in dieser Szene hervorheben wollen. Stattdessen werden wir Umgebungslicht mit einem einzelnen, gerichteten Licht verwenden, welches auf den rotierenden Würfel aus der vorherigen Demo zeigt.

+ +

Wenn Sie die Konzepte der Punktbeleuchtung und des Glanzlichtes hinter sich gelassen haben, gibt es dennoch zwei kleine Informationen, die Sie benötigen werden, wenn wir unser gerichtetes Licht implementieren:

+ +
    +
  1. Wir müssen die Oberflächennormale mit jedem Vertex verbinden. Das ist ein Vektor, der senkrecht zur Oberfläche des Vertex ist.
  2. +
  3. Wir müssen die Richtung in welche das Licht strahlt wissen. Diese wird durch den Richtungsvektor angegeben.
  4. +
+ +

Dann aktualisieren wir den Vertex-Shader, um die Farbe jedes Vertices, unter Berücksichtigung des Umgebungslichts und dem Effekt des gerichteten Lichts (sowie dessen Winkel mit dem es auf die Oberfläche trifft), einzustellen. Wir werden sehen, wie genau wir das machen, wenn wir einen Blick auf den Code für den Shader werfen.

+ +

Die Normalen für die Vertices erstellen

+ +

Als Erstes müssen wir einen Array für die Normalen für alle Vertices erstellen, die unseren Würfel umfassen. Da ein Würfel ein sehr einfaches Objekt ist, ist dies auch sehr einfach zu erstellen. Für komplexere Objekte wird das Berechnen der Normalen schon umfassender.

+ +
  cubeVerticesNormalBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);
+
+  var vertexNormals = [
+    // vorne
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+     0.0,  0.0,  1.0,
+
+    // hinten
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+     0.0,  0.0, -1.0,
+
+    // oben
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+     0.0,  1.0,  0.0,
+
+    // unten
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+     0.0, -1.0,  0.0,
+
+    // rechts
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+     1.0,  0.0,  0.0,
+
+    // links
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0,
+    -1.0,  0.0,  0.0
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertexNormals), gl.STATIC_DRAW);
+
+ +

Das sollte Ihnen schon bekannt vorkommen: Wir erstellen einen neuen Buffer, verknüpfen den Array damit und senden dann unseren Vertex-Normalen-Array in den Buffer, indem wir bufferData() aufrufen.

+ +

Dann fügen wir Code zu drawScene() hinzu, um das Normalen-Array mit einem Shader-Attribut zu verknüpfen, sodass der Shader-Code darauf zugreifen kann:

+ +
  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);
+  gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ +

Schließlich müssen wir den Code aktualisieren, welcher die Einheitsmatrizen erstellt, um eine Normalenmatrix zu generieren und zum Shader auszuliefern. Diese wird verwendet, um die Normalen umzuwandeln, wenn die aktuelle Orientierung des Würfels in Beziehung zur Lichtquelle behandelt wird:

+ +
  var normalMatrix = mvMatrix.inverse();
+  normalMatrix = normalMatrix.transpose();
+  var nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");
+  gl.uniformMatrix4fv(nUniform, false, new WebGLFloatArray(normalMatrix.flatten()));
+
+ +

Die Shader aktualisieren

+ +

Jetzt sind alle Daten, die von den Shadern gebraucht werden, verfügbar. Wir müssen nun den Code in den Shadern selbst aktualisieren.

+ +

Der Vertex-Shader

+ +

Zunächst aktualisieren wir den Vertex-Shader, sodass dieser einen Schattenwert für jeden Vertex auf Basis des Umgebungslichts sowie des direktionalen Lichts berechnet. Werfen wir einen Blick auf den Code:

+ +
    <script id="shader-vs" type="x-shader/x-vertex">
+      attribute vec3 aVertexNormal;
+      attribute vec3 aVertexPosition;
+      attribute vec2 aTextureCoord;
+
+      uniform mat4 uNormalMatrix;
+      uniform mat4 uMVMatrix;
+      uniform mat4 uPMatrix;
+
+      varying vec2 vTextureCoord;
+      varying vec3 vLighting;
+
+      void main(void) {
+        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+        vTextureCoord = aTextureCoord;
+
+        // Beleuchtungseffekt anwenden
+
+        vec3 ambientLight = vec3(0.6, 0.6, 0.6);
+        vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);
+        vec3 directionalVector = vec3(0.85, 0.8, 0.75);
+
+        vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);
+
+        float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
+        vLighting = ambientLight + (directionalLightColor * directional);
+      }
+    </script>
+
+ +

Sobald die Position des Vertex berechnet wurde und wir die Koordinaten des Texels (welcher passend zum Vertex ist) erhalten haben, können wir den Schatten für den Vertex berechnen.

+ +

Als Erstes wandeln wir die Normale auf Basis der aktuellen Position und Orientierung des Würfels um, indem wir die Normale des Vertexes mit der Normalenmatrix multiplizieren. Dann können wir den Betrag an direktionalem Licht, welcher auf den Vertex angewendet werden soll, berechnen, indem wir das Skalarprodukt der umgewandelten Normalen und des direktionalen Vektors (Richtung aus der das Licht kommt) bilden. Wenn dieser Wert kleiner als Null ist, setzen wir den Wert auf Null fest, da man nicht weniger als Null Licht haben kann.

+ +

Wenn der Betrag des direktionalen Lichts berechnet wurde, können wir den Beleuchtungswert generieren, indem wir das Umgebungslicht nehmen und das Produkt der Farbe des direktionalen Lichts und den Betrag an direktionalem Licht bereitstellen. Als Ergebnis haben wir nun einen RGB-Wert, welcher vom Fragment-Shader verwendet wird, um die Farbe jedes Pixels den wir rendern einzustellen.

+ +

Der Fragment-Shader

+ +

Der Fragment-Shader muss nun aktualisiert werden, um den berechneten Beleuchtungswert vom Vertex-Shader zu berücksichtigen:

+ +
    <script id="shader-fs" type="x-shader/x-fragment">
+      varying vec2 vTextureCoord;
+      varying vec3 vLighting;
+
+      uniform sampler2D uSampler;
+
+      void main(void) {
+        vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+
+        gl_FragColor = vec4(texelColor.rgb * vLighting, texelColor.a);
+      }
+    </script>
+
+ +

Hier erhalten wir nun die Farbe des Texels, genau so wie wir es im vorherigen Beispiel getan haben. Bevor wir die Farbe der Fragmente aber festlegen, multiplizieren wir die Texel-Farbe mit dem Beleuchtungswert, um die Texel-Farbe so einzustellen, dass diese den Effekt der Lichtquelle berücksichtigt.

+ +

Und das war's! Wenn Sie einen Browser verwenden, der WebGL unterstützt, können Sie einen Blick auf die Live-Demo werfen.

+ +

Übungen für den Leser

+ +

Dies ist natürlich ein sehr einfaches Beispiel, welches eine Beleuchtung pro Vertex implementiert. Für fortgeschrittene Grafiken, möchten Sie sicher eine Beleuchtung pro Pixel implementieren, aber dies wird Sie in die Richtung leiten.

+ +

Sie können nun also versuchen mit der Richtung der Lichtquelle zu experimentieren, die Farbe der Leuchtquelle zu ändern und so weiter.

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden", "Web/API/WebGL_API/Tutorial/Animierte_Texturen_in_WebGL")}}

diff --git a/files/de/web/api/webgl_api/tutorial/objekte_mit_webgl_animieren/index.html b/files/de/web/api/webgl_api/tutorial/objekte_mit_webgl_animieren/index.html deleted file mode 100644 index a9eafed6db..0000000000 --- a/files/de/web/api/webgl_api/tutorial/objekte_mit_webgl_animieren/index.html +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: Objekte mit WebGL animieren -slug: Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL ---- -

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen", "Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen") }}

- -

Unser Code vom vorherigen Beispiel ist bereits so konfiguriert, dass die WebGL-Szene alle 15 Millisekunden neu gezeichnet wird. Bis jetzt wird zu jeder Zeit das gleiche Bild immer neu gezeichnet. Das wollen wir nun ändern, sodass sich unser Quadrat auf der Bildfläche bewegt.

- -

In diesem Beispiel rotieren und verschieben wir unser Quadrat in alle drei Dimensionen, sodass es schon in einem 3D Raum existieren kann (obwohl wir bisher nur ein 2D-Objekt erstellt haben).

- -

Das Quadrat rotieren lassen

- -

Fangen wir damit an, das Quadrat im Raum zu rotieren. Als erstes brauchen wir dazu eine Variable in welche wir die Rotation des Quadrats verfolgen können:

- -
var squareRotation = 0.0;
-
- -

Jetzt müssen wir die drawScene() Funktion ändern, um die aktuelle Rotation auf das Quadrat anzuwenden, wenn dies gezeichnet werden soll. Nach der Umrechnung der Startposition für das Quadrat, wenden wir eine Rotation wie diese an:

- -
mvPushMatrix();
-mvRotate(squareRotation, [1, 0, 1]);
-
- -

Das speichert die aktuelle Model-View Matrix und rotiert die Matrix mit dem aktuellen Wert von squareRotation um die X und Z Achsen.

- -

Nach dem Zeichen müssen wir die Originalmatrix wiederherstellen:

- -
mvPopMatrix();
-
- -

Wir speichern und stellen die Originalmatrix dann wieder her, um zu verhindern, dass die Rotation auf andere Objekte angewendet wird, die wir vielleicht später noch zeichnen wollen.

- -

Um letztendlich etwas zu animieren, brauchen wir noch ein paar Zeilen Code, welcher den Wert von squareRotation über die Zeit verändert. Dafür erstellen wir eine neue Variable, die die Zeit aufzeichnet, welche wir zuletzt animiert haben (wir nennen diese lastSquareUpdateTime), dann fügen wir den folgenden Code an das Ende der drawScene() Funktion:

- -
var currentTime = (new Date).getTime();
-if (lastSquareUpdateTime) {
-  var delta = currentTime - lastSquareUpdateTime;
-  squareRotation += (30 * delta) / 1000.0;
-}
-lastSquareUpdateTime = currentTime;
-
- -

Dieser Code benutzt den Betrag der Zeit, die vergangen ist, seitdem wir zum letzten Mal den Wert von squareRotation geändert haben, um festzustellen wie weit das Quadrat rotiert werden soll.

- -

Das Quadrat bewegen

- -

Wir können das Quadrat auch verschieben indem wir eine unterschiedliche Position berechnen lassen, bevor wir es zeichnen. Dieses Beispiel zeigt wie eine grundlegende Animation gemacht werden kann. Allerdings möchten Sie in einer echten Anwendung wohl eher etwas weniger Irrsinniges machen.

- -

Verfolgen wir die Abstände zu jeder Achse für unsere Verschiebung in drei neuen Variablen:

- -
var squareXOffset = 0.0;
-var squareYOffset = 0.0;
-var squareZOffset = 0.0;
-
- -

Und den Betrag, welcher unsere Postion auf jeder Achse verändern soll, in diesen Variablen:

- -
var xIncValue = 0.2;
-var yIncValue = -0.4;
-var zIncValue = 0.3;
-
- -

Nun können wir einfach diesen Code zum vorherigen Code, der die Rotation aktualisiert, hinzufügen:

- -
squareXOffset += xIncValue * ((30 * delta) / 1000.0);
-squareYOffset += yIncValue * ((30 * delta) / 1000.0);
-squareZOffset += zIncValue * ((30 * delta) / 1000.0);
-
-if (Math.abs(squareYOffset) > 2.5) {
-  xIncValue = -xIncValue;
-  yIncValue = -yIncValue;
-  zIncValue = -zIncValue;
-}
-
- -

Das bringt unser Quadrat dazu seine Größe zu verändern, sich willkürlich auf der Fläche zu verschieben, sich vom Betrachter weg und zum Betrachter hin zu bewegen und das alles während das Quadrat auch noch rotiert. Das sieht dann schon eher wie ein Bildschirmschoner aus.

- -

Wenn Ihr Browser WebGL unterstützt, ist hier das Beispiel in Aktion.

- -

Weitere Matrixoperationen

- -

Dieses Beispiel verwendet einige zusätzliche Matrixoperationen, darunter zwei Routinen, die die Matrizen verschieben, wiederherstellen und in einem Stack aufbewahren und eine Routine, die die Matrix um eine gewissen Anzahl von Grad rotiert:

- -
var mvMatrixStack = [];
-
-function mvPushMatrix(m) {
-  if (m) {
-    mvMatrixStack.push(m.dup());
-    mvMatrix = m.dup();
-  } else {
-    mvMatrixStack.push(mvMatrix.dup());
-  }
-}
-
-function mvPopMatrix() {
-  if (!mvMatrixStack.length) {
-    throw("Can't pop from an empty matrix stack.");
-  }
-
-  mvMatrix = mvMatrixStack.pop();
-  return mvMatrix;
-}
-
-function mvRotate(angle, v) {
-  var inRadians = angle * Math.PI / 180.0;
-
-  var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4();
-  multMatrix(m);
-}
-
- -

Diese Routinen wurden von einem Beispiel ausgeliehen, welches von Vlad Vukićević geschrieben wurde.

- -

{{PreviousNext("Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen", "Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen") }}

diff --git a/files/de/web/api/webgl_api/tutorial/texturen_in_webgl_verwenden/index.html b/files/de/web/api/webgl_api/tutorial/texturen_in_webgl_verwenden/index.html deleted file mode 100644 index eb59417694..0000000000 --- a/files/de/web/api/webgl_api/tutorial/texturen_in_webgl_verwenden/index.html +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: Texturen in WebGL verwenden -slug: Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden -tags: - - Tutorial - - WebGL -translation_of: Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL ---- -

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen", "Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

- -

Jetzt wo unser Beispielprogramm über einen rotierenden 3D-Würfel verfügt, wollen wir darauf eine Textur legen, statt der bisher verwendeten, einfachen Farben.

- -

Texturen laden

- -

Als Erstes müssen wir ein paar Zeilen Code hinzufügen, um die Texturen zu laden. In unserem Fall werden wir eine einzige Textur verwenden, die auf alle sechs Seiten des rotierenden Würfels gelegt wird, aber die gleiche Technik kann verwendet werden, um jede beliebig viele Texturen auf ein Objekt zu legen.

- -

Der Code, der die Textur lädt, sieht so aus:

- -
function initTextures() {
-  gl.enable(gl.TEXTURE_2D);
-  cubeTexture = gl.createTexture();
-  cubeImage = new Image();
-  cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }
-  cubeImage.src = "cubetexture.png";
-}
-
-function handleTextureLoaded(image, texture) {
-  gl.bindTexture(gl.TEXTURE_2D, texture);
-  gl.texImage2D(gl.TEXTURE_2D, 0, image, true);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
-  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
-  gl.generateMipmap(gl.TEXTURE_2D);
-  gl.bindTexture(gl.TEXTURE_2D, null);
-}
-
- -

Die Routine initTextures() aktiviert zunächst die Unterstützung von Texturen, dann wird das GL Textur-Objekt cubeTexture durch Aufruf der GL createTexture() Funktion erstellt. Um die Textur von der Bilddatei zu laden, wird dann ein Image-Objekt erstellt und in die Grafikdatei geladen, die wir als unsere Textur verwenden wollen. Die handleTextureLoaded() Callback-Routine wird ausgeführt, wenn das Bild geladen wurde.

- -

Um schließlich die Textur zu erstellen, legen wir fest, dass die neue Textur die aktuelle Textur ist, mit welcher wir arbeiten wollen und verbinden diese mit gl.TEXTURE_2D. Danach wird das geladene Bild mit texImage2D() die Bilddaten in die Textur schreiben.

- -

Die nächsten zwei Zeilen legen Filter für die Textur fest, die steuern, wie das Bild gefiltert wird, wenn es skaliert wird. In diesem Fall verwenden wir lineare Filter, wenn das Bild hoch skaliert wird und Mip-Mapping wenn wir herunter skalieren. Dann wird die Mip-Map generiert, indem generateMipMap() aufgerufen wird. Schließlich teilen wir WebGL mit, dass wir mit der Arbeit an der Textur fertig sind, in dem wir null mit gl.TEXTURE_2D verknüpfen.

- -

Textur auf die Flächen legen

- -

Nun ist die Textur geladen und bereit eingesetzt zu werden. Bevor wir die Textur aber verwenden können, müssen wir die Texturkoordinaten auf die Vertices der Flächen des Würfels legen. Das ersetzt den vorherigen Code in initBuffers(), der die Farben für jede Fläche festgelegt hat.

- -
  cubeVerticesTextureCoordBuffer = gl.createBuffer();
-  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
-
-  var textureCoordinates = [
-    // vorne
-    0.0,  0.0,
-    1.0,  0.0,
-    1.0,  1.0,
-    0.0,  1.0,
-    // hinten
-    0.0,  0.0,
-    1.0,  0.0,
-    1.0,  1.0,
-    0.0,  1.0,
-    // oben
-    0.0,  0.0,
-    1.0,  0.0,
-    1.0,  1.0,
-    0.0,  1.0,
-    // unten
-    0.0,  0.0,
-    1.0,  0.0,
-    1.0,  1.0,
-    0.0,  1.0,
-    // rechts
-    0.0,  0.0,
-    1.0,  0.0,
-    1.0,  1.0,
-    0.0,  1.0,
-    // links
-    0.0,  0.0,
-    1.0,  0.0,
-    1.0,  1.0,
-    0.0,  1.0
-  ];
-
-  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(textureCoordinates),
-                gl.STATIC_DRAW);
-
- -

Zuerst erstellt dieser Code einen GL-Buffer in welchen wir die Texturkoordinaten für jede Fläche speichern werden, dann verknüpfen wir diesen Buffer als das Array in welchen wir schreiben werden.

- -

Das textureCoordinates Array definiert die Texturkoordinaten entsprechend jedem Vertex von jeder Fläche. Beachten Sie, dass die Texturkoordinaten sich im Bereich von 0.0 bis 1.0 befinden. Beim Texturmapping werden die Dimensionen von Texturen immer auf einen Bereich von 0.0 bis 1.0 normiert, egal welche Größe die Textur wirklich hat.

- -

Sobald wir das Texturmapping-Array erstellt haben, speichern wir das Array in den Buffer, sodass GL die Daten zur Verfügung hat.

- -

Die Shader aktualisieren

- -

Das Shader-Programm - und der Code, der die Shader initialisiert - muss aktualisiert werden, damit die Textur anstatt der Farben verwendet wird.

- -

Werfen wir zunächst einen Blick auf die einfache Änderung, die in initShaders() benötigt wird:

- -
  textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
-  gl.enableVertexAttribArray(textureCoordAttribute);
-
- -

Das ersetzt den Code, der die Vertex Farbattribute enthielt, mit dem, der nun die Texturkoordinaten für jeden Vertex enthält.

- -

Der Vertex-Shader

- -

Als Nächstes müssen wir den Vertex-Shader ersetzen, sodass statt der Farbdaten die Texturkoordinaten abgerufen werden.

- -
    <script id="shader-vs" type="x-shader/x-vertex">
-      attribute vec3 aVertexPosition;
-      attribute vec2 aTextureCoord;
-
-      uniform mat4 uMVMatrix;
-      uniform mat4 uPMatrix;
-
-      varying vec2 vTextureCoord;
-
-      void main(void) {
-        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
-        vTextureCoord = aTextureCoord;
-      }
-    </script>
-
- -

Die wichtigste Änderung ist hier, dass anstatt die Vertex-Farbe abzurufen, die Texturkoordinaten gesetzt werden. Das gibt den Ort der Textur entsprechend zum Vertex an.

- -

Der Fragment-Shader

- -

Der Fragment-Shader muss in ähnlicher Weise geändert werden:

- -
    <script id="shader-fs" type="x-shader/x-fragment">
-      varying vec2 vTextureCoord;
-
-      uniform sampler2D uSampler;
-
-      void main(void) {
-        gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
-      }
-    </script>
-
- -

Anstatt einen Farbwert auf die Fragment-Farbe zu legen, wird die Fragment-Farbe berechnet in dem der texel (der Pixel innerhalb der Textur) abgerufen wird, der am Besten auf die Fragement-Position laut dem Sampler passt.

- -

Zeichnen des textuierten Würfels

- -

Die Änderungen an der drawScene() Funktion sind einfach (mit der Ausnahme, dass ich nun zur besseren Anschaulichkeit die Verschiebungen entfernt habe und der Würfel nur noch rotiert wird).

- -

Der Code, der die Farben auf die Textur legt ist weg und wurde ersetzt:

- -
  gl.activeTexture(gl.TEXTURE0);
-  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
-  gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
-
- -

GL ermöglicht 32 Textur-Register; der Erste davon ist gl.TEXTURE0. Wir verknüpfen unsere geladene Textur zu diesem Register, dann wird der Shader-Sampler uSampler gesetzt (im Shader-Program festgelegt), um die Textur zu benutzen.

- -

Jetzt sollte der rotierende Würfel gut anzuschauen zu sein. Wenn Ihr Browser WebGL unterstützt, können Sie das Live-Beispiel ausprobieren.

- -

{{PreviousNext("Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen", "Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

diff --git a/files/de/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html b/files/de/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html new file mode 100644 index 0000000000..94068822d5 --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html @@ -0,0 +1,97 @@ +--- +title: Farben mittels Shader in einen WebGL-Kontext hinzufügen +slug: >- + Web/API/WebGL_API/Tutorial/Farben_mittels_Shader_in_einen_WebGL-Kontext_hinzufügen +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext", "Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren")}}

+ +

Wir haben ein simples Quadrat im vorherigen Teil erstellt, im nächsten Schritt wollen wir ein bisschen Farbe ins Spiel bringen. Dafür sind Änderungen an den Shadern erforderlich.

+ +

Farben zu den Eckpunkten hinzufügen

+ +

In der Computergrafik werden Objekte mit einer Reihe von Punkten erstellt. Jeder Punkt hat eine Position und eine Farbe. Standardmäßig werden alle anderen Pixelfarben (und alle weiteren Attribute, darunter die Position) über eine lineare Interpolation berechnet, die automatisch glatte Verläufe erstellt. Vorher hat unser Vertex-Shader keine festgelegten Farben auf die Punkte (Vertices) angewendet und der Fragment-Shader legte die feste Farbe weiß für jeden Pixel fest, sodass das gesamte Quadrat komplett weiß gezeichnet wurde.

+ +

Nun wollen wir in jeder Ecke des Quadrats einen Verlauf in einer unterschiedlichen Farbe rendern: rot, blau, grün und weiß. Als erstes sollten wir daher diese Farben in den vier Eckpunkten einrichten. Um das zu machen, müssen wir zunächst einen Array der Vertex-Farben erstellen und diesen dann in einen WebGL Buffer speichern. Das erreichen wir durch die folgenden Zeilen in unserer initBuffers() Funktion:

+ +
var colors = [
+  1.0,  1.0,  1.0,  1.0,    // weiß
+  1.0,  0.0,  0.0,  1.0,    // rot
+  0.0,  1.0,  0.0,  1.0,    // grün
+  0.0,  0.0,  1.0,  1.0     // blau
+];
+
+squareVerticesColorBuffer = gl.createBuffer();
+gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
+gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
+}
+
+ +

Dieser Code definiert zuerst einen JavaScript Array, welcher die vier Farb-Vektoren mit jeweils vier Werten für die jeweilige Farbe enthält. Dann wird ein neuer WebGL Buffer angewiesen diese Farben zu speichern und der Array wird in WebGL Floats konvertiert und im Buffer gespeichert.

+ +

Um die Farben schließlich zu verwenden, muss der der Vertex-Shader aktualisiert werden, um die entsprechende Farbe vom Farb-Buffer zu erhalten:

+ +
<script id="shader-vs" type="x-shader/x-vertex">
+  attribute vec3 aVertexPosition;
+  attribute vec4 aVertexColor;
+
+  uniform mat4 uMVMatrix;
+  uniform mat4 uPMatrix;
+
+  varying vec4 vColor;
+
+  void main(void) {
+    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+    vColor = aVertexColor;
+  }
+</script>
+
+ +

Der wichtigste Unterschied ist hier, dass wir für jeden Punkt (Vertex) die Farbe entsprechend des Farb-Arrays setzen.

+ +

Die Fragmente mit Farben versehen

+ +

Als Erinnerung, so sah unser Fragment-Shader vorher aus:

+ +
<script id="shader-fs" type="x-shader/x-fragment">
+  void main(void) {
+    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+  }
+</script>
+
+ +

Um nun die interpolierte Farbe für jeden Pixel aufzugreifen, müssen wir dies einfach so ändern, dass wir den Wert der vColor Variable erhalten:

+ +
<script id="shader-fs" type="x-shader/x-fragment">
+  varying vec4 vColor;
+
+  void main(void) {
+    gl_FragColor = vColor;
+  }
+</script>
+
+ +

Das ist eine sehr einfache Änderung. Anstatt des festen Wertes vorher, erhält jedes Fragment jetzt einfach die interpolierte Farbe, basierend auf der Position relativ zu den Kontenpunkten (Vertices).

+ +

Mit den Farben zeichnen

+ +

Als nächstes ist es nötig, Code zur initShaders() Routine hinzuzufügen, um das Farbattribut für das Shader-Programm zu initialisieren:

+ +
  vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
+  gl.enableVertexAttribArray(vertexColorAttribute);
+
+ +

Dann wird drawScene() abgeändert, um schließlich die Farben zu verwenden, wenn das Quadrat gezeichnet wird:

+ +
  gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
+  gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ +

Jetzt sollten Sie das Beispiel in einem WebGL kompatiblen Browser sehen und Ihre Ausgabe sollte so wie im Bild unten gezeichnet werden (das Quadrat ist innerhalb eines schwarzen Felds zu sehen):

+ +

screenshot.png

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/Hinzufügen_von_2D_Inhalten_in_einen_WebGL-Kontext", "Web/API/WebGL_API/Tutorial/Objekte_mit_WebGL_animieren")}}

diff --git a/files/de/web/api/webgl_api/tutorial/using_textures_in_webgl/index.html b/files/de/web/api/webgl_api/tutorial/using_textures_in_webgl/index.html new file mode 100644 index 0000000000..eb59417694 --- /dev/null +++ b/files/de/web/api/webgl_api/tutorial/using_textures_in_webgl/index.html @@ -0,0 +1,159 @@ +--- +title: Texturen in WebGL verwenden +slug: Web/API/WebGL_API/Tutorial/Texturen_in_WebGL_verwenden +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL +--- +

{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen", "Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

+ +

Jetzt wo unser Beispielprogramm über einen rotierenden 3D-Würfel verfügt, wollen wir darauf eine Textur legen, statt der bisher verwendeten, einfachen Farben.

+ +

Texturen laden

+ +

Als Erstes müssen wir ein paar Zeilen Code hinzufügen, um die Texturen zu laden. In unserem Fall werden wir eine einzige Textur verwenden, die auf alle sechs Seiten des rotierenden Würfels gelegt wird, aber die gleiche Technik kann verwendet werden, um jede beliebig viele Texturen auf ein Objekt zu legen.

+ +

Der Code, der die Textur lädt, sieht so aus:

+ +
function initTextures() {
+  gl.enable(gl.TEXTURE_2D);
+  cubeTexture = gl.createTexture();
+  cubeImage = new Image();
+  cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }
+  cubeImage.src = "cubetexture.png";
+}
+
+function handleTextureLoaded(image, texture) {
+  gl.bindTexture(gl.TEXTURE_2D, texture);
+  gl.texImage2D(gl.TEXTURE_2D, 0, image, true);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+  gl.generateMipmap(gl.TEXTURE_2D);
+  gl.bindTexture(gl.TEXTURE_2D, null);
+}
+
+ +

Die Routine initTextures() aktiviert zunächst die Unterstützung von Texturen, dann wird das GL Textur-Objekt cubeTexture durch Aufruf der GL createTexture() Funktion erstellt. Um die Textur von der Bilddatei zu laden, wird dann ein Image-Objekt erstellt und in die Grafikdatei geladen, die wir als unsere Textur verwenden wollen. Die handleTextureLoaded() Callback-Routine wird ausgeführt, wenn das Bild geladen wurde.

+ +

Um schließlich die Textur zu erstellen, legen wir fest, dass die neue Textur die aktuelle Textur ist, mit welcher wir arbeiten wollen und verbinden diese mit gl.TEXTURE_2D. Danach wird das geladene Bild mit texImage2D() die Bilddaten in die Textur schreiben.

+ +

Die nächsten zwei Zeilen legen Filter für die Textur fest, die steuern, wie das Bild gefiltert wird, wenn es skaliert wird. In diesem Fall verwenden wir lineare Filter, wenn das Bild hoch skaliert wird und Mip-Mapping wenn wir herunter skalieren. Dann wird die Mip-Map generiert, indem generateMipMap() aufgerufen wird. Schließlich teilen wir WebGL mit, dass wir mit der Arbeit an der Textur fertig sind, in dem wir null mit gl.TEXTURE_2D verknüpfen.

+ +

Textur auf die Flächen legen

+ +

Nun ist die Textur geladen und bereit eingesetzt zu werden. Bevor wir die Textur aber verwenden können, müssen wir die Texturkoordinaten auf die Vertices der Flächen des Würfels legen. Das ersetzt den vorherigen Code in initBuffers(), der die Farben für jede Fläche festgelegt hat.

+ +
  cubeVerticesTextureCoordBuffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
+
+  var textureCoordinates = [
+    // vorne
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // hinten
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // oben
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // unten
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // rechts
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0,
+    // links
+    0.0,  0.0,
+    1.0,  0.0,
+    1.0,  1.0,
+    0.0,  1.0
+  ];
+
+  gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(textureCoordinates),
+                gl.STATIC_DRAW);
+
+ +

Zuerst erstellt dieser Code einen GL-Buffer in welchen wir die Texturkoordinaten für jede Fläche speichern werden, dann verknüpfen wir diesen Buffer als das Array in welchen wir schreiben werden.

+ +

Das textureCoordinates Array definiert die Texturkoordinaten entsprechend jedem Vertex von jeder Fläche. Beachten Sie, dass die Texturkoordinaten sich im Bereich von 0.0 bis 1.0 befinden. Beim Texturmapping werden die Dimensionen von Texturen immer auf einen Bereich von 0.0 bis 1.0 normiert, egal welche Größe die Textur wirklich hat.

+ +

Sobald wir das Texturmapping-Array erstellt haben, speichern wir das Array in den Buffer, sodass GL die Daten zur Verfügung hat.

+ +

Die Shader aktualisieren

+ +

Das Shader-Programm - und der Code, der die Shader initialisiert - muss aktualisiert werden, damit die Textur anstatt der Farben verwendet wird.

+ +

Werfen wir zunächst einen Blick auf die einfache Änderung, die in initShaders() benötigt wird:

+ +
  textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
+  gl.enableVertexAttribArray(textureCoordAttribute);
+
+ +

Das ersetzt den Code, der die Vertex Farbattribute enthielt, mit dem, der nun die Texturkoordinaten für jeden Vertex enthält.

+ +

Der Vertex-Shader

+ +

Als Nächstes müssen wir den Vertex-Shader ersetzen, sodass statt der Farbdaten die Texturkoordinaten abgerufen werden.

+ +
    <script id="shader-vs" type="x-shader/x-vertex">
+      attribute vec3 aVertexPosition;
+      attribute vec2 aTextureCoord;
+
+      uniform mat4 uMVMatrix;
+      uniform mat4 uPMatrix;
+
+      varying vec2 vTextureCoord;
+
+      void main(void) {
+        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+        vTextureCoord = aTextureCoord;
+      }
+    </script>
+
+ +

Die wichtigste Änderung ist hier, dass anstatt die Vertex-Farbe abzurufen, die Texturkoordinaten gesetzt werden. Das gibt den Ort der Textur entsprechend zum Vertex an.

+ +

Der Fragment-Shader

+ +

Der Fragment-Shader muss in ähnlicher Weise geändert werden:

+ +
    <script id="shader-fs" type="x-shader/x-fragment">
+      varying vec2 vTextureCoord;
+
+      uniform sampler2D uSampler;
+
+      void main(void) {
+        gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+      }
+    </script>
+
+ +

Anstatt einen Farbwert auf die Fragment-Farbe zu legen, wird die Fragment-Farbe berechnet in dem der texel (der Pixel innerhalb der Textur) abgerufen wird, der am Besten auf die Fragement-Position laut dem Sampler passt.

+ +

Zeichnen des textuierten Würfels

+ +

Die Änderungen an der drawScene() Funktion sind einfach (mit der Ausnahme, dass ich nun zur besseren Anschaulichkeit die Verschiebungen entfernt habe und der Würfel nur noch rotiert wird).

+ +

Der Code, der die Farben auf die Textur legt ist weg und wurde ersetzt:

+ +
  gl.activeTexture(gl.TEXTURE0);
+  gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+  gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
+
+ +

GL ermöglicht 32 Textur-Register; der Erste davon ist gl.TEXTURE0. Wir verknüpfen unsere geladene Textur zu diesem Register, dann wird der Shader-Sampler uSampler gesetzt (im Shader-Program festgelegt), um die Textur zu benutzen.

+ +

Jetzt sollte der rotierende Würfel gut anzuschauen zu sein. Wenn Ihr Browser WebGL unterstützt, können Sie das Live-Beispiel ausprobieren.

+ +

{{PreviousNext("Web/API/WebGL_API/Tutorial/3D-Objekte_mit_WebGL_erstellen", "Web/API/WebGL_API/Tutorial/Beleuchtung_in_WebGL")}}

-- cgit v1.2.3-54-g00ecf