Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.attachShader()

WebGLRenderingContext.attachShader()

Methode

Hängt einen kompilierten Vertex- oder Fragment-Shader (<code>WebGLShader</code>) an ein <code>WebGLProgram</code> an, damit das Programm anschließend gelinkt werden kann.

seit JavaScript Baseline: alle Browser (WebGL 1.0) Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.attachShader(program, shader)

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() und gl.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

Typ
void
Beschreibung
Kein 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');
}
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);
2 2

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 muss gl.getError() prüfen.
  • Fehlerprüfung: attachShader() prüft nicht, ob der Shader kompiliert werden konnte. Kompilierfehler zeigen sich erst bei COMPILE_STATUS oder beim Linken. Deshalb immer getShaderParameter() und getProgramParameter(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 WebGL2RenderingContext und in Workern über OffscreenCanvas.