WebGL - Shader

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 das Shader-Objekt und gibt es 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 an das Programm ü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);