Signatur
Beschreibung
attachShader() verbindet ein WebGLShader-Objekt mit einem WebGLProgram. Ein lauffähiges WebGL-Programm braucht genau einen Vertex-Shader (gl.VERTEX_SHADER) und genau einen Fragment-Shader (gl.FRAGMENT_SHADER). Beide werden mit attachShader() angehängt, bevor gl.linkProgram() aufgerufen wird.
Der übliche Ablauf sieht so aus:
gl.createShader(typ)erzeugt den Shader.gl.shaderSource()undgl.compileShader()setzen den GLSL-Quelltext und kompilieren ihn.gl.createProgram()erzeugt das Programm.gl.attachShader()hängt beide Shader an.gl.linkProgram()linkt sie,gl.useProgram()aktiviert das Programm.
Die Reihenfolge von attachShader() und compileShader() spielt technisch keine Rolle. Entscheidend ist, dass beide Shader beim Aufruf von linkProgram() angehängt und erfolgreich kompiliert sind. Einen Shader kann man an mehrere Programme anhängen. So lässt sich zum Beispiel ein gemeinsamer Vertex-Shader mit verschiedenen Fragment-Shadern kombinieren.
Die Methode gibt es genauso auch in WebGL2RenderingContext.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $program Pflicht | WebGLProgram | Das Programm, an das der Shader angehängt wird. Wird mit gl.createProgram() erzeugt. |
|
| $shader Pflicht | WebGLShader | Ein Vertex- oder Fragment-Shader, der mit gl.createShader() erzeugt wurde. |
Rückgabewert
undefined). Fehler meldet die Methode nur über gl.getError().Beispiele
Shader-Programm erstellen und linken
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const vsSource = `
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}`;
const fsSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
}`;
const compile = (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 program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(program));
} else {
gl.useProgram(program);
console.log('Programm gelinkt');
}
Angehängte Shader abfragen
const gl = document.createElement('canvas').getContext('webgl');
const program = gl.createProgram();
const vs = gl.createShader(gl.VERTEX_SHADER);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.attachShader(program, vs);
gl.attachShader(program, fs);
console.log(gl.getProgramParameter(program, gl.ATTACHED_SHADERS));
console.log(gl.getAttachedShaders(program).length);
Nach dem Linken aufräumen
// Setzt program, vs und fs aus dem ersten Beispiel voraus
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
// Die Shader werden nach dem Linken nicht mehr gebraucht
gl.detachShader(program, vs);
gl.detachShader(program, fs);
gl.deleteShader(vs);
gl.deleteShader(fs);
}
console.log(gl.getAttachedShaders(program).length);
// Wichtig · Fallstricke
- Doppelt anhängen: Hängt man denselben Shader zweimal an oder einen zweiten Shader desselben Typs an dasselbe Programm, entsteht
gl.INVALID_OPERATION. Eine Exception wird dabei nicht geworfen, man mussgl.getError()prüfen. - Fehlerprüfung:
attachShader()prüft nicht, ob der Shader kompiliert werden konnte. Kompilierfehler zeigen sich erst beiCOMPILE_STATUSoder beim Linken. Deshalb immergetShaderParameter()undgetProgramParameter(program, gl.LINK_STATUS)abfragen. - Kontextverlust: Nach einem
webglcontextlost-Ereignis sind alle Programme und Shader ungültig und müssen neu erzeugt und angehängt werden. - Löschen: Ruft man
deleteShader()für einen noch angehängten Shader auf, wird er erst entfernt, wenn er vom Programm gelöst wird oder das Programm gelöscht wird. - Kompatibilität: Wird von allen modernen Browsern unterstützt, auch in
WebGL2RenderingContextund in Workern überOffscreenCanvas.