Signatur
Beschreibung
Mit getUniformLocation() holst du dir einen „Griff“ auf eine uniform-Variable eines Shader-Programms. Uniforms sind Werte, die für alle Vertices bzw. Fragmente eines Zeichenaufrufs gleich bleiben, zum Beispiel Transformationsmatrizen, Farben, die Zeit für Animationen oder Textureinheiten für sampler2D.
Das zurückgegebene WebGLUniformLocation-Objekt übergibst du anschließend an die uniform*()-Methoden wie uniform1f(), uniform4fv() oder uniformMatrix4fv(), um den Wert zu setzen. Diese Methoden wirken immer auf das Programm, das gerade mit useProgram() aktiv ist.
Du solltest die Location einmal nach dem Linken des Programms abfragen und zwischenspeichern, nicht bei jedem Frame. Der Aufruf geht über Zeichenketten und kann den Treiber ansprechen, darum ist er vergleichsweise teuer. Elemente von Arrays und Struct-Felder sprichst du über Namen wie "uLights[2].color" oder "uWeights[0]" an.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $program Pflicht | WebGLProgram | Das gelinkte Shader-Programm (nach linkProgram()), in dem die uniform-Variable gesucht wird. |
|
| $name Pflicht | string | Name der uniform-Variable, genau so wie im GLSL-Code (Groß-/Kleinschreibung zählt). Für Arrays und Structs sind Namen wie "uArr[1]" oder "uLight.pos" erlaubt. Namen mit dem Präfix gl_ oder webgl_ sind nicht zulässig. |
Rückgabewert
WebGLUniformLocation-Objekt, oder null, wenn die Variable nicht existiert, vom Shader-Compiler als unbenutzt entfernt wurde oder der Name ungültig ist.Beispiele
Farbe und Matrix eines Shaders setzen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const vsSource = `
attribute vec2 aPosition;
uniform mat4 uMatrix;
void main() { gl_Position = uMatrix * vec4(aPosition, 0.0, 1.0); }
`;
const fsSource = `
precision mediump float;
uniform vec4 uColor;
void main() { gl_FragColor = uColor; }
`;
const compile = (type, src) => {
const shader = gl.createShader(type);
gl.shaderSource(shader, src);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(shader));
}
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);
// Locations einmal nach dem Linken abfragen
const uColor = gl.getUniformLocation(program, 'uColor');
const uMatrix = gl.getUniformLocation(program, 'uMatrix');
gl.useProgram(program); // uniform*() wirkt auf das aktive Programm
gl.uniform4f(uColor, 1.0, 0.4, 0.0, 1.0);
gl.uniformMatrix4fv(uMatrix, false, new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1,
]));
console.log(uColor instanceof WebGLUniformLocation);
Alle Uniforms automatisch cachen
// Legt eine Map Name -> Location für alle aktiven Uniforms an
const getUniformLocations = (gl, program) => {
const locations = {};
const count = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
for (let i = 0; i < count; i++) {
const info = gl.getActiveUniform(program, i);
// Arrays werden als "name[0]" gemeldet, das Suffix entfernen
const name = info.name.replace(/\[0\]$/, '');
locations[name] = gl.getUniformLocation(program, info.name);
}
return locations;
};
const uniforms = getUniformLocations(gl, program);
console.log(Object.keys(uniforms));
Zeit-Uniform animieren und null abfangen
const uTime = gl.getUniformLocation(program, 'uTime');
if (uTime === null) {
console.warn('uTime nicht gefunden – falsch geschrieben oder vom Compiler entfernt?');
}
const render = (t) => {
gl.useProgram(program);
// uniform1f mit null ist erlaubt und bewirkt einfach nichts
gl.uniform1f(uTime, t / 1000);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(render);
};
requestAnimationFrame(render);
// Wichtig · Fallstricke
- Unbenutzte Uniforms werden entfernt: Wenn der GLSL-Compiler eine deklarierte Uniform nicht braucht, optimiert er sie weg. Dann liefert der Aufruf
null, obwohl die Variable im Quelltext steht. Beim Debuggen ist das eine häufige Ursache für Verwirrung. - Wenn du
nullanuniform*()übergibst, passiert still nichts. Du bekommst also keinen Fehler, falls ein Name falsch geschrieben ist. - Die Location gilt nur für genau das Programm, für das sie abgefragt wurde. Linkst du das Programm neu (
linkProgram()), werden alle alten Locations ungültig. Benutzt du sie mit einem anderen Programm, meldet WebGLINVALID_OPERATION. - Ist das Programm nicht erfolgreich gelinkt, entsteht
INVALID_OPERATION. Prüfe das vorher mitgetProgramParameter(program, gl.LINK_STATUS). - Samplern (
sampler2D) weist du mituniform1i()die Nummer der Textureinheit zu, nicht das Texturobjekt selbst. - Nach einem Kontextverlust (
webglcontextlost) sind alle Locations ungültig und müssen neu abgefragt werden. - Die Methode gibt es auch in
WebGL2RenderingContext. In WebGL 2 lassen sich viele Uniforms zusätzlich in Uniform-Blöcken zusammenfassen (getUniformBlockIndex()).