Signatur
Beschreibung
Mit getAttachedShaders() fragst du ab, welche Shader-Objekte gerade per attachShader() an ein Programm gebunden sind. Typischerweise sind das ein Vertex- und ein Fragment-Shader. Die Methode entspricht dem OpenGL-ES-Aufruf glGetAttachedShaders.
Nützlich ist sie vor allem zum Debuggen, zum Aufräumen (alle Shader eines Programms lösen und löschen, bevor das Programm selbst gelöscht wird) und für Werkzeuge, die zur Laufzeit ein Programm untersuchen, etwa um Shader-Quelltexte mit getShaderSource() auszulesen oder einzelne Shader beim Hot-Reload auszutauschen.
Die Methode gibt es auch auf WebGL2RenderingContext, das Verhalten ist dort identisch. Die Reihenfolge der Shader im Array ist nicht festgelegt. Den Typ eines Shaders findest du daher über gl.getShaderParameter(shader, gl.SHADER_TYPE) heraus.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $program Pflicht | WebGLProgram | Das Programm, dessen angehängte Shader abgefragt werden sollen. |
Rückgabewert
WebGLShader-Objekten, oder ein leeres Array, wenn keine Shader angehängt sind. Ist der Kontext verloren (context lost) oder tritt ein Fehler auf, wird null zurückgegeben.Beispiele
Angehängte Shader eines Programms auflisten
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const compile = (type, source) => {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
return shader;
};
const vs = compile(gl.VERTEX_SHADER, 'attribute vec4 p; void main(){ gl_Position = p; }');
const fs = compile(gl.FRAGMENT_SHADER, 'precision mediump float; void main(){ gl_FragColor = vec4(1.0); }');
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
const shaders = gl.getAttachedShaders(program);
console.log(shaders.length);
shaders.forEach((s) => {
const type = gl.getShaderParameter(s, gl.SHADER_TYPE);
console.log(type === gl.VERTEX_SHADER ? 'Vertex' : 'Fragment');
});
Programm samt Shadern sauber freigeben
const destroyProgram = (gl, program) => {
const shaders = gl.getAttachedShaders(program) ?? [];
for (const shader of shaders) {
gl.detachShader(program, shader);
gl.deleteShader(shader);
}
gl.deleteProgram(program);
};
// Aufruf, z. B. beim Verlassen einer Szene
destroyProgram(gl, program);
console.log(gl.isProgram(program));
Fragment-Shader beim Hot-Reload austauschen
const replaceFragmentShader = (gl, program, newSource) => {
const old = (gl.getAttachedShaders(program) ?? [])
.find((s) => gl.getShaderParameter(s, gl.SHADER_TYPE) === gl.FRAGMENT_SHADER);
const fresh = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fresh, newSource);
gl.compileShader(fresh);
if (!gl.getShaderParameter(fresh, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(fresh));
gl.deleteShader(fresh);
return false;
}
if (old) {
gl.detachShader(program, old);
gl.deleteShader(old);
}
gl.attachShader(program, fresh);
gl.linkProgram(program);
return gl.getProgramParameter(program, gl.LINK_STATUS);
};
console.log(replaceFragmentShader(gl, program,
'precision mediump float; void main(){ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); }'));
// Wichtig · Fallstricke
- Rückgabewert
null: Wenn der Kontext verloren ist (webglcontextlost) oder das Argument ungültig ist, gibt die Methodenullstatt eines Arrays zurück. Prüfe darauf, z. B. mit?? []. - Ungültiges Argument: Ist
programkeinWebGLProgramoder wurde es schon gelöscht, entstehtINVALID_VALUE(abfragbar mitgl.getError()). Programme aus einem anderen Kontext führen zuINVALID_OPERATION. - Keine feste Reihenfolge: Verlass dich nicht auf die Position im Array. Den Typ bestimmst du immer mit
SHADER_TYPE. - Löschen ohne Lösen: Ein Shader, der mit
deleteShader()gelöscht, aber nicht gelöst wurde, bleibt angehängt und taucht weiter im Ergebnis auf, bisdetachShader()aufgerufen oder das Programm gelöscht wird. - Die Methode steht in allen modernen Browsern mit WebGL-Unterstützung zur Verfügung, ebenso auf
WebGL2RenderingContext.