Signatur
Beschreibung
WebGLShader ist ein Teil der WebGL-API und steht für ein einzelnes Shader-Objekt auf der GPU. Das kann entweder ein Vertex-Shader (gl.VERTEX_SHADER) sein, der die Position jedes Eckpunkts berechnet, oder ein Fragment-Shader (gl.FRAGMENT_SHADER), der die Farbe jedes Pixels festlegt. Das Objekt selbst hat weder eigene Eigenschaften noch eigene Methoden. Es ist nur ein undurchsichtiges Handle, das du an Methoden von WebGLRenderingContext bzw. WebGL2RenderingContext übergibst.
Einen Konstruktor gibt es nicht. Instanzen erzeugst du mit gl.createShader(type). Danach übergibst du mit gl.shaderSource() den GLSL-Quelltext und übersetzt ihn mit gl.compileShader(). Ob das Kompilieren geklappt hat, prüfst du mit gl.getShaderParameter(shader, gl.COMPILE_STATUS). Fehlermeldungen bekommst du über gl.getShaderInfoLog().
Zum Zeichnen brauchst du immer genau einen Vertex- und einen Fragment-Shader. Beide hängst du mit gl.attachShader() an ein WebGLProgram an und verknüpfst sie mit gl.linkProgram(). Nach dem erfolgreichen Linken kannst du die Shader-Objekte mit gl.detachShader() und gl.deleteShader() freigeben. Das Programm behält den übersetzten Code.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | GLenum | Parameter von gl.createShader(type), mit dem ein WebGLShader erzeugt wird: gl.VERTEX_SHADER oder gl.FRAGMENT_SHADER. |
Rückgabewert
gl.createShader() liefert ein neues WebGLShader-Objekt. Bei einem ungültigen Typ oder einem verlorenen Kontext kommt null zurück.Beispiele
Shader erzeugen und kompilieren (mit Fehlerprüfung)
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const compileShader = (gl, type, source) => {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
const log = gl.getShaderInfoLog(shader);
gl.deleteShader(shader);
throw new Error(`Shader-Fehler: ${log}`);
}
return shader;
};
const vsSource = `
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}
`;
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vsSource);
console.log(vertexShader instanceof WebGLShader);
Vertex- und Fragment-Shader zu einem Programm verknüpfen
const gl = document.createElement('canvas').getContext('webgl');
const compile = (type, src) => {
const s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(s));
}
return s;
};
const vs = compile(gl.VERTEX_SHADER, `
attribute vec2 aPosition;
void main() { gl_Position = vec4(aPosition, 0.0, 1.0); }
`);
const fs = compile(gl.FRAGMENT_SHADER, `
precision mediump float;
void main() { gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0); }
`);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(program));
}
// Shader werden nach dem Linken nicht mehr gebraucht
gl.detachShader(program, vs);
gl.detachShader(program, fs);
gl.deleteShader(vs);
gl.deleteShader(fs);
gl.useProgram(program);
console.log('Programm bereit');
Kompilierfehler auslesen
const gl = document.createElement('canvas').getContext('webgl');
const shader = gl.createShader(gl.FRAGMENT_SHADER);
// Absichtlicher Fehler: fehlendes Semikolon und keine Präzision
gl.shaderSource(shader, 'void main() { gl_FragColor = vec4(1.0) }');
gl.compileShader(shader);
console.log(gl.getShaderParameter(shader, gl.COMPILE_STATUS));
console.log(gl.getShaderInfoLog(shader));
console.log(gl.getShaderParameter(shader, gl.SHADER_TYPE) === gl.FRAGMENT_SHADER);
gl.deleteShader(shader);
// Wichtig · Fallstricke
- Kein Konstruktor:
new WebGLShader()wirft einenTypeError. Verwende immergl.createShader(). - Fehler kommen still:
gl.compileShader()wirft bei Fehlern keine Ausnahme. Prüfe deshalb immerCOMPILE_STATUS. Der Text vongetShaderInfoLog()sieht je nach Browser und Treiber anders aus. - Präzision: Im Fragment-Shader von GLSL ES 1.00 ist eine Präzisionsangabe wie
precision mediump float;Pflicht, sonst schlägt das Kompilieren fehl. - GLSL-Version: WebGL 2 unterstützt GLSL ES 3.00. Dann muss
#version 300 esin der allerersten Zeile stehen, auch Leerzeilen davor sind nicht erlaubt. Stattattribute/varying/gl_FragColornutzt du dortin/out. - Kontextverlust: Nach dem Ereignis
webglcontextlostsind alle Shader-Objekte ungültig und müssen nachwebglcontextrestoredneu erzeugt werden. - Leistung: Kompilieren und Linken sind teuer. Übersetze Shader einmal beim Start und nicht in jedem Frame. Mit der Erweiterung
KHR_parallel_shader_compilelässt sich das Kompilieren nicht blockierend abfragen. - Sicherheit: Übernimm keinen GLSL-Code ungeprüft aus Benutzereingaben. Fehlerhafte Shader können die GPU stark belasten oder den Kontext zum Absturz bringen.
- Unterstützt von allen aktuellen Browsern. Auch in Web Workers verfügbar, zusammen mit
OffscreenCanvas.