WebGL - Kurzanleitung
Vor einigen Jahren wurden Java-Anwendungen - als Kombination aus Applets und JOGL - verwendet, um 3D-Grafiken im Web zu verarbeiten, indem die GPU (Graphical Processing Unit) angesprochen wurde. Da für die Ausführung von Applets eine JVM erforderlich ist, wurde es schwierig, sich auf Java-Applets zu verlassen. Einige Jahre später hörten die Leute auf, Java-Applets zu verwenden.
Die von Adobe (Flash, AIR) bereitgestellten Stage3D-APIs boten eine hardwarebeschleunigte GPU-Architektur. Mithilfe dieser Technologien könnten Programmierer Anwendungen mit 2D- und 3D-Funktionen in Webbrowsern sowie auf IOS- und Android-Plattformen entwickeln. Da Flash eine proprietäre Software war, wurde sie nicht als Webstandard verwendet.
Im März 2011 wurde WebGL veröffentlicht. Es ist eine Openware, die ohne JVM ausgeführt werden kann. Es wird vollständig vom Webbrowser gesteuert.
Die neue Version von HTML 5 bietet verschiedene Funktionen zur Unterstützung von 3D-Grafiken wie 2D-Canvas, WebGL, SVG, 3D-CSS-Transformationen und SMIL. In diesem Tutorial werden die Grundlagen von WebGL behandelt.
Was ist OpenGL?
OpenGL (Open Graphics Library) ist eine sprachübergreifende, plattformübergreifende API für 2D- und 3D-Grafiken. Es ist eine Sammlung von Befehlen. OpenGL4.5 ist die neueste Version von OpenGL. In der folgenden Tabelle sind einige Technologien aufgeführt, die sich auf OpenGL beziehen.
API | Verwendete Technologie |
---|---|
OpenGL ES | Es ist die Bibliothek für 2D- und 3D-Grafiken auf eingebetteten Systemen - einschließlich Konsolen, Telefonen, Geräten und Fahrzeugen. OpenGL ES 3.1 ist die neueste Version. Es wird von der Khronos Group www.khronos.org gepflegt |
JOGL | Es ist die Java-Bindung für OpenGL. JOGL 4.5 ist die neueste Version und wird von jogamp.org gepflegt . |
WebGL | Es ist die JavaScript-Bindung für OpenGL. WebGL 1.0 ist die neueste Version und wird von der khronos-Gruppe verwaltet . |
OpenGLSL | OpenGL Shading Language. Es ist eine Programmiersprache, die OpenGL 2.0 und höher unterstützt. Es ist Teil der OpenGL 4.4-Kernspezifikation. Es ist eine API, die speziell auf eingebettete Systeme zugeschnitten ist, wie sie auf Mobiltelefonen und Tablets vorhanden sind. |
Note - In WebGL verwenden wir GLSL, um Shader zu schreiben.
Was ist WebGL?
WebGL (Web Graphics Library) ist der neue Standard für 3D-Grafiken im Web. Er wurde zum Rendern von 2D-Grafiken und interaktiven 3D-Grafiken entwickelt. Es basiert auf der ES 2.0-Bibliothek von OpenGL, einer einfachen 3D-API für Telefone und andere mobile Geräte. WebGL bietet ähnliche Funktionen wie ES 2.0 (Embedded Systems) und funktioniert gut mit moderner 3D-Grafikhardware.
Es ist eine JavaScript-API, die mit HTML5 verwendet werden kann. WebGL-Code wird in das <canvas> -Tag von HTML5 geschrieben. Diese Spezifikation ermöglicht Internetbrowsern den Zugriff auf Grafikprozessoren (GPUs) auf den Computern, auf denen sie verwendet wurden.
Wer hat WebGL entwickelt?
Ein amerikanisch-serbischer Software-Ingenieur namens Vladimir Vukicevic hat die Grundlagenarbeit geleistet und die Erstellung von WebGL geleitet
2007 begann Vladimir mit der Arbeit an einem OpenGL Prototyp für das Canvas-Element des HTML-Dokuments.
Im März 2011 gründete die Kronos Group WebGL.
Rendern
Beim Rendern wird mithilfe von Computerprogrammen aus einem Modell ein Bild generiert. In Grafiken wird eine virtuelle Szene anhand von Informationen wie Geometrie, Ansichtspunkt, Textur, Beleuchtung und Schattierung beschrieben, die durch ein Renderprogramm geleitet werden. Die Ausgabe dieses Renderprogramms ist ein digitales Bild.
Es gibt zwei Arten des Renderns:
Software Rendering - Alle Rendering-Berechnungen werden mit Hilfe der CPU durchgeführt.
Hardware Rendering - Alle Grafikberechnungen werden von der GPU (Graphical Processing Unit) durchgeführt.
Das Rendern kann lokal oder remote erfolgen. Wenn das zu rendernde Bild viel zu komplex ist, erfolgt das Rendern remote auf einem dedizierten Server, der über genügend Hardwareressourcen verfügt, um komplexe Szenen zu rendern. Es wird auch als bezeichnetserver-based rendering. Das Rendern kann auch lokal von der CPU durchgeführt werden. Es heißt alsclient-based rendering.
WebGL verfolgt einen clientbasierten Rendering-Ansatz zum Rendern von 3D-Szenen. Die gesamte zum Abrufen eines Bildes erforderliche Verarbeitung wird lokal mit der Grafikhardware des Clients ausgeführt.
GPU
Laut NVIDIA ist eine GPU "ein Einzelchip-Prozessor mit integrierten Transformations-, Beleuchtungs-, Dreieck-Setup- / Clipping- und Rendering-Engines, die mindestens 10 Millionen Polygone pro Sekunde verarbeiten können". Im Gegensatz zu Mehrkernprozessoren mit wenigen für die sequentielle Verarbeitung optimierten Kernen besteht eine GPU aus Tausenden kleinerer Kerne, die parallele Workloads effizient verarbeiten. Daher beschleunigt die GPU die Erstellung von Bildern in einem Bildpuffer (einem Teil des RAM, der vollständige Bilddaten enthält), der zur Ausgabe an eine Anzeige bestimmt ist.
GPU Accelerated Computing
Beim GPU-beschleunigten Rechnen wird die Anwendung in die CPU geladen. Wann immer es auf a trifftcompute-intensiveTeil des Codes, dann wird dieser Teil des Codes geladen und auf der GPU ausgeführt. Es gibt dem System die Möglichkeit, Grafiken auf effiziente Weise zu verarbeiten.
Die GPU verfügt über einen separaten Speicher und führt mehrere Kopien eines kleinen Teils des Codes gleichzeitig aus. Die GPU verarbeitet alle Daten, die sich in ihrem lokalen Speicher befinden, nicht im zentralen Speicher. Daher sollten die Daten, die von der GPU verarbeitet werden müssen, in den GPU-Speicher geladen / kopiert und dann verarbeitet werden.
In den Systemen mit der obigen Architektur sollte der Kommunikationsaufwand zwischen der CPU und der GPU reduziert werden, um eine schnellere Verarbeitung von 3D-Programmen zu erreichen. Dazu müssen wir alle Daten kopieren und auf der GPU belassen, anstatt wiederholt mit der GPU zu kommunizieren.
Browser unterstützt
Die folgenden Tabellen zeigen eine Liste der Browser, die WebGL unterstützen -
Internetbrowser
Browsername | Ausführung | Unterstützung |
---|---|---|
IInternet Explorer | 11 und höher | Komplette Unterstützung |
Google Chrome | 39 und höher | Komplette Unterstützung |
Safari | 8 | Komplette Unterstützung |
Feuerfuchs | 36 und höher | Teilweise Unterstützung |
Oper | 27 und höher | Teilweise Unterstützung |
Mobile Browser
Browsername | Ausführung | Unterstützung |
---|---|---|
Chrome für Android | 42 | Teilweise Unterstützung |
Android-Browser | 40 | Teilweise Unterstützung |
IOS Safari | 8.3 | Komplette Unterstützung |
Opera Mini | 8 | Unterstützt nicht |
Blackberry Browser | 10 | Komplette Unterstützung |
IE mobil | 10 | Teilweise Unterstützung |
Vorteile von WebGL
Hier sind die Vorteile der Verwendung von WebGL:
JavaScript programming- WebGL-Anwendungen sind in JavaScript geschrieben. Mit diesen Anwendungen können Sie direkt mit anderen Elementen des HTML-Dokuments interagieren. Sie können auch andere JavaScript-Bibliotheken (z. B. JQuery) und HTML-Technologien verwenden, um die WebGL-Anwendung anzureichern.
Increasing support with mobile browsers - WebGL unterstützt auch mobile Browser wie iOS-Safari, Android-Browser und Chrome für Android.
Open source- WebGL ist Open Source. Sie können auf den Quellcode der Bibliothek zugreifen und verstehen, wie sie funktioniert und wie sie entwickelt wurde.
No need for compilation- JavaScript ist eine halb programmierende und halb HTML-Komponente. Um dieses Skript auszuführen, muss die Datei nicht kompiliert werden. Stattdessen können Sie die Datei direkt mit einem der Browser öffnen und das Ergebnis überprüfen. Da WebGL-Anwendungen mit JavaScript entwickelt werden, müssen auch keine WebGL-Anwendungen kompiliert werden.
Automatic memory management- JavaScript unterstützt die automatische Speicherverwaltung. Eine manuelle Speicherzuweisung ist nicht erforderlich. WebGL erbt diese Funktion von JavaScript.
Easy to set up- Da WebGL in HTML 5 integriert ist, ist keine zusätzliche Einrichtung erforderlich. Zum Schreiben einer WebGL-Anwendung benötigen Sie lediglich einen Texteditor und einen Webbrowser.
Umgebungs-Setup
Es ist nicht erforderlich, eine andere Umgebung für WebGL festzulegen. Die Browser, die WebGL unterstützen, verfügen über ein eigenes Setup für WebGL.
Um grafische Anwendungen im Web zu erstellen, bietet HTML-5 eine Vielzahl von Funktionen wie 2D-Canvas, WebGL, SVG, 3D-CSS-Transformationen und SMIL. Zum Schreiben von WebGL-Anwendungen verwenden wir das vorhandene Canvas-Element von HTML-5. Dieses Kapitel bietet einen Überblick über das HTML-5 2D-Canvas-Element.
HTML5 Canvas
HTML-5 <canvas>bietet eine einfache und leistungsstarke Option zum Zeichnen von Grafiken mit JavaScript. Es kann verwendet werden, um Grafiken zu zeichnen, Fotokompositionen zu erstellen oder einfache (und nicht so einfache) Animationen zu erstellen.
Hier ist eine einfache <canvas> Element mit nur zwei spezifischen Attributen width und height plus alle HTML-5-Kernattribute wie ID, Name und Klasse.
Syntax
Die Syntax des HTML-Canvas-Tags ist unten angegeben. Sie müssen den Namen der Leinwand in doppelten Anführungszeichen ("") angeben.
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
Canvas-Attribute
Das Canvas-Tag verfügt über drei Attribute: ID, Breite und Höhe.
Id- ID repräsentiert die Kennung des Canvas-Elements im Document Object Model (DOM) .
Width - Breite repräsentiert die Breite der Leinwand.
Height - Die Höhe entspricht der Höhe der Leinwand.
Diese Attribute bestimmen die Größe der Zeichenfläche. Wenn ein Programmierer sie nicht unter dem Canvas-Tag angibt, stellen Browser wie Firefox, Chrome und Web Kit standardmäßig ein Canvas-Element der Größe 300 × 150 bereit.
Beispiel - Erstellen Sie eine Leinwand
Der folgende Code zeigt, wie Sie eine Zeichenfläche erstellen. Wir haben CSS verwendet, um der Leinwand einen farbigen Rand zu geben.
<html>
<head>
<style>
#mycanvas{border:1px solid red;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "100" height = "100"></canvas>
</body>
</html>
Bei der Ausführung erzeugt der obige Code die folgende Ausgabe:
Der Rendering-Kontext
Das <canvas> ist anfangs leer. Um etwas auf dem Canvas-Element anzuzeigen, müssen wir eine Skriptsprache verwenden. Diese Skriptsprache sollte auf den Renderkontext zugreifen und darauf zurückgreifen.
Das Canvas-Element verfügt über eine aufgerufene DOM-Methode getContext(), mit dem der Renderkontext und seine Zeichenfunktionen abgerufen werden. Diese Methode verwendet einen Parameter, den Kontexttyp2d.
Der folgende Code muss geschrieben werden, um den erforderlichen Kontext zu erhalten. Sie können dieses Skript wie unten gezeigt in das Body-Tag schreiben.
<!DOCTYPE HTML>
<html>
<body>
<canvas id = "mycanvas" width = "600" height = "200"></canvas>
<script>
var canvas = document.getElementById('mycanvas');
var context = canvas.getContext('2d');
context.font = '20pt Calibri';
context.fillStyle = 'green';
context.fillText('Welcome to Tutorialspoint', 70, 70);
</script>
</body>
</html>
Bei der Ausführung erzeugt der obige Code die folgende Ausgabe:
Weitere Beispiele zu HTML-5 2D Canvas finden Sie unter folgendem Link HTML-5 Canvas .
WebGL-Kontext
HTML5 Canvas wird auch zum Schreiben von WebGL-Anwendungen verwendet. Um einen WebGL-Rendering-Kontext für das Canvas-Element zu erstellen, müssen Sie die Zeichenfolge übergebenexperimental-webgl, Anstatt von 2d zum canvas.getContext()Methode. Einige Browser unterstützen nur 'webgl'.
<!DOCTYPE html>
<html>
<canvas id = 'my_canvas'></canvas>
<script>
var canvas = document.getElementById('my_canvas');
var gl = canvas.getContext('experimental-webgl');
gl.clearColor(0.9,0.9,0.8,1);
gl.clear(gl.COLOR_BUFFER_BIT);
</script>
</html>
Bei der Ausführung erzeugt der obige Code die folgende Ausgabe:
WebGL ist meistens eine Rasterisierungs-API auf niedriger Ebene und keine 3D-API. Um ein Bild mit WebGL zu zeichnen, müssen Sie einen Vektor übergeben, der das Bild darstellt. Anschließend wird der angegebene Vektor mit OpenGL SL in das Pixelformat konvertiert und das Bild auf dem Bildschirm angezeigt. Das Schreiben einer WebGL-Anwendung umfasst eine Reihe von Schritten, die in diesem Kapitel erläutert werden.
WebGL - Koordinatensystem
Wie bei jedem anderen 3D-System haben Sie in WebGL x-, y- und z-Achsen, wobei die z Achse bedeutet depth. Die Koordinaten in WebGL sind auf (1, 1, 1) und (-1, -1, - 1) beschränkt. Dies bedeutet: Wenn Sie den Bildschirm betrachten, auf dem WebGL-Grafiken als Würfel projiziert werden, ist eine Ecke des Würfels (1, 1, 1) und die gegenüberliegende Ecke (-1, -1, -1). WebGL zeigt nichts an, was über diese Grenzen hinaus gezeichnet wurde.
Das folgende Diagramm zeigt das WebGL-Koordinatensystem. Die z-Achse zeigt die Tiefe an. Ein positiver Wert von z zeigt an, dass sich das Objekt in der Nähe des Bildschirms / Betrachters befindet, während ein negativer Wert von z anzeigt, dass sich das Objekt vom Bildschirm entfernt befindet. Ebenso zeigt ein positiver Wert von x an, dass sich das Objekt auf der rechten Seite des Bildschirms befindet, und ein negativer Wert zeigt an, dass sich das Objekt auf der linken Seite befindet. In ähnlicher Weise geben positive und negative Werte von y an, ob sich das Objekt oben oder unten auf dem Bildschirm befindet.
WebGL-Grafiken
Nachdem Sie den WebGL-Kontext des Canvas-Objekts abgerufen haben, können Sie mit der WebGL-API in JavaScript grafische Elemente zeichnen.
Hier sind einige grundlegende Begriffe, die Sie kennen müssen, bevor Sie mit WebGL beginnen.
Eckpunkte
Um Objekte wie ein Polygon zu zeichnen, markieren wir im Allgemeinen die Punkte in der Ebene und verbinden sie zu einem gewünschten Polygon. EINvertexist ein Punkt, der die Verbindung der Kanten eines 3D-Objekts definiert. Es wird durch drei Gleitkommawerte dargestellt, die jeweils die x-, y- und z-Achse darstellen.
Beispiel
Im folgenden Beispiel zeichnen wir ein Dreieck mit den folgenden Eckpunkten: (0,5, 0,5), (-0,5, 0,5), (-0,5, -0,5).
Note - Wir müssen diese Scheitelpunkte manuell mithilfe von JavaScript-Arrays speichern und sie mithilfe des Scheitelpunktpuffers an die WebGL-Rendering-Pipeline übergeben.
Indizes
In WebGL werden numerische Werte verwendet, um die Eckpunkte zu identifizieren. Diese Zahlenwerte werden als Indizes bezeichnet. Diese Indizes werden zum Zeichnen von Netzen in WebGL verwendet.
Note - Genau wie Vertices speichern wir die Indizes mithilfe von JavaScript-Arrays und übergeben sie mithilfe des Indexpuffers an die WebGL-Rendering-Pipeline.
Arrays
Im Gegensatz zu OpenGL und JoGL gibt es in WebGL keine vordefinierten Methoden zum direkten Rendern der Scheitelpunkte. Wir müssen sie manuell mit JavaScript-Arrays speichern.
Beispiel
var vertices = [ 0.5, 0.5, 0.1,-0.5, 0.5,-0.5]
Puffer
Puffer sind die Speicherbereiche von WebGL, in denen sich die Daten befinden. Es gibt verschiedene Puffer, nämlich Zeichenpuffer, Bildpuffer, Vetexpuffer und Indexpuffer. Dasvertex buffer und index buffer werden verwendet, um die Geometrie des Modells zu beschreiben und zu verarbeiten.
Scheitelpunktpufferobjekte speichern Daten über die Scheitelpunkte, während Indexpufferobjekte Daten über die Indizes speichern. Nachdem die Scheitelpunkte in Arrays gespeichert wurden, übergeben wir sie mithilfe dieser Pufferobjekte an die WegGL-Grafikpipeline.
Frame bufferist ein Teil des Grafikspeichers, der die Szenendaten enthält. Dieser Puffer enthält Details wie Breite und Höhe der Oberfläche (in Pixel), Farbe jedes Pixels, Tiefe und Schablonenpuffer.
Gittergewebe
Zum Zeichnen von 2D- oder 3D-Objekten bietet die WebGL-API zwei Methoden: drawArrays() und drawElements(). Diese beiden Methoden akzeptieren einen Parameter namensmodemit dem Sie das Objekt auswählen können, das Sie zeichnen möchten. Die in diesem Feld bereitgestellten Optionen sind auf Punkte, Linien und Dreiecke beschränkt.
Um ein 3D-Objekt mit diesen beiden Methoden zu zeichnen, müssen wir ein oder mehrere primitive Polygone mit Punkten, Linien oder Dreiecken konstruieren. Danach können wir unter Verwendung dieser primitiven Polygone ein Netz bilden.
Ein 3D-Objekt, das mit primitiven Polygonen gezeichnet wurde, heißt a mesh. WebGL bietet verschiedene Möglichkeiten zum Zeichnen von grafischen 3D-Objekten. Benutzer ziehen es jedoch normalerweise vor, ein Netz zu zeichnen.
Beispiel
Im folgenden Beispiel können Sie beobachten, dass wir ein Quadrat mit zwei Dreiecken → {1, 2, 3} und {4, 1, 3} gezeichnet haben.
Shader-Programme
Normalerweise verwenden wir Dreiecke, um Netze zu konstruieren. Da WebGL GPU-beschleunigtes Computing verwendet, sollten die Informationen zu diesen Dreiecken von der CPU zur GPU übertragen werden, was viel Kommunikationsaufwand erfordert.
WebGL bietet eine Lösung zur Reduzierung des Kommunikationsaufwands. Da ES SL (Embedded System Shader Language) verwendet wird, das auf der GPU ausgeführt wird, schreiben wir alle erforderlichen Programme, um grafische Elemente auf dem Client-System zu zeichnenshader programs (die Programme, die wir mit OpenGL ES Shading Language schreiben / GLSL).
Diese Shader sind die Programme für die GPU und die Sprache, die zum Schreiben von Shader-Programmen verwendet wird, ist GLSL. In diesen Shadern definieren wir genau, wie Scheitelpunkte, Transformationen, Materialien, Lichter und Kamera miteinander interagieren, um ein bestimmtes Bild zu erstellen.
Kurz gesagt, es ist ein Snippet, das Algorithmen implementiert, um Pixel für ein Netz zu erhalten. Wir werden in späteren Kapiteln mehr über Shader diskutieren. Es gibt zwei Arten von Shadern - Vertex Shader und Fragment Shader.
Vertex Shader
Vertext Shader ist der Programmcode, der für jeden Vertex aufgerufen wird. Es wird verwendet, um die Geometrie (z. B. Dreieck) von einem Ort zum anderen zu transformieren (zu verschieben). Es verarbeitet die Daten jedes Scheitelpunkts (Daten pro Scheitelpunkt) wie Scheitelpunktkoordinaten, Normalen, Farben und Texturkoordinaten.
In dem ES GLIm Code des Vertex-Shaders müssen Programmierer Attribute definieren, um mit den Daten umgehen zu können. Diese Attribute zeigen auf aVertex Buffer Object geschrieben in JavaScript.
Die folgenden Aufgaben können mit Vertex-Shadern ausgeführt werden:
- Scheitelpunkttransformation
- Normale Transformation und Normalisierung
- Erzeugung von Texturkoordinaten
- Texturkoordinatentransformation
- Lighting
- Farbmaterialanwendung
Fragment Shader (Pixel Shader)
Ein Netz wird durch mehrere Dreiecke gebildet, und die Oberfläche jedes der Dreiecke ist als a bekannt fragment. Fragment Shader ist der Code, der auf allen Pixeln jedes Fragments ausgeführt wird. Es wurde geschrieben, um die Farbe einzelner Pixel zu berechnen und zu füllen .
Die folgenden Aufgaben können mit Fragment-Shadern ausgeführt werden:
- Operationen mit interpolierten Werten
- Texturzugriff
- Texturanwendung
- Fog
- Farbsumme
OpenGL ES SL-Variablen
Die vollständige Form von OpenGL ES SList OpenGL Embedded System Shading Language. Um die Daten in den Shader-Programmen zu verarbeiten, bietet ES SL drei Arten von Variablen. Sie sind wie folgt -
Attributes- Diese Variablen enthalten die Eingabewerte des Vertex-Shader-Programms. Attribute verweisen auf die Scheitelpunktpufferobjekte, die Daten pro Scheitelpunkt enthalten. Jedes Mal, wenn der Vertex-Shader aufgerufen wird, zeigen die Attribute auf VBO verschiedener Vertices.
Uniforms - Diese Variablen enthalten die Eingabedaten, die sowohl für Scheitelpunkt- als auch für Fragment-Shader gelten, z. B. Lichtposition, Texturkoordinaten und Farbe.
Varyings - Diese Variablen werden verwendet, um die Daten vom Vertex-Shader an den Fragment-Shader zu übergeben.
Mit so vielen Grundlagen werden wir nun die Grafik-Pipeline diskutieren.
Um 3D-Grafiken zu rendern, müssen wir eine Abfolge von Schritten befolgen. Diese Schritte sind bekannt alsgraphics pipeline oder rendering pipeline. Das folgende Diagramm zeigt die WebGL-Grafikpipeline.
In den folgenden Abschnitten werden wir nacheinander die Rolle jedes Schritts in der Pipeline diskutieren.
JavaScript
Während der Entwicklung von WebGL-Anwendungen schreiben wir Shader-Sprachcode für die Kommunikation mit der GPU. JavaScript wird verwendet, um den Steuercode des Programms zu schreiben, der die folgenden Aktionen enthält:
Initialize WebGL - JavaScript wird verwendet, um den WebGL-Kontext zu initialisieren.
Create arrays - Wir erstellen JavaScript-Arrays, um die Daten der Geometrie zu speichern.
Buffer objects - Wir erstellen Pufferobjekte (Vertex und Index), indem wir die Arrays als Parameter übergeben.
Shaders - Wir erstellen, kompilieren und verknüpfen die Shader mit JavaScript.
Attributes - Mit JavaScript können wir Attribute erstellen, aktivieren und mit Pufferobjekten verknüpfen.
Uniforms - Wir können die Uniformen auch mit JavaScript verknüpfen.
Transformation matrix - Mit JavaScript können wir eine Transformationsmatrix erstellen.
Zunächst erstellen wir die Daten für die gewünschte Geometrie und übergeben sie in Form von Puffern an die Shader. Die Attributvariable der Shader-Sprache zeigt auf die Pufferobjekte, die als Eingaben an den Vertex-Shader übergeben werden.
Vertex Shader
Wenn wir den Renderprozess durch Aufrufen der Methoden starten drawElements() und drawArray()wird der Vertex-Shader für jeden im Vertex-Pufferobjekt bereitgestellten Vertex ausgeführt. Es berechnet die Position jedes Scheitelpunkts eines primitiven Polygons und speichert sie in der Variationgl_position. Es berechnet auch die anderen Attribute wiecolor, texture coordinates, und vertices die normalerweise mit einem Scheitelpunkt verbunden sind.
Primitive Versammlung
Nach der Berechnung der Position und anderer Details jedes Scheitelpunkts ist die nächste Phase die primitive assembly stage. Hier werden die Dreiecke zusammengesetzt und an den Rasterer übergeben.
Rasterisierung
Im Rasterungsschritt werden die Pixel im endgültigen Bild des Grundelements bestimmt. Es hat zwei Schritte -
Culling- Zunächst wird die Ausrichtung (nach vorne oder hinten gerichtet?) Des Polygons bestimmt. Alle Dreiecke mit falscher Ausrichtung, die im Ansichtsbereich nicht sichtbar sind, werden verworfen. Dieser Vorgang wird als Keulen bezeichnet.
Clipping- Befindet sich ein Dreieck teilweise außerhalb des Ansichtsbereichs, wird der Teil außerhalb des Ansichtsbereichs entfernt. Dieser Vorgang wird als Clipping bezeichnet.
Fragment Shader
Der Fragment Shader bekommt
- Daten aus dem Vertex-Shader in verschiedenen Variablen,
- Grundelemente aus der Rasterphase und dann
- berechnet die Farbwerte für jedes Pixel zwischen den Eckpunkten.
Der Fragment-Shader speichert die Farbwerte jedes Pixels in jedem Fragment. Auf diese Farbwerte kann während Fragmentoperationen zugegriffen werden, auf die wir als nächstes eingehen werden.
Fragmentoperationen
Fragmentoperationen werden ausgeführt, nachdem die Farbe jedes Pixels im Grundelement bestimmt wurde. Diese Fragmentoperationen können Folgendes umfassen:
- Depth
- Farbpuffermischung
- Dithering
Sobald alle Fragmente verarbeitet sind, wird ein 2D-Bild erstellt und auf dem Bildschirm angezeigt. Dasframe buffer ist das endgültige Ziel der Rendering-Pipeline.
Bildspeicher, Framebuffer
Der Bildpuffer ist ein Teil des Grafikspeichers, der die Szenendaten enthält. Dieser Puffer enthält Details wie Breite und Höhe der Oberfläche (in Pixel), Farbe jedes Pixels sowie Tiefen- und Schablonenpuffer.
Wir haben die Grundlagen von WebGL und der WebGL-Pipeline besprochen (ein Verfahren zum Rendern von Grafikanwendungen). In diesem Kapitel nehmen wir eine Beispielanwendung, um mit WebGL ein Dreieck zu erstellen, und befolgen die in der Anwendung befolgten Schritte.
Struktur der WebGL-Anwendung
Der WebGL-Anwendungscode ist eine Kombination aus JavaScript und OpenGL Shader Language.
- Für die Kommunikation mit der CPU ist JavaScript erforderlich
- Für die Kommunikation mit der GPU ist OpenGL Shader Language erforderlich.
Beispielanwendung
Nehmen wir nun ein einfaches Beispiel, um zu lernen, wie Sie mit WebGL ein einfaches Dreieck mit 2D-Koordinaten zeichnen.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/* Step1: Prepare the canvas and get WebGL context */
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
/* Step2: Define the geometry and store it in buffer objects */
var vertices = [-0.5, 0.5, -0.5, -0.5, 0.0, -0.5,];
// Create a new buffer object
var vertex_buffer = gl.createBuffer();
// Bind an empty array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertices data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/* Step3: Create and compile Shader programs */
// Vertex shader source code
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' + ' gl_Position = vec4(coordinates,0.0, 1.0);' + '}';
//Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
//Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
//Compile the vertex shader
gl.compileShader(vertShader);
//Fragment shader source code
var fragCode = 'void main(void) {' + 'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' + '}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragment shader
gl.compileShader(fragShader);
// Create a shader program object to store combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* Step 4: Associate the shader programs to buffer objects */
//Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
//point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 2, gl.FLOAT, false, 0, 0);
//Enable the attribute
gl.enableVertexAttribArray(coord);
/* Step5: Drawing the required object (triangle) */
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Es wird das folgende Ergebnis erzeugt -
Wenn Sie das obige Programm sorgfältig beobachten, haben wir fünf aufeinanderfolgende Schritte ausgeführt, um mit WebGL ein einfaches Dreieck zu zeichnen. Die Schritte sind wie folgt:
Step 1 − Prepare the canvas and get WebGL rendering context
Wir erhalten das aktuelle HTML-Canvas-Objekt und erhalten dessen WebGL-Rendering-Kontext.
Step 2 − Define the geometry and store it in buffer objects
Wir definieren die Attribute der Geometrie wie Scheitelpunkte, Indizes, Farben usw. und speichern sie in den JavaScript-Arrays. Anschließend erstellen wir ein oder mehrere Pufferobjekte und übergeben die Arrays mit den Daten an das jeweilige Pufferobjekt. Im Beispiel speichern wir die Scheitelpunkte des Dreiecks in einem JavaScript-Array und übergeben dieses Array an ein Scheitelpunktpufferobjekt.
Step 3 − Create and compile Shader programs
Wir schreiben Vertex-Shader- und Fragment-Shader-Programme, kompilieren sie und erstellen ein kombiniertes Programm, indem wir diese beiden Programme verbinden.
Step 4 − Associate the shader programs with buffer objects
Wir verknüpfen die Pufferobjekte und das kombinierte Shader-Programm.
Step 5 − Drawing the required object (triangle)
Dieser Schritt umfasst Vorgänge wie das Löschen der Farbe, das Löschen des Pufferbits, das Aktivieren des Tiefentests, das Festlegen des Ansichtsfensters usw. Schließlich müssen Sie die erforderlichen Grundelemente mit einer der folgenden Methoden zeichnen: drawArrays() oder drawElements().
Alle diese Schritte werden in diesem Tutorial näher erläutert.
Um eine WebGL-Anwendung zu schreiben, müssen Sie zunächst das WebGL-Rendering-Kontextobjekt abrufen. Dieses Objekt interagiert mit dem WebGL-Zeichenpuffer und kann alle WebGL-Methoden aufrufen. Die folgenden Vorgänge werden ausgeführt, um den WebGL-Kontext abzurufen:
- Erstellen Sie eine HTML-5-Zeichenfläche
- Holen Sie sich die Canvas-ID
- Erhalten Sie WebGL
Erstellen eines HTML-5-Canvas-Elements
In Kapitel 5 haben wir erläutert, wie ein HTML-5-Canvas-Element erstellt wird. Schreiben Sie im Hauptteil des HTML-5-Dokuments eine Zeichenfläche, geben Sie ihr einen Namen und übergeben Sie sie als Parameter an die Attribut-ID. Sie können die Abmessungen der Leinwand mithilfe der Attribute width und height definieren (optional).
Beispiel
Das folgende Beispiel zeigt, wie Sie ein Canvas-Element mit den Abmessungen 500 × 500 erstellen. Wir haben mit CSS einen Rahmen für die Canvas erstellt, um die Sichtbarkeit zu gewährleisten. Kopieren Sie den folgenden Code und fügen Sie ihn in eine Datei mit dem Namen einmy_canvas.html.
<!DOCTYPE HTML>
<html>
<head>
<style>
#mycanvas{border:1px solid blue;}
</style>
</head>
<body>
<canvas id = "mycanvas" width = "300" height = "300"></canvas>
</body>
</html>
Es wird das folgende Ergebnis erzeugt -
Holen Sie sich die Canvas ID
Nach dem Erstellen der Zeichenfläche müssen Sie den WebGL-Kontext abrufen. Um einen WebGL-Zeichnungskontext abzurufen, müssen Sie zunächst die ID des aktuellen Canvas-Elements abrufen.
Die Canvas-ID wird durch Aufrufen der DOM-Methode (Document Object Model) ermittelt getElementById(). Diese Methode akzeptiert einen Zeichenfolgenwert als Parameter, daher übergeben wir den Namen der aktuellen Zeichenfläche.
Zum Beispiel, wenn der Canvas-Name lautet my_canvasDann wird die Canvas-ID wie unten gezeigt erhalten
var canvas = document.getElementById('my_Canvas');
Rufen Sie den WebGL-Zeichnungskontext ab
Um das WebGLRenderingContext-Objekt (oder das WebGL Drawing-Kontextobjekt oder einfach den WebGL-Kontext) abzurufen, rufen Sie das auf getContext() Methode des Stroms HTMLCanvasElement. Die Syntax von getContext () lautet wie folgt:
canvas.getContext(contextType, contextAttributes);
Übergeben Sie die Saiten webgl oder experimental-webgl als die contentType. DascontextAttributesParameter ist optional. (Stellen Sie in diesem Schritt sicher, dass Ihr Browser WebGL Version 1 (OpenGL ES 2.0) implementiert .)
Das folgende Codefragment zeigt, wie Sie den WebGL-Rendering-Kontext erhalten. Hiergl ist die Referenzvariable für das erhaltene Kontextobjekt.
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
WebGLContextAttributes
Der Parameter WebGLContextAttributesist nicht obligatorisch. Dieser Parameter bietet verschiedene Optionen, die Boolesche Werte akzeptieren, wie unten aufgeführt -
Sr.Nr. | Attribute & Beschreibung |
---|---|
1 | Alpha Wenn der Wert true ist, wird der Zeichenfläche ein Alpha-Puffer bereitgestellt. Standardmäßig ist der Wert true. |
2 | depth Wenn der Wert true ist, erhalten Sie einen Zeichenpuffer, der einen Tiefenpuffer von mindestens 16 Bit enthält. Standardmäßig ist der Wert true. |
3 | stencil Wenn der Wert true ist, erhalten Sie einen Zeichenpuffer, der einen Schablonenpuffer von mindestens 8 Bit enthält. Standardmäßig ist der Wert false. |
4 | antialias Wenn der Wert true ist, erhalten Sie einen Zeichenpuffer, der ein Anti-Aliasing ausführt. Standardmäßig ist der Wert true. |
5 | premultipliedAlpha Wenn der Wert true ist, erhalten Sie einen Zeichenpuffer, der Farben mit vormultipliziertem Alpha enthält. Standardmäßig ist der Wert true. |
6 | preserveDrawingBuffer Wenn der Wert true ist, werden die Puffer nicht gelöscht und behalten ihre Werte bei, bis sie vom Autor gelöscht oder überschrieben werden. Standardmäßig ist der Wert false. |
Das folgende Codeausschnitt zeigt, wie ein WebGL-Kontext mit einem Schablonenpuffer erstellt wird, der nicht funktioniert anti-aliasing.
var canvas = document.getElementById('canvas1');
var context = canvas.getContext('webgl', { antialias: false, stencil: true });
Zum Zeitpunkt der Erstellung des WebGLRenderingContext wird ein Zeichenpuffer erstellt. Das Context-Objekt verwaltet den OpenGL-Status und rendert in den Zeichenpuffer.
WebGLRenderingContext
Es ist die Hauptschnittstelle in WebGL. Es repräsentiert den WebGL-Zeichnungskontext. Diese Schnittstelle enthält alle Methoden, mit denen verschiedene Aufgaben im Zeichenpuffer ausgeführt werden. Die Attribute dieser Schnittstelle sind in der folgenden Tabelle angegeben.
Sr.Nr. | Attribute & Beschreibung |
---|---|
1 | Canvas Dies ist ein Verweis auf das Canvas-Element, das diesen Kontext erstellt hat. |
2 | drawingBufferWidth Dieses Attribut repräsentiert die tatsächliche Breite des Zeichenpuffers. Es kann vom width-Attribut des HTMLCanvasElement abweichen. |
3 | drawingBufferHeight Dieses Attribut repräsentiert die tatsächliche Höhe des Zeichenpuffers. Es kann vom Höhenattribut des HTMLCanvasElement abweichen. |
Nachdem Sie den WebGL-Kontext erhalten haben, müssen Sie die Geometrie für das Grundelement (Objekt, das Sie zeichnen möchten) definieren und speichern. In WebGL definieren wir die Details einer Geometrie - zum Beispiel Scheitelpunkte, Indizes, Farbe des Grundelements - mithilfe von JavaScript-Arrays. Um diese Details an die Shader-Programme zu übergeben, müssen wir die Pufferobjekte erstellen und die JavaScript-Arrays, die die Daten enthalten, in den jeweiligen Puffern speichern (anhängen).
Note: Später werden diese Pufferobjekte den Attributen des Shader-Programms (Vertex-Shader) zugeordnet.
Definieren der erforderlichen Geometrie
Ein 2D- oder 3D-Modell, das mit Scheitelpunkten gezeichnet wurde, wird als a bezeichnet mesh. Jede Facette in einem Netz heißt apolygon und ein Polygon besteht aus 3 oder mehr Eckpunkten.
Um Modelle im WebGL-Rendering-Kontext zu zeichnen, müssen Sie die Scheitelpunkte und Indizes mithilfe von JavaScript-Arrays definieren. Wenn Sie beispielsweise ein Dreieck erstellen möchten, das auf den Koordinaten {(5,5), (-5,5), (-5, -5)} liegt, wie im Diagramm gezeigt, können Sie ein Array für erstellen die Eckpunkte als -
var vertices = [
0.5,0.5, //Vertex 1
0.5,-0.5, //Vertex 2
-0.5,-0.5, //Vertex 3
];
Ebenso können Sie ein Array für die Indizes erstellen. Indizes für die obigen Dreiecksindizes sind [0, 1, 2] und können definiert werden als -
var indices = [ 0,1,2 ]
Betrachten Sie zum besseren Verständnis von Indizes komplexere Modelle wie Quadrat. Wir können ein Quadrat als eine Menge von zwei Dreiecken darstellen. Wenn (0,3,1) und (3,1,2) die beiden Dreiecke sind, mit denen wir ein Quadrat zeichnen wollen, werden die Indizes definiert als -
var indices = [0,3,1,3,1,2];
Note - -
Zum Zeichnen von Grundelementen bietet WebGL die folgenden zwei Methoden:
drawArrays() - Bei Verwendung dieser Methode übergeben wir die Eckpunkte des Grundelements mithilfe von JavaScript-Arrays.
drawElements() - Bei Verwendung dieser Methode übergeben wir sowohl Scheitelpunkte als auch Indizes des Grundelements mithilfe eines JavaScript-Arrays.
Pufferobjekte
Ein Pufferobjekt ist ein von WebGL bereitgestellter Mechanismus, der einen im System zugewiesenen Speicherbereich angibt. In diesen Pufferobjekten können Sie Daten des Modells speichern, das Sie zeichnen möchten, entsprechend Scheitelpunkten, Indizes, Farben usw.
Mit diesen Pufferobjekten können Sie über eine seiner Attributvariablen mehrere Daten an das Shader-Programm (Vertex-Shader) übergeben. Da sich diese Pufferobjekte im GPU-Speicher befinden, können sie direkt gerendert werden, was wiederum die Leistung verbessert.
Um Geometrie zu verarbeiten, gibt es zwei Arten von Pufferobjekten. Sie sind -
Vertex buffer object (VBO)- Es enthält die Daten pro Scheitelpunkt des grafischen Modells, das gerendert werden soll. Wir verwenden Scheitelpunktpufferobjekte in WebGL, um die Daten zu Scheitelpunkten wie Scheitelpunktkoordinaten, Normalen, Farben und Texturkoordinaten zu speichern und zu verarbeiten.
Index buffer objects (IBO) - Es enthält die Indizes (Indexdaten) des grafischen Modells, das gerendert werden soll.
Nachdem Sie die erforderliche Geometrie definiert und in JavaScript-Arrays gespeichert haben, müssen Sie diese Arrays an die Pufferobjekte übergeben, von wo aus die Daten an die Shader-Programme übergeben werden. Die folgenden Schritte sind auszuführen, um Daten in den Puffern zu speichern.
Erstellen Sie einen leeren Puffer.
Binden Sie ein geeignetes Array-Objekt an den leeren Puffer.
Übergeben Sie die Daten (Eckpunkte / Indizes) mit einem der folgenden Elemente an den Puffer typed arrays.
Entbinden Sie den Puffer (optional).
Puffer erstellen
Um ein leeres Pufferobjekt zu erstellen, bietet WebGL eine Methode namens createBuffer(). Diese Methode gibt ein neu erstelltes Pufferobjekt zurück, wenn die Erstellung erfolgreich war. Andernfalls wird im Fehlerfall ein Nullwert zurückgegeben.
WebGL arbeitet als Zustandsmaschine. Sobald ein Puffer erstellt wurde, wird jede nachfolgende Pufferoperation für den aktuellen Puffer ausgeführt, bis wir ihn lösen. Verwenden Sie den folgenden Code, um einen Puffer zu erstellen -
var vertex_buffer = gl.createBuffer();
Note - - gl ist die Referenzvariable für den aktuellen WebGL-Kontext.
Binden Sie den Puffer
Nachdem Sie ein leeres Pufferobjekt erstellt haben, müssen Sie einen geeigneten Array-Puffer (Ziel) daran binden. WebGL bietet eine Methode namensbindBuffer() für diesen Zweck.
Syntax
Die Syntax von bindBuffer() Methode ist wie folgt -
void bindBuffer (enum target, Object buffer)
Diese Methode akzeptiert zwei Parameter und sie werden unten diskutiert.
target- Die erste Variable ist ein Aufzählungswert, der den Typ des Puffers darstellt, den wir an den leeren Puffer binden möchten. Sie haben zwei vordefinierte Aufzählungswerte als Optionen für diesen Parameter. Sie sind -
ARRAY_BUFFER welches Scheitelpunktdaten darstellt.
ELEMENT_ARRAY_BUFFER welches Indexdaten darstellt.
Object buffer- Die zweite ist die Referenzvariable für das im vorherigen Schritt erstellte Pufferobjekt. Die Referenzvariable kann ein Scheitelpunktpufferobjekt oder ein Indexpufferobjekt sein.
Beispiel
Das folgende Codeausschnitt zeigt, wie die bindBuffer () -Methode verwendet wird.
//vertex buffer
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//Index buffer
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
Daten an den Puffer übergeben
Der nächste Schritt besteht darin, die Daten (Eckpunkte / Indizes) an den Puffer zu übergeben. Bis jetzt haben Daten die Form eines Arrays. Bevor wir sie an den Puffer übergeben, müssen wir sie in eines der Arrays vom Typ WebGL einschließen. WebGL bietet eine Methode mit dem NamenbufferData() für diesen Zweck.
Syntax
Die Syntax der bufferData () -Methode lautet wie folgt:
void bufferData (enum target, Object data, enum usage)
Diese Methode akzeptiert drei Parameter und sie werden unten diskutiert -
target - Der erste Parameter ist ein Aufzählungswert, der den Typ des von uns verwendeten Array-Puffers darstellt. Die Optionen für diesen Parameter sind -
ARRAY_BUFFER welches darstellt vertex data.
ELEMENT_ARRAY_BUFFER welches darstellt index data.
Object data- Der zweite Parameter ist der Objektwert, der die Daten enthält, die in das Pufferobjekt geschrieben werden sollen. Hier müssen wir die Daten mit weitergebentyped arrays.
Usage- Der dritte Parameter dieser Methode ist eine Enum-Variable, die angibt, wie die Pufferobjektdaten (gespeicherte Daten) zum Zeichnen von Formen verwendet werden. Es gibt drei Optionen für diesen Parameter, wie unten aufgeführt.
gl.STATIC_DRAW - Daten werden einmal angegeben und mehrfach verwendet.
gl.STREAM_DRAW - Die Daten werden einmal angegeben und einige Male verwendet.
gl.DYNAMIC_DRAW - Daten werden wiederholt angegeben und mehrfach verwendet.
Beispiel
Das folgende Codeausschnitt zeigt, wie Sie das verwenden bufferData()Methode. Angenommen, Scheitelpunkte und Indizes sind die Arrays, die die Scheitelpunkt- bzw. Indexdaten enthalten.
//vertex buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//Index buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
Typisierte Arrays
WebGL bietet einen speziellen Array-Typ namens typed arraysum die Datenelemente wie Indexscheitelpunkt und Textur zu übertragen. Diese typisierten Arrays speichern große Datenmengen und verarbeiten sie im nativen Binärformat, was zu einer besseren Leistung führt. Die von WebGL verwendeten typisierten Arrays sind Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, UInt32Array, Float32Array und Float64Array.
Note
Im Allgemeinen verwenden wir zum Speichern von Scheitelpunktdaten Float32Array;; und um Indexdaten zu speichern, verwenden wirUint16Array.
Sie können typisierte Arrays wie JavaScript-Arrays mit erstellen new Stichwort.
Löse die Puffer
Es wird empfohlen, die Puffer nach der Verwendung zu lösen. Dies kann durch Übergeben eines Nullwerts anstelle des Pufferobjekts erfolgen, wie unten gezeigt.
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
WebGL bietet die folgenden Methoden zum Ausführen von Pufferoperationen:
Sr.Nr. | Methoden und Beschreibung |
---|---|
1 | Leere bindBuffer(ENUM Ziel , Objekt - Puffer ) Ziel - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
2 | Leere bufferData(Enum Ziel , lange Größe , Enum Nutzung ) Ziel - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER Verwendung - STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW |
3 | Leere bufferData(ENUM Ziel , Objekt - Daten , ENUM - Nutzung ) Ziel und Verwendung - Wie fürbufferData über |
4 | Leere bufferSubData(ENUM Ziel , lange Offset , Objekt - Daten ) Ziel - ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER |
5 | Objekt createBuffer() |
6 | Leere deleteBuffer(Object - Puffer ) |
7 | irgendein getBufferParameter(enum target , enum pname ) Ziel - ARRAY_BUFFER, ELEMENT_ ARRAY_BUFFER pname - BUFFER_SIZE, BUFFER_USAGE |
8 | Bool isBuffer(Object - Puffer ) |
Shader sind die Programme, die auf der GPU ausgeführt werden. Shader sind in OpenGL ES Shader Language (bekannt als ES SL) geschrieben. ES SL verfügt über eigene Variablen, Datentypen, Qualifizierer, integrierte Ein- und Ausgänge.
Datentypen
In der folgenden Tabelle sind die von OpenGL ES SL bereitgestellten Basisdatentypen aufgeführt.
Sr.Nr. | Typ & Beschreibung |
---|---|
1 | void Stellt einen leeren Wert dar. |
2 | bool Akzeptiert wahr oder falsch. |
3 | int Dies ist ein vorzeichenbehafteter ganzzahliger Datentyp. |
4 | float Dies ist ein schwebender skalarer Datentyp. |
5 | vec2, vec3, vec4 Gleitkomma-Vektor mit n Komponenten |
6 | bvec2, bvec3, bvec4 Boolescher Vektor |
7 | ivec2, ivec3, ivec4 Ganzzahlvektor mit Vorzeichen |
8 | mat2, mat3, mat4 2x2, 3x3, 4x4 Float Matrix |
9 | sampler2D Greifen Sie auf eine 2D-Textur zu |
10 | samplerCube Zugriff auf die Würfel-zugeordnete Textur |
Qualifikanten
Es gibt drei Hauptqualifikanten in OpenGL ES SL -
Sr.Nr. | Qualifier & Beschreibung |
---|---|
1 | attribute Dieses Qualifikationsmerkmal fungiert als Verbindung zwischen einem Vertex-Shader und OpenGL ES für Daten pro Vertex. Der Wert dieses Attributs ändert sich bei jeder Ausführung des Vertex-Shaders. |
2 | uniform Dieses Qualifikationsmerkmal verknüpft Shader-Programme und die WebGL-Anwendung. Im Gegensatz zum Attributqualifizierer ändern sich die Werte von Uniformen nicht. Uniformen sind schreibgeschützt; Sie können sie mit allen grundlegenden Datentypen verwenden, um eine Variable zu deklarieren. Example - Uniform vec4 lightPosition; |
3 | varying Dieses Qualifikationsmerkmal bildet eine Verbindung zwischen einem Vertex-Shader und einem Fragment-Shader für interpolierte Daten. Es kann mit den folgenden Datentypen verwendet werden: float, vec2, vec3, vec4, mat2, mat3, mat4 oder Arrays. Example - variieren vec3 normal; |
Vertex Shader
Vertex Shader ist ein Programmcode, der auf jedem Vertex aufgerufen wird. Es transformiert (verschiebt) die Geometrie (zB Dreieck) von einem Ort zum anderen. Es verarbeitet die Daten jedes Scheitelpunkts (Daten pro Scheitelpunkt) wie Scheitelpunktkoordinaten, Normalen, Farben und Texturkoordinaten.
Im ES GL-Code des Vertex Shader müssen Programmierer Attribute definieren, um Daten zu verarbeiten. Diese Attribute verweisen auf ein in JavaScript geschriebenes Vertex-Pufferobjekt. Die folgenden Aufgaben können mit Vertex-Shadern zusammen mit der Vertex-Transformation ausgeführt werden:
- Scheitelpunkttransformation
- Normale Transformation und Normalisierung
- Erzeugung von Texturkoordinaten
- Texturkoordinatentransformation
- Lighting
- Farbmaterialanwendung
Vordefinierte Variablen
OpenGL ES SL bietet die folgenden vordefinierten Variablen für den Vertex-Shader:
Sr.Nr. | Variablen & Beschreibung |
---|---|
1 | highp vec4 gl_Position; Hält die Position des Scheitelpunkts. |
2 | mediump float gl_PointSize; Enthält die transformierte Punktgröße. Die Einheiten für diese Variable sind Pixel. |
Beispielcode
Sehen Sie sich den folgenden Beispielcode eines Vertex-Shaders an. Es verarbeitet die Eckpunkte eines Dreiecks.
attribute vec2 coordinates;
void main(void) {
gl_Position = vec4(coordinates, 0.0, 1.0);
};
Wenn Sie den obigen Code sorgfältig beachten, haben wir eine Attributvariable mit dem Namen deklariert coordinates. (Diese Variable wird mithilfe der Methode dem Vertex Buffer Object zugeordnetgetAttribLocation(). Das Attributcoordinates wird zusammen mit dem Shader-Programmobjekt als Parameter an diese Methode übergeben.)
Im zweiten Schritt des angegebenen Vertex-Shader-Programms wird der gl_position Variable ist definiert.
gl_Position
gl_Position ist die vordefinierte Variable, die nur im Vertex-Shader-Programm verfügbar ist. Es enthält die Scheitelpunktposition. Im obigen Code ist diecoordinatesDas Attribut wird in Form eines Vektors übergeben. Da der Vertex-Shader eine Operation pro Vertex ist, wird der Wert gl_position für jeden Vertex berechnet.
Später wird der Wert gl_position von primitiven Assemblierungs-, Clipping-, Culling- und anderen Operationen mit fester Funktionalität verwendet, die nach Abschluss der Vertex-Verarbeitung auf den Primitiven ausgeführt werden.
Wir können Vertex-Shader-Programme für alle möglichen Operationen des Vertex-Shaders schreiben, die wir in diesem Tutorial einzeln behandeln werden.
Fragment Shader
EIN mesh wird durch mehrere Dreiecke gebildet, und die Oberfläche jedes Dreiecks ist als a bekannt fragment. Ein Fragment-Shader ist der Code, der auf jedem Pixel jedes Fragments ausgeführt wird. Dies wird geschrieben, um die Farbe einzelner Pixel zu berechnen und zu füllen. Die folgenden Aufgaben können mit Fragment-Shadern ausgeführt werden:
- Operationen mit interpolierten Werten
- Texturzugriff
- Texturanwendung
- Fog
- Farbsumme
Vordefinierte Variablen
OpenGL ES SL bietet die folgenden vordefinierten Variablen für den Fragment-Shader:
Sr.Nr. | Variablen & Beschreibung |
---|---|
1 | mittelp vec4 gl_FragCoord;; Hält die Fragmentposition innerhalb des Bildpuffers. |
2 | bool gl_FrontFacing; Enthält das Fragment, das zu einem nach vorne gerichteten Grundelement gehört. |
3 | mediump vec2 gl_PointCoord; Hält die Fragmentposition innerhalb eines Punktes (nur Punktrasterung). |
4 | mediump vec4 gl_FragColor; Enthält den Farbwert des Ausgabefragments des Shaders |
5 | mediump vec4 gl_FragData[n] Hält die Fragmentfarbe für die Farbbefestigung n. |
Beispielcode
Der folgende Beispielcode eines Fragment-Shaders zeigt, wie jedem Pixel in einem Dreieck Farbe zugewiesen wird.
void main(void) {
gl_FragColor = vec4(0, 0.8, 0, 1);
}
Im obigen Code ist die colorWert wird in der Variablen gespeichert gl.FragColor
. Das Fragment-Shader-Programm übergibt die Ausgabe unter Verwendung fester Funktionsvariablen an die Pipeline. FragColor ist einer von ihnen. Diese Variable enthält den Farbwert der Pixel des Modells.
Speichern und Kompilieren der Shader-Programme
Da Shader unabhängige Programme sind, können wir sie als separates Skript schreiben und in der Anwendung verwenden. Oder Sie können sie direkt in speichernstring Format wie unten gezeigt.
var vertCode =
'attribute vec2 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 0.0, 1.0);' +
'}';
Shader kompilieren
Die Kompilierung umfasst die folgenden drei Schritte:
- Erstellen des Shader-Objekts
- Anhängen des Quellcodes an das erstellte Shader-Objekt
- Programm kompilieren
Erstellen des Vertex Shader
Um einen leeren Shader zu erstellen, bietet WebGL eine Methode namens createShader(). Es erstellt und gibt das Shader-Objekt zurück. Die Syntax lautet wie folgt:
Object createShader (enum type)
Wie in der Syntax angegeben, akzeptiert diese Methode einen vordefinierten Aufzählungswert als Parameter. Wir haben zwei Möglichkeiten dafür -
gl.VERTEX_SHADER zum Erstellen eines Vertex-Shaders
gl.FRAGMENT_SHADER zum Erstellen eines Fragment-Shaders.
Anhängen der Quelle an den Shader
Mit der Methode können Sie den Quellcode an das erstellte Shader-Objekt anhängen shaderSource(). Die Syntax lautet wie folgt:
void shaderSource(Object shader, string source)
Diese Methode akzeptiert zwei Parameter -
shader - Sie müssen das erstellte Shader-Objekt als einen Parameter übergeben.
Source - Sie müssen den Shader-Programmcode im String-Format übergeben.
Programm kompilieren
Um das Programm zu kompilieren, müssen Sie die Methode verwenden compileShader(). Die Syntax lautet wie folgt:
compileShader(Object shader)
Diese Methode akzeptiert das Shader-Programmobjekt als Parameter. Fügen Sie nach dem Erstellen eines Shader-Programmobjekts den Quellcode hinzu und übergeben Sie dieses Objekt an diese Methode.
Das folgende Codefragment zeigt, wie Sie einen Vertex-Shader sowie einen Fragment-Shader erstellen und kompilieren, um ein Dreieck zu erstellen.
// Vertex Shader
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
// Fragment Shader
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0, 0.8, 0, 1);' +
'}';
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
Kombiniertes Programm
Nachdem Sie beide Shader-Programme erstellt und kompiliert haben, müssen Sie ein kombiniertes Programm erstellen, das beide Shader (Vertex & Fragment) enthält. Die folgenden Schritte müssen befolgt werden:
- Erstellen Sie ein Programmobjekt
- Befestigen Sie beide Shader
- Verbinde beide Shader
- Verwenden Sie das Programm
Erstellen Sie ein Programmobjekt
Erstellen Sie mit der Methode ein Programmobjekt createProgram(). Es wird ein leeres Programmobjekt zurückgegeben. Hier ist seine Syntax -
createProgram();
Befestigen Sie die Shader
Hängen Sie die Shader mit der Methode an das erstellte Programmobjekt an attachShader(). Die Syntax lautet wie folgt:
attachShader(Object program, Object shader);
Diese Methode akzeptiert zwei Parameter -
Program - Übergeben Sie das erstellte leere Programmobjekt als einen Parameter.
Shader - Übergeben Sie eines der kompilierten Shader-Programme (Vertex-Shader, Fragment-Shader).
Note - Sie müssen beide Shader mit dieser Methode anbringen.
Verbinde die Shader
Verknüpfen Sie die Shader mit der Methode linkProgram(), indem Sie das Programmobjekt übergeben, an das Sie die Shader angehängt haben. Die Syntax lautet wie folgt:
linkProgram(shaderProgram);
Verwenden Sie das Programm
WebGL bietet eine Methode namens useProgram(). Sie müssen das verknüpfte Programm daran übergeben. Die Syntax lautet wie folgt:
useProgram(shaderProgram);
Das folgende Codefragment zeigt, wie Sie ein kombiniertes Shader-Programm erstellen, verknüpfen und verwenden.
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
Jedes Attribut im Vertex-Shader-Programm zeigt auf ein Vertex-Pufferobjekt. Nach dem Erstellen der Vertex-Pufferobjekte müssen Programmierer sie den Attributen des Vertex-Shader-Programms zuordnen. Jedes Attribut zeigt nur auf ein Scheitelpunktpufferobjekt, aus dem die Datenwerte extrahiert werden. Anschließend werden diese Attribute an das Shader-Programm übergeben.
Um die Vertex-Pufferobjekte den Attributen des Vertex-Shader-Programms zuzuordnen, müssen Sie die folgenden Schritte ausführen:
- Holen Sie sich die Attributposition
- Zeigen Sie mit dem Attribut auf ein Scheitelpunktpufferobjekt
- Aktivieren Sie das Attribut
Holen Sie sich den Attributspeicherort
WebGL bietet eine Methode namens getAttribLocation()Dies gibt den Attributspeicherort zurück. Die Syntax lautet wie folgt:
ulong getAttribLocation(Object program, string name)
Diese Methode akzeptiert das Vertex-Shader-Programmobjekt und die Attributwerte des Vertex-Shader-Programms.
Das folgende Codefragment zeigt, wie diese Methode verwendet wird.
var coordinatesVar = gl.getAttribLocation(shader_program, "coordinates");
Hier, shader_program ist das Objekt des Shader-Programms und coordinates ist das Attribut des Vertex-Shader-Programms.
Zeigen Sie mit dem Attribut auf einen VBO
Um das Pufferobjekt der Attributvariablen zuzuweisen, bietet WebGL eine Methode namens vertexAttribPointer(). Hier ist die Syntax dieser Methode -
void vertexAttribPointer(location, int size, enum type, bool normalized, long stride, long offset)
Diese Methode akzeptiert sechs Parameter und sie werden unten diskutiert.
Location- Es gibt den Speicherort einer Attributvariablen an. Bei dieser Option müssen Sie den vom übergebenen Wert übergebengetAttribLocation() Methode.
Size - Gibt die Anzahl der Komponenten pro Scheitelpunkt im Pufferobjekt an.
Type - Es gibt den Datentyp an.
Normalized- Dies ist ein boolescher Wert. Wenn true, werden nicht schwebende Daten auf [0, 1] normalisiert. Andernfalls wird es auf [-1, 1] normalisiert.
Stride - Gibt die Anzahl der Bytes zwischen verschiedenen Scheitelpunktdatenelementen oder Null für den Standardschritt an.
Offset- Es gibt den Versatz (in Bytes) in einem Pufferobjekt an, um anzugeben, von welchem Byte die Scheitelpunktdaten gespeichert werden. Wenn die Daten von Anfang an gespeichert werden, beträgt der Offset 0.
Das folgende Snippet zeigt die Verwendung vertexAttribPointer() in einem Programm -
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
Aktivieren des Attributs
Aktivieren Sie das Vertex-Shader-Attribut, um auf das Pufferobjekt in einem Vertex-Shader zuzugreifen. Für diesen Vorgang stellt WebGL bereitenableVertexAttribArray()Methode. Diese Methode akzeptiert die Position des Attributs als Parameter. So verwenden Sie diese Methode in einem Programm:
gl.enableVertexAttribArray(coordinatesVar);
Nachdem die Puffer den Shadern zugeordnet wurden, besteht der letzte Schritt darin, die erforderlichen Grundelemente zu zeichnen. WebGL bietet zwei Methoden, nämlichdrawArrays() und drawElements() Modelle zeichnen.
drawArrays ()
drawArrays()ist die Methode, mit der Modelle mithilfe von Scheitelpunkten gezeichnet werden. Hier ist seine Syntax -
void drawArrays(enum mode, int first, long count)
Diese Methode verwendet die folgenden drei Parameter:
mode- In WebGL werden Modelle mit primitiven Typen gezeichnet. Im Modus müssen Programmierer einen der von WebGL bereitgestellten primitiven Typen auswählen. Die möglichen Werte für diese Option sind - gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN und gl.TRIANGLES.
first- Diese Option gibt das Startelement in den aktivierten Arrays an. Es kann kein negativer Wert sein.
count - Diese Option gibt die Anzahl der zu rendernden Elemente an.
Wenn Sie ein Modell mit zeichnen drawArrays() Methode, dann erstellt WebGL beim Rendern der Formen die Geometrie in der Reihenfolge, in der die Scheitelpunktkoordinaten definiert sind.
Beispiel
Wenn Sie ein einzelnes Dreieck mit zeichnen möchten drawArray() Methode, dann müssen Sie drei Eckpunkte übergeben und die aufrufen drawArrays() Methode, wie unten gezeigt.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 3);
Es wird ein Dreieck wie unten gezeigt erzeugt.
Angenommen, Sie möchten zusammenhängende Dreiecke zeichnen, dann müssen Sie die nächsten drei Scheitelpunkte der Reihe nach im Scheitelpunktpuffer übergeben und die Anzahl der zu rendernden Elemente als 6 angeben.
var vertices = [-0.5,-0.5, -0.25,0.5, 0.0,-0.5, 0.0,-0.5, 0.25,0.5, 0.5,-0.5,];
gl.drawArrays(gl.TRIANGLES, 0, 6);
Es wird ein zusammenhängendes Dreieck erzeugt, wie unten gezeigt.
drawElements ()
drawElements()ist die Methode, mit der Modelle mithilfe von Scheitelpunkten und Indizes gezeichnet werden. Die Syntax lautet wie folgt:
void drawElements(enum mode, long count, enum type, long offset)
Diese Methode verwendet die folgenden vier Parameter:
mode- WebGL-Modelle werden mit primitiven Typen gezeichnet. Im Modus müssen Programmierer einen der von WebGL bereitgestellten primitiven Typen auswählen. Die Liste der möglichen Werte für diese Option lautet: gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN und gl.TRIANGLES.
count - Diese Option gibt die Anzahl der zu rendernden Elemente an.
type - Diese Option gibt den Datentyp der Indizes an, die UNSIGNED_BYTE oder UNSIGNED_SHORT sein müssen.
offset- Diese Option gibt den Startpunkt für das Rendern an. Es ist normalerweise das erste Element (0).
Wenn Sie ein Modell mit zeichnen drawElements()Methode sollte dann auch das Indexpufferobjekt zusammen mit dem Scheitelpunktpufferobjekt erstellt werden. Wenn Sie diese Methode verwenden, werden die Scheitelpunktdaten einmal verarbeitet und so oft verwendet, wie in den Indizes angegeben.
Beispiel
Wenn Sie ein einzelnes Dreieck mit Indizes zeichnen möchten, müssen Sie die Indizes zusammen mit den Scheitelpunkten übergeben und die aufrufen drawElements() Methode wie unten gezeigt.
var vertices = [ -0.5,-0.5,0.0, -0.25,0.5,0.0, 0.0,-0.5,0.0 ];
var indices = [0,1,2];
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Es wird die folgende Ausgabe erzeugt -
Wenn Sie ansteckende Dreiecke mit zeichnen möchten drawElements() Methode, fügen Sie einfach die anderen Scheitelpunkte hinzu und erwähnen Sie die Indizes für die verbleibenden Scheitelpunkte.
var vertices = [
-0.5,-0.5,0.0,
-0.25,0.5,0.0,
0.0,-0.5,0.0,
0.25,0.5,0.0,
0.5,-0.5,0.0
];
var indices = [0,1,2,2,3,4];
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Es wird die folgende Ausgabe erzeugt -
Erforderliche Operationen
Bevor Sie ein Grundelement zeichnen, müssen Sie einige Operationen ausführen, die im Folgenden erläutert werden.
Löschen Sie die Leinwand
Zunächst sollten Sie die Leinwand mit löschen clearColor()Methode. Sie können die RGBA-Werte einer gewünschten Farbe als Parameter an diese Methode übergeben. Dann löscht WebGL die Leinwand und füllt sie mit der angegebenen Farbe. Daher können Sie diese Methode zum Einstellen der Hintergrundfarbe verwenden.
Schauen Sie sich das folgende Beispiel an. Hier übergeben wir den RGBA-Wert der grauen Farbe.
gl.clearColor(0.5, 0.5, .5, 1);
Tiefentest aktivieren
Aktivieren Sie den Tiefentest mit enable() Methode, wie unten gezeigt.
gl.enable(gl.DEPTH_TEST);
Löschen Sie das Farbpufferbit
Löschen Sie die Farbe sowie den Tiefenpuffer mit dem clear() Methode, wie unten gezeigt.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
Stellen Sie den Ansichtsport ein
Das Ansichtsfenster stellt einen rechteckigen sichtbaren Bereich dar, der die Renderergebnisse des Zeichenpuffers enthält. Sie können die Abmessungen des Ansichtsfensters mithilfe von festlegenviewport()Methode. Im folgenden Code werden die Abmessungen des Ansichtsfensters auf die Canvas-Abmessungen festgelegt.
gl.viewport(0,0,canvas.width,canvas.height);
Wir haben zuvor (in Kapitel 5) besprochen, wie man Schritt für Schritt einem Primitiv folgt. Wir haben den Prozess in fünf Schritten erklärt. Sie müssen diese Schritte jedes Mal wiederholen, wenn Sie eine neue Form zeichnen. In diesem Kapitel wird erläutert, wie Sie in WebGL Punkte mit 3D-Koordinaten zeichnen. Bevor wir fortfahren, werfen wir einen Blick auf die fünf Schritte.
Erforderliche Schritte
Die folgenden Schritte sind erforderlich, um eine WebGL-Anwendung zum Zeichnen von Punkten zu erstellen.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
In diesem Schritt erhalten wir das WebGL-Rendering-Kontextobjekt mithilfe der Methode getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Da wir drei Punkte zeichnen, definieren wir drei Eckpunkte mit 3D-Koordinaten und speichern sie in Puffern.
var vertices = [
-0.5,0.5,0.0,
0.0,0.5,0.0,
-0.25,0.25,0.0,
];
Step 3 − Create and Compile the Shader Programs
In diesem Schritt müssen Sie Vertex-Shader- und Fragment-Shader-Programme schreiben, kompilieren und ein kombiniertes Programm erstellen, indem Sie diese beiden Programme verknüpfen.
Vertex Shader - Im Vertex-Shader des angegebenen Beispiels definieren wir ein Vektorattribut zum Speichern von 3D-Koordinaten und weisen es dem zu gl_position Variable.
gl_pointsizeist die Variable, mit der dem Punkt eine Größe zugewiesen wird. Wir weisen die Punktgröße als 10 zu.
var vertCode = 'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
Fragment Shader - Im Fragment-Shader weisen wir dem einfach die Fragmentfarbe zu gl_FragColor Variable
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
In diesem Schritt ordnen wir die Pufferobjekte dem Shader-Programm zu.
Step 5 − Drawing the Required Object
Wir verwenden die Methode drawArrays()Punkte ziehen. Da wir drei Punkte zeichnen möchten, beträgt der Zählwert 3.
gl.drawArrays(gl.POINTS, 0, 3)
Beispiel - Zeichnen Sie mit WebGL drei Punkte
Hier ist das komplette WebGL-Programm, um drei Punkte zu ziehen -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*================Creating a canvas=================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*==========Defining and storing the geometry=======*/
var vertices = [
-0.5,0.5,0.0,
0.0,0.5,0.0,
-0.25,0.25,0.0,
];
// Create an empty buffer object to store the vertex buffer
var vertex_buffer = gl.createBuffer();
//Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*=========================Shaders========================*/
// vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'gl_PointSize = 10.0;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======== Associating shaders to buffer objects ========*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============= Drawing the primitive ===============*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.POINTS, 0, 3);
</script>
</body>
</html>
Es wird das folgende Ergebnis erzeugt -
Im vorherigen Kapitel (Kapitel 11) haben wir erläutert, wie Sie mit WebGL drei Punkte zeichnen. In Kapitel 5 haben wir anhand einer Beispielanwendung demonstriert, wie ein Dreieck gezeichnet wird. In beiden Beispielen haben wir die Grundelemente nur mit Eckpunkten gezeichnet.
Um komplexere Formen / Netze zu zeichnen, übergeben wir die Indizes einer Geometrie zusammen mit den Scheitelpunkten auch an die Shader. In diesem Kapitel erfahren Sie, wie Sie mithilfe von Indizes ein Dreieck zeichnen.
Erforderliche Schritte zum Zeichnen eines Dreiecks
Die folgenden Schritte sind erforderlich, um eine WebGL-Anwendung zum Zeichnen eines Dreiecks zu erstellen.
Step 1 − Prepare the Canvas and Get WebGL Rendering Context
In diesem Schritt erhalten wir das WebGL-Rendering-Kontextobjekt mit getContext().
Step 2 − Define the Geometry and Store it in Buffer Objects
Da wir ein Dreieck mit Indizes zeichnen, müssen wir die drei Eckpunkte des Dreiecks einschließlich der Indizes übergeben und in den Puffern speichern.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
indices = [0,1,2];
Step 3 − Create and Compile the Shader Programs
In diesem Schritt müssen Sie Vertex-Shader- und Fragment-Shader-Programme schreiben, kompilieren und ein kombiniertes Programm erstellen, indem Sie diese beiden Programme verknüpfen.
Vertex Shader - Im Vertex-Shader des Programms definieren wir das Vektorattribut, um 3D-Koordinaten zu speichern und zuzuweisen gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - Im Fragment-Shader weisen wir dem einfach die Fragmentfarbe zu gl_FragColor Variable.
var fragCode = 'void main(void) {' +
' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +
'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
In diesem Schritt ordnen wir die Pufferobjekte und das Shader-Programm zu.
Step 5 − Drawing the Required Object
Da wir ein Dreieck mit Indizes zeichnen, werden wir verwenden drawElements()
. An diese Methode müssen wir die Anzahl der Indizes übergeben. Der Wert desindices.length bezeichnet die Anzahl der Indizes.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Beispiel - Zeichnen eines Dreiecks
Der folgende Programmcode zeigt, wie ein Dreieck in WebGL mithilfe von Indizes gezeichnet wird:
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============== Creating a canvas ====================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*======== Defining and storing the geometry ===========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
indices = [0,1,2];
// Create an empty buffer object to store vertex buffer
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object to store Index buffer
var Index_Buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
/*================ Shaders ====================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======= Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*=========Drawing the triangle===========*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
Im vorherigen Kapitel (Kapitel 12) haben wir erläutert, wie Sie mit WebGL ein Dreieck zeichnen. Neben Dreiecken unterstützt WebGL verschiedene andere Zeichenmodi. In diesem Kapitel werden die von WebGL unterstützten Zeichenmodi erläutert.
Der Modus Parameter
Werfen wir einen Blick auf die Syntax der Methoden - drawElements() und zeichnen Arrays().
void drawElements(enum mode, long count, enum type, long offset);
void drawArrays(enum mode, int first, long count);
Wenn Sie dies klar beobachten, akzeptieren beide Methoden einen Parameter mode. Mit diesem Parameter können die Programmierer den Zeichenmodus in WebGL auswählen.
Die von WebGL bereitgestellten Zeichenmodi sind in der folgenden Tabelle aufgeführt.
Sr.Nr. | Modus & Beschreibung |
---|---|
1 | gl.POINTS Eine Reihe von Punkten zeichnen. |
2 | gl.LINES Zeichnen einer Reihe nicht verbundener Liniensegmente (einzelne Linien). |
3 | gl.LINE_STRIP Zeichnen einer Reihe verbundener Liniensegmente. |
4 | gl.LINE_LOOP Zeichnen einer Reihe verbundener Liniensegmente. Es verbindet auch den ersten und den letzten Scheitelpunkt, um eine Schleife zu bilden. |
5 | gl.TRIANGLES Eine Reihe separater Dreiecke zeichnen. |
6 | gl.TRIANGLE_STRIP Zeichnen einer Reihe verbundener Dreiecke in Streifenform. |
7 | gl.TRIANGLE_FAN Zeichnen einer Reihe verbundener Dreiecke, die den ersten Scheitelpunkt fächerartig teilen. |
Beispiel - Zeichnen Sie drei parallele Linien
Das folgende Beispiel zeigt, wie Sie mit drei drei parallele Linien zeichnen gl.LINES.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*======= Creating a canvas =========*/
var canvas = document.getElementById('my_Canvas');
var gl = canvas.getContext('experimental-webgl');
/*======= Defining and storing the geometry ======*/
var vertices = [
-0.7,-0.1,0,
-0.3,0.6,0,
-0.3,-0.3,0,
0.2,0.6,0,
0.3,-0.3,0,
0.7,0.6,0
]
// Create an empty buffer object
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*=================== Shaders ====================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// Fragment shader source code
var fragCode =
'void main(void) {' +
'gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to store
// the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/*======= Associating shaders to buffer objects ======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============ Drawing the triangle =============*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawArrays(gl.LINES, 0, 6);
// POINTS, LINE_STRIP, LINE_LOOP, LINES,
// TRIANGLE_STRIP,TRIANGLE_FAN, TRIANGLES
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
Zeichenmodi
Im obigen Programm, wenn Sie den Modus von ersetzen drawArrays() Mit einem der folgenden Zeichenmodi werden jedes Mal unterschiedliche Ausgaben erzeugt.
Zeichenmodi | Ausgänge |
---|---|
LINE_STRIP |
|
LINE_LOOP |
|
TRIANGLE_STRIP |
|
TRIANGLE_FAN |
|
DREIECKE |
|
Im vorherigen Kapitel haben wir die verschiedenen Zeichenmodi von WebGL erläutert. Wir können auch Indizes verwenden, um Primitive mit einem dieser Modi zu zeichnen. Um Modelle in WebGL zu zeichnen, müssen wir eines dieser Grundelemente auswählen und das erforderliche Netz zeichnen (dh ein Modell, das mit einem oder mehreren Grundelementen erstellt wurde).
In diesem Kapitel zeigen wir anhand eines Beispiels, wie mit WebGL ein Viereck gezeichnet wird.
Schritte zum Zeichnen eines Vierecks
Die folgenden Schritte sind erforderlich, um eine WebGL-Anwendung zum Zeichnen eines Vierecks zu erstellen.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
In diesem Schritt erhalten wir das WebGL-Rendering-Kontextobjekt mit getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Ein Quadrat kann mit zwei Dreiecken gezeichnet werden. In diesem Beispiel stellen wir die Eckpunkte für zwei Dreiecke (mit einer gemeinsamen Kante) und Indizes bereit.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
indices = [3,2,1,3,1,0];
Step 3 − Create and Compile the Shader Programs
In diesem Schritt müssen Sie die Programme Vertex Shader und Fragment Shader schreiben, kompilieren und ein kombiniertes Programm erstellen, indem Sie diese beiden Programme verknüpfen.
Vertex Shader - Im Vertex-Shader des Programms definieren wir das Vektorattribut, um 3D-Koordinaten zu speichern und zuzuweisen gl_position.
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
Fragment Shader - Im Fragment-Shader weisen wir dem einfach die Fragmentfarbe zu gl_FragColor Variable.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(0.5, 0.3, 0.0, 7.5);' +'}';
Step 4 − Associate the Shader Programs to Buffer Objects
In diesem Schritt ordnen wir die Pufferobjekte dem Shader-Programm zu.
Step 5 − Drawing the Required Object
Da wir zwei Dreiecke zeichnen, um mithilfe von Indizes ein Quad zu bilden, verwenden wir die Methode drawElements(). An diese Methode müssen wir die Anzahl der Indizes übergeben. Der Wert vonindices.length gibt die Anzahl der Indizes an.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Beispiel - Zeichnen Sie ein Viereck
Das folgende Programm zeigt, wie Sie eine WebGL-Anwendung zum Zeichnen eines Vierecks erstellen.
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============ Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry =========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
indices = [3,2,1,3,1,0];
// Create an empty buffer object to store vertex buffer
var vertex_buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object to store Index buffer
var Index_Buffer = gl.createBuffer();
// Bind appropriate array buffer to it
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Pass the vertex data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
// Unbind the buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
/*====================== Shaders =======================*/
// Vertex shader source code
var vertCode =
'attribute vec3 coordinates;' +
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// Fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* ======= Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// Point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
/*============= Drawing the Quad ================*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
// Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
In all unseren vorherigen Beispielen haben wir dem Objekt Farbe zugewiesen, indem wir dem Objekt einen gewünschten Farbwert zugewiesen haben gl_FragColorVariable. Darüber hinaus können wir Farben für jeden Scheitelpunkt definieren - genau wie Scheitelpunktkoordinaten und -indizes. In diesem Kapitel wird anhand eines Beispiels gezeigt, wie Farben mit WebGL auf ein Viereck angewendet werden.
Farben anwenden
Um Farben anzuwenden, müssen Sie die Farben für jeden Scheitelpunkt mithilfe der RGB-Werte im JavaScript-Array definieren. Sie können allen Scheitelpunkten dieselben Werte zuweisen, um dem Objekt eine eindeutige Farbe zu verleihen. Nachdem Sie die Farben definiert haben, müssen Sie einen Farbpuffer erstellen, diese Werte darin speichern und ihn den Vertex-Shader-Attributen zuordnen.
Im Vertex-Shader definieren wir zusammen mit dem Koordinatenattribut (das die Position der Vertices enthält) eine attribute und ein varying mit Farben umgehen.
Das color Attribut enthält den Farbwert pro Scheitelpunkt und varyingist die Variable, die als Eingabe an den Fragment-Shader übergeben wird. Deshalb müssen wir die zuweisencolor Wert zu varying.
Im Fragment-Shader wird der varying das hält den Farbwert zugeordnet ist gl_FragColor, die die endgültige Farbe des Objekts enthält.
Schritte zum Anwenden von Farben
Die folgenden Schritte sind erforderlich, um eine WebGL-Anwendung zum Zeichnen eines Quad zu erstellen und Farben darauf anzuwenden.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
In diesem Schritt erhalten wir das WebGL-Rendering-Kontextobjekt mit getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Ein Quadrat kann mit zwei Dreiecken gezeichnet werden. Daher stellen wir in diesem Beispiel die Eckpunkte für zwei Dreiecke (mit einer gemeinsamen Kante) und Indizes bereit. Da wir Farben darauf anwenden möchten, wird auch eine Variable definiert, die die Farbwerte enthält, und die Farbwerte für jede (Rot, Blau, Grün und Rosa) werden ihr zugewiesen.
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [ 0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
Step 3 − Create and Compile the Shader Programs
In diesem Schritt müssen Sie die Programme Vertex Shader und Fragment Shader schreiben, kompilieren und ein kombiniertes Programm erstellen, indem Sie diese beiden Programme verknüpfen.
Vertex Shader- Im Vertex-Shader des Programms definieren wir Vektorattribute zum Speichern von 3D-Koordinaten (Position) und der Farbe jedes Vertex. EINvaringDie Variable wird deklariert, um die Farbwerte vom Vertex-Shader an den Fragment-Shader zu übergeben. Und schließlich wird der im Farbattribut gespeicherte Wert zugewiesenvarying.
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
Fragment Shader - Im Fragment-Shader weisen wir die zu varying zum gl_FragColor Variable.
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
In diesem Schritt ordnen wir die Pufferobjekte und das Shader-Programm zu.
Step 5 − Drawing the Required Object
Da wir mit Hilfe von Indizes zwei Dreiecke zeichnen, die ein Quad bilden, verwenden wir die Methode drawElements(). An diese Methode müssen wir die Anzahl der Indizes übergeben. Der Wert vonindices.length gibt die Anzahl der Indizes an.
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
Beispiel - Anwenden von Farbe
Das folgende Programm zeigt, wie Sie mit der WebGL-Anwendung ein Quad zeichnen und Farben darauf anwenden.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas ==================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry ==========*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
0.5,0.5,0.0
];
var colors = [0,0,1, 1,0,0, 0,1,0, 1,0,1,];
indices = [3,2,1,3,1,0];
// Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// Create an empty buffer object and store Index data
var Index_Buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// Create an empty buffer object and store color data
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
/*======================= Shaders =======================*/
// vertex shader source code
var vertCode = 'attribute vec3 coordinates;'+
'attribute vec3 color;'+
'varying vec3 vColor;'+
'void main(void) {' +
' gl_Position = vec4(coordinates, 1.0);' +
'vColor = color;'+
'}';
// Create a vertex shader object
var vertShader = gl.createShader(gl.VERTEX_SHADER);
// Attach vertex shader source code
gl.shaderSource(vertShader, vertCode);
// Compile the vertex shader
gl.compileShader(vertShader);
// fragment shader source code
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
// Create fragment shader object
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
// Attach fragment shader source code
gl.shaderSource(fragShader, fragCode);
// Compile the fragmentt shader
gl.compileShader(fragShader);
// Create a shader program object to
// store the combined shader program
var shaderProgram = gl.createProgram();
// Attach a vertex shader
gl.attachShader(shaderProgram, vertShader);
// Attach a fragment shader
gl.attachShader(shaderProgram, fragShader);
// Link both the programs
gl.linkProgram(shaderProgram);
// Use the combined shader program object
gl.useProgram(shaderProgram);
/* ======== Associating shaders to buffer objects =======*/
// Bind vertex buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
// Bind index buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Index_Buffer);
// Get the attribute location
var coord = gl.getAttribLocation(shaderProgram, "coordinates");
// point an attribute to the currently bound VBO
gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// Enable the attribute
gl.enableVertexAttribArray(coord);
// bind the color buffer
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
// get the attribute location
var color = gl.getAttribLocation(shaderProgram, "color");
// point attribute to the volor buffer object
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// enable the color attribute
gl.enableVertexAttribArray(color);
/*============Drawing the Quad====================*/
// Clear the canvas
gl.clearColor(0.5, 0.5, 0.5, 0.9);
// Enable the depth test
gl.enable(gl.DEPTH_TEST);
// Clear the color buffer bit
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the view port
gl.viewport(0,0,canvas.width,canvas.height);
//Draw the triangle
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT,0);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
Bisher haben wir besprochen, wie Sie mit WebGL verschiedene Formen zeichnen und Farben darauf anwenden können. In diesem Kapitel zeigen wir anhand eines Beispiels, wie ein Dreieck übersetzt wird.
Übersetzung
Übersetzung ist eine der affine transformationsbereitgestellt von WebGL. Mithilfe der Übersetzung können wir ein Dreieck (ein beliebiges Objekt) auf der xyz-Ebene verschieben. Angenommen, wir haben ein Dreieck [a, b, c] und möchten das Dreieck an eine Position verschieben, die 5 Einheiten in Richtung der positiven X-Achse und 3 Einheiten in Richtung der positiven Y-Achse beträgt. Dann wären die neuen Eckpunkte [a + 5, b + 3, c + 0]. Das heißt, um das Dreieck zu übersetzen, müssen wir jedem Scheitelpunkt die Übersetzungsabstände hinzufügen, z. B. tx, ty, tz.
Da ist es ein per-vertex operation, Wir können es im Vertex-Shader-Programm tragen.
Im Vertex-Shader zusammen mit dem Attribut coordinates(die die Scheitelpunktpositionen enthalten) definieren wir eine einheitliche Variable, die die Translationsabstände (x, y, z) enthält. Später fügen wir diese einheitliche Variable der Koordinatenvariablen hinzu und weisen das Ergebnis der zugl_Position Variable.
Note - Da der Scheitelpunkt-Shader für jeden Scheitelpunkt ausgeführt wird, werden alle Scheitelpunkte des Dreiecks übersetzt.
Schritte zum Übersetzen eines Dreiecks
Die folgenden Schritte sind erforderlich, um eine WebGL-Anwendung zum Zeichnen eines Dreiecks zu erstellen und es dann an eine neue Position zu übersetzen.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
In diesem Schritt erhalten wir das WebGL-Rendering-Kontextobjekt mit getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Da wir ein Dreieck zeichnen, müssen wir drei Eckpunkte des Dreiecks passieren und sie in Puffern speichern.
var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];
Step 3 − Create and Compile the Shader Programs
In diesem Schritt müssen Sie die Programme Vertex Shader und Fragment Shader schreiben, kompilieren und ein kombiniertes Programm erstellen, indem Sie diese beiden Programme verknüpfen.
Vertex Shader- Im Vertex-Shader des Programms definieren wir ein Vektorattribut zum Speichern von 3D-Koordinaten. Gleichzeitig definieren wir eine einheitliche Variable zum Speichern der Übersetzungsabstände. Schließlich addieren wir diese beiden Werte und weisen sie zugl_position welches die Endposition der Eckpunkte hält.
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
Fragment Shader - Im Fragment-Shader weisen wir der Variablen gl_FragColor einfach die Fragmentfarbe zu.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs to the Buffer Objects
In diesem Schritt ordnen wir die Pufferobjekte dem Shader-Programm zu.
Step 5 − Drawing the Required Object
Da wir das Dreieck mit Indizes zeichnen, verwenden wir die Methode drawArrays(). Bei dieser Methode müssen wir die Anzahl der zu berücksichtigenden Eckpunkte / Elemente übergeben. Da wir ein Dreieck zeichnen, übergeben wir 3 als Parameter.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Beispiel - Ein Dreieck übersetzen
Das folgende Beispiel zeigt, wie ein Dreieck in der xyz-Ebene verschoben wird.
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
//Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
//Create a new buffer
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
//bind it to the current buffer
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Pass the buffer data
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*========================Shaders============================*/
//vertex shader source code
var vertCode =
'attribute vec4 coordinates;' +
'uniform vec4 translation;'+
'void main(void) {' +
' gl_Position = coordinates + translation;' +
'}';
//Create a vertex shader program object and compile it
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
//Create a fragment shader program object and compile it
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//Create and use combiened shader program
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
/* ===========Associating shaders to buffer objects============*/
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coordinatesVar);
/* ==========translation======================================*/
var Tx = 0.5, Ty = 0.5, Tz = 0.0;
var translation = gl.getUniformLocation(shaderProgram, 'translation');
gl.uniform4f(translation, Tx, Ty, Tz, 0.0);
/*=================Drawing the riangle and transforming it========================*/
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
In diesem Kapitel zeigen wir anhand eines Beispiels, wie Sie die Skalierung eines Dreiecks mithilfe von WebGL ändern können.
Skalierung
Skalieren ist nichts anderes als das Erhöhen oder Verringern der Größe eines Objekts. Wenn ein Dreieck beispielsweise Scheitelpunkte der Größe [a, b, c] hat, ist das Dreieck mit den Scheitelpunkten [2a, 2b, 2c] doppelt so groß. Um ein Dreieck zu skalieren, müssen Sie daher jeden Scheitelpunkt mit dem Skalierungsfaktor multiplizieren. Sie können auch einen bestimmten Scheitelpunkt skalieren.
Um ein Dreieck zu skalieren, erstellen wir im Vertex-Shader des Programms eine einheitliche Matrix und multiplizieren die Koordinatenwerte mit dieser Matrix. Später passieren wir eine 4 × 4-Diagonalmatrix mit den Skalierungsfaktoren der x-, y- und z-Koordinaten in den diagonalen Positionen (letzte diagonale Position 1).
Erforderliche Schritte
Die folgenden Schritte sind erforderlich, um eine WebGL-Anwendung zum Skalieren eines Dreiecks zu erstellen.
Step 1 − Prepare the Canvas and Get the WebGL Rendering Context
In diesem Schritt erhalten wir das WebGL-Rendering-Kontextobjekt mit getContext().
Step 2 − Define the Geometry and Store it in the Buffer Objects
Da wir ein Dreieck zeichnen, müssen wir drei Eckpunkte des Dreiecks passieren und sie in Puffern speichern.
var vertices = [ -0.5,0.5,0.0, -0.5,-0.5,0.0, 0.5,-0.5,0.0, ];
Step 3 − Create and Compile the Shader Programs
In diesem Schritt müssen Sie die Programme Vertex Shader und Fragment Shader schreiben, kompilieren und ein kombiniertes Programm erstellen, indem Sie diese beiden Programme verknüpfen.
Vertex Shader- Im Vertex-Shader des Programms definieren wir ein Vektorattribut zum Speichern von 3D-Koordinaten. Gleichzeitig definieren wir eine einheitliche Matrix zum Speichern der Skalierungsfaktoren. Schließlich multiplizieren wir diese beiden Werte und weisen sie zugl_position welches die Endposition der Eckpunkte hält.
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
Fragment Shader - Im Fragment-Shader weisen wir dem einfach die Fragmentfarbe zu gl_FragColor Variable.
var fragCode = 'void main(void) {' +' gl_FragColor = vec4(1, 0.5, 0.0, 1);' +'}';
Step 4 − Associate the Shader Programs with the Buffer Objects
In diesem Schritt ordnen wir die Pufferobjekte dem Shader-Programm zu.
Step 5 − Drawing the Required Object
Da wir das Dreieck mit Indizes zeichnen, verwenden wir die drawArrays()Methode. Bei dieser Methode müssen wir die Anzahl der zu berücksichtigenden Eckpunkte / Elemente übergeben. Da wir ein Dreieck zeichnen, übergeben wir 3 als Parameter.
gl.drawArrays(gl.TRIANGLES, 0, 3);
Beispiel - Skalieren Sie ein Dreieck
Das folgende Beispiel zeigt, wie ein Dreieck skaliert wird -
<!doctype html>
<html>
<body>
<canvas width = "300" height = "300" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [
-0.5,0.5,0.0,
-0.5,-0.5,0.0,
0.5,-0.5,0.0,
];
//Create an empty buffer object and store vertex data
var vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
/*========================Shaders============================*/
//Vertex shader source code
var vertCode =
'attribute vec4 coordinates;' +
'uniform mat4 u_xformMatrix;' +
'void main(void) {' +
' gl_Position = u_xformMatrix * coordinates;' +
'}';
//Create a vertex shader program object and compile it
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'void main(void) {' +
' gl_FragColor = vec4(0.0, 0.0, 0.0, 0.1);' +
'}';
//Create a fragment shader program object and compile it
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
//Create and use combiened shader program
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
/*===================scaling==========================*/
var Sx = 1.0, Sy = 1.5, Sz = 1.0;
var xformMatrix = new Float32Array([
Sx, 0.0, 0.0, 0.0,
0.0, Sy, 0.0, 0.0,
0.0, 0.0, Sz, 0.0,
0.0, 0.0, 0.0, 1.0
]);
var u_xformMatrix = gl.getUniformLocation(shaderProgram, 'u_xformMatrix');
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix);
/* ===========Associating shaders to buffer objects============*/
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var coordinatesVar = gl.getAttribLocation(shaderProgram, "coordinates");
gl.vertexAttribPointer(coordinatesVar, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coordinatesVar);
/*=================Drawing the Quad========================*/
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.enable(gl.DEPTH_TEST);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport(0,0,canvas.width,canvas.height);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
In diesem Kapitel zeigen wir anhand eines Beispiels, wie ein Dreieck mit WebGL gedreht wird.
Beispiel - Drehen Sie ein Dreieck
Das folgende Programm zeigt, wie Sie mit WebGL ein Dreieck drehen.
<!doctype html>
<html>
<body>
<canvas width = "400" height = "400" id = "my_Canvas"></canvas>
<script>
/*=================Creating a canvas=========================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*===========Defining and storing the geometry==============*/
var vertices = [ -1,-1,-1, 1,-1,-1, 1, 1,-1 ];
var colors = [ 1,1,1, 1,1,1, 1,1,1 ];
var indices = [ 0,1,2 ];
//Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
//Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
//Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*==========================Shaders=========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/*===========associating attributes to vertex shader ============*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ; //position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ; //color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*========================= MATRIX ========================= */
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
//translating z
view_matrix[14] = view_matrix[14]-6; //zoom
/*=======================rotation========================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1] = c*m[1]+s*mv0;
m[5] = c*m[5]+s*mv4;
m[9] = c*m[9]+s*mv8;
}
/*=================Drawing===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.002);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
In diesem Kapitel zeigen wir anhand eines Beispiels, wie ein rotierender 3D-Würfel mit WebGL gezeichnet wird.
Beispiel - Zeichnen Sie einen rotierenden 3D-Würfel
Das folgende Programm zeigt, wie ein rotierender 3D-Würfel gezeichnet wird -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas =================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*============ Defining and storing the geometry =========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== Shaders =========================*/
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
/* ====== Associating attributes to vertex shader =====*/
var Pmatrix = gl.getUniformLocation(shaderProgram, "Pmatrix");
var Vmatrix = gl.getUniformLocation(shaderProgram, "Vmatrix");
var Mmatrix = gl.getUniformLocation(shaderProgram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var position = gl.getAttribLocation(shaderProgram, "position");
gl.vertexAttribPointer(position, 3, gl.FLOAT, false,0,0) ;
// Position
gl.enableVertexAttribArray(position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var color = gl.getAttribLocation(shaderProgram, "color");
gl.vertexAttribPointer(color, 3, gl.FLOAT, false,0,0) ;
// Color
gl.enableVertexAttribArray(color);
gl.useProgram(shaderProgram);
/*==================== MATRIX =====================*/
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mov_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
var view_matrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1];
// translating z
view_matrix[14] = view_matrix[14]-6;//zoom
/*==================== Rotation ====================*/
function rotateZ(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]-s*m[1];
m[4] = c*m[4]-s*m[5];
m[8] = c*m[8]-s*m[9];
m[1]=c*m[1]+s*mv0;
m[5]=c*m[5]+s*mv4;
m[9]=c*m[9]+s*mv8;
}
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*================= Drawing ===========================*/
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
rotateZ(mov_matrix, dt*0.005);//time
rotateY(mov_matrix, dt*0.002);
rotateX(mov_matrix, dt*0.003);
time_old = time;
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(Mmatrix, false, mov_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt:
In diesem Kapitel zeigen wir anhand eines Beispiels, wie ein 3D-Würfel gezeichnet wird, der mit Maussteuerelementen gedreht werden kann.
Beispiel - Zeichnen Sie einen interaktiven Würfel
Das folgende Programm zeigt, wie ein Würfel mit der Maus gedreht wird -
<!doctype html>
<html>
<body>
<canvas width = "570" height = "570" id = "my_Canvas"></canvas>
<script>
/*============= Creating a canvas ======================*/
var canvas = document.getElementById('my_Canvas');
gl = canvas.getContext('experimental-webgl');
/*========== Defining and storing the geometry ==========*/
var vertices = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
-1,-1,-1, -1, 1,-1, -1, 1, 1, -1,-1, 1,
1,-1,-1, 1, 1,-1, 1, 1, 1, 1,-1, 1,
-1,-1,-1, -1,-1, 1, 1,-1, 1, 1,-1,-1,
-1, 1,-1, -1, 1, 1, 1, 1, 1, 1, 1,-1,
];
var colors = [
5,3,7, 5,3,7, 5,3,7, 5,3,7,
1,1,3, 1,1,3, 1,1,3, 1,1,3,
0,0,1, 0,0,1, 0,0,1, 0,0,1,
1,0,0, 1,0,0, 1,0,0, 1,0,0,
1,1,0, 1,1,0, 1,1,0, 1,1,0,
0,1,0, 0,1,0, 0,1,0, 0,1,0
];
var indices = [
0,1,2, 0,2,3, 4,5,6, 4,6,7,
8,9,10, 8,10,11, 12,13,14, 12,14,15,
16,17,18, 16,18,19, 20,21,22, 20,22,23
];
// Create and store data into vertex buffer
var vertex_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Create and store data into color buffer
var color_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
// Create and store data into index buffer
var index_buffer = gl.createBuffer ();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
/*=================== SHADERS =================== */
var vertCode = 'attribute vec3 position;'+
'uniform mat4 Pmatrix;'+
'uniform mat4 Vmatrix;'+
'uniform mat4 Mmatrix;'+
'attribute vec3 color;'+//the color of the point
'varying vec3 vColor;'+
'void main(void) { '+//pre-built function
'gl_Position = Pmatrix*Vmatrix*Mmatrix*vec4(position, 1.);'+
'vColor = color;'+
'}';
var fragCode = 'precision mediump float;'+
'varying vec3 vColor;'+
'void main(void) {'+
'gl_FragColor = vec4(vColor, 1.);'+
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
var shaderprogram = gl.createProgram();
gl.attachShader(shaderprogram, vertShader);
gl.attachShader(shaderprogram, fragShader);
gl.linkProgram(shaderprogram);
/*======== Associating attributes to vertex shader =====*/
var _Pmatrix = gl.getUniformLocation(shaderprogram, "Pmatrix");
var _Vmatrix = gl.getUniformLocation(shaderprogram, "Vmatrix");
var _Mmatrix = gl.getUniformLocation(shaderprogram, "Mmatrix");
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
var _position = gl.getAttribLocation(shaderprogram, "position");
gl.vertexAttribPointer(_position, 3, gl.FLOAT, false,0,0);
gl.enableVertexAttribArray(_position);
gl.bindBuffer(gl.ARRAY_BUFFER, color_buffer);
var _color = gl.getAttribLocation(shaderprogram, "color");
gl.vertexAttribPointer(_color, 3, gl.FLOAT, false,0,0) ;
gl.enableVertexAttribArray(_color);
gl.useProgram(shaderprogram);
/*==================== MATRIX ====================== */
function get_projection(angle, a, zMin, zMax) {
var ang = Math.tan((angle*.5)*Math.PI/180);//angle*.5
return [
0.5/ang, 0 , 0, 0,
0, 0.5*a/ang, 0, 0,
0, 0, -(zMax+zMin)/(zMax-zMin), -1,
0, 0, (-2*zMax*zMin)/(zMax-zMin), 0
];
}
var proj_matrix = get_projection(40, canvas.width/canvas.height, 1, 100);
var mo_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
var view_matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 ];
view_matrix[14] = view_matrix[14]-6;
/*================= Mouse events ======================*/
var AMORTIZATION = 0.95;
var drag = false;
var old_x, old_y;
var dX = 0, dY = 0;
var mouseDown = function(e) {
drag = true;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
return false;
};
var mouseUp = function(e){
drag = false;
};
var mouseMove = function(e) {
if (!drag) return false;
dX = (e.pageX-old_x)*2*Math.PI/canvas.width,
dY = (e.pageY-old_y)*2*Math.PI/canvas.height;
THETA+= dX;
PHI+=dY;
old_x = e.pageX, old_y = e.pageY;
e.preventDefault();
};
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mouseup", mouseUp, false);
canvas.addEventListener("mouseout", mouseUp, false);
canvas.addEventListener("mousemove", mouseMove, false);
/*=========================rotation================*/
function rotateX(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv1 = m[1], mv5 = m[5], mv9 = m[9];
m[1] = m[1]*c-m[2]*s;
m[5] = m[5]*c-m[6]*s;
m[9] = m[9]*c-m[10]*s;
m[2] = m[2]*c+mv1*s;
m[6] = m[6]*c+mv5*s;
m[10] = m[10]*c+mv9*s;
}
function rotateY(m, angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
var mv0 = m[0], mv4 = m[4], mv8 = m[8];
m[0] = c*m[0]+s*m[2];
m[4] = c*m[4]+s*m[6];
m[8] = c*m[8]+s*m[10];
m[2] = c*m[2]-s*mv0;
m[6] = c*m[6]-s*mv4;
m[10] = c*m[10]-s*mv8;
}
/*=================== Drawing =================== */
var THETA = 0,
PHI = 0;
var time_old = 0;
var animate = function(time) {
var dt = time-time_old;
if (!drag) {
dX *= AMORTIZATION, dY*=AMORTIZATION;
THETA+=dX, PHI+=dY;
}
//set model matrix to I4
mo_matrix[0] = 1, mo_matrix[1] = 0, mo_matrix[2] = 0,
mo_matrix[3] = 0,
mo_matrix[4] = 0, mo_matrix[5] = 1, mo_matrix[6] = 0,
mo_matrix[7] = 0,
mo_matrix[8] = 0, mo_matrix[9] = 0, mo_matrix[10] = 1,
mo_matrix[11] = 0,
mo_matrix[12] = 0, mo_matrix[13] = 0, mo_matrix[14] = 0,
mo_matrix[15] = 1;
rotateY(mo_matrix, THETA);
rotateX(mo_matrix, PHI);
time_old = time;
gl.enable(gl.DEPTH_TEST);
// gl.depthFunc(gl.LEQUAL);
gl.clearColor(0.5, 0.5, 0.5, 0.9);
gl.clearDepth(1.0);
gl.viewport(0.0, 0.0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniformMatrix4fv(_Pmatrix, false, proj_matrix);
gl.uniformMatrix4fv(_Vmatrix, false, view_matrix);
gl.uniformMatrix4fv(_Mmatrix, false, mo_matrix);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
window.requestAnimationFrame(animate);
}
animate(0);
</script>
</body>
</html>
Wenn Sie dieses Beispiel ausführen, wird die folgende Ausgabe erzeugt: