Signatur
Beschreibung
getUniformIndices() ordnet Uniform-Namen ihren aktiven Uniform-Indizes in einem gelinkten Shader-Programm zu. Diese Indizes sind nicht dasselbe wie die Locations von getUniformLocation(). Man braucht sie für die Abfrage-Methoden, die mit Indizes arbeiten, vor allem getActiveUniforms() und getActiveUniform().
Am häufigsten kommt die Methode bei Uniform Buffer Objects (UBOs) zum Einsatz. Wenn ein Uniform-Block das Layout shared oder packed nutzt, kennt man die Byte-Offsets der einzelnen Mitglieder nicht im Voraus. Dann holt man zuerst mit getUniformIndices() die Indizes und fragt danach mit getActiveUniforms(program, indices, gl.UNIFORM_OFFSET) die Offsets ab. So lässt sich der Puffer passend befüllen.
Namen, die im Programm nicht als aktive Uniforms vorkommen, bekommen den Wert gl.INVALID_INDEX (0xFFFFFFFF). Das passiert auch, wenn der Shader-Compiler eine unbenutzte Uniform wegoptimiert hat. Bei Arrays und Struct-Mitgliedern muss man den vollständigen Namen angeben, z. B. "lights[0].color" oder "weights[0]".
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $program Pflicht | WebGLProgram | Ein erfolgreich gelinktes Shader-Programm. | |
| $uniformNames Pflicht | Array<string> | Array mit den Namen der Uniforms, deren Indizes abgefragt werden sollen. Bei Block-Mitgliedern ohne Instanznamen reicht der Mitgliedsname, mit Instanznamen gilt Blockname.mitglied. |
Rückgabewert
GLuint) in derselben Reihenfolge wie uniformNames. Unbekannte oder inaktive Namen ergeben gl.INVALID_INDEX. Bei einem Fehler, z. B. einem ungültigen Programm, wird null zurückgegeben.Beispiele
Indizes einfacher Uniforms abfragen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const vsSource = `#version 300 es
uniform mat4 uModel;
uniform float uScale;
in vec4 aPos;
void main() { gl_Position = uModel * aPos * uScale; }`;
const fsSource = `#version 300 es
precision highp float;
uniform vec4 uColor;
out vec4 outColor;
void main() { outColor = uColor; }`;
const compile = (type, src) => {
const s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
return s;
};
const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);
const indices = gl.getUniformIndices(program, ['uModel', 'uColor', 'uGibtEsNicht']);
console.log(indices.map(i => i === gl.INVALID_INDEX ? 'INVALID' : i));
Offsets in einem Uniform Buffer Object ermitteln
// Annahme: gl und ein gelinktes program mit folgendem Block:
// layout(std140) uniform Material { vec4 diffuse; vec4 specular; float shininess; };
const names = ['diffuse', 'specular', 'shininess'];
const indices = gl.getUniformIndices(program, names);
if (indices.includes(gl.INVALID_INDEX)) {
throw new Error('Mindestens eine Uniform ist nicht aktiv');
}
const offsets = gl.getActiveUniforms(program, indices, gl.UNIFORM_OFFSET);
const blockIndex = gl.getUniformBlockIndex(program, 'Material');
const blockSize = gl.getActiveUniformBlockParameter(
program, blockIndex, gl.UNIFORM_BLOCK_DATA_SIZE
);
const data = new Float32Array(blockSize / 4);
data.set([1, 0, 0, 1], offsets[0] / 4); // diffuse
data.set([1, 1, 1, 1], offsets[1] / 4); // specular
data[offsets[2] / 4] = 32; // shininess
const ubo = gl.createBuffer();
gl.bindBuffer(gl.UNIFORM_BUFFER, ubo);
gl.bufferData(gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW);
gl.uniformBlockBinding(program, blockIndex, 0);
gl.bindBufferBase(gl.UNIFORM_BUFFER, 0, ubo);
console.log(names.map((n, i) => `${n}: ${offsets[i]}`));
Typ und Größe über die Indizes auslesen
const indices = gl.getUniformIndices(program, ['uModel', 'uColor']);
const types = gl.getActiveUniforms(program, indices, gl.UNIFORM_TYPE);
const sizes = gl.getActiveUniforms(program, indices, gl.UNIFORM_SIZE);
console.log(types[0] === gl.FLOAT_MAT4, types[1] === gl.FLOAT_VEC4, sizes);
// Wichtig · Fallstricke
- Index ist nicht gleich Location: Die zurückgegebenen Indizes kann man nicht an
gl.uniform*()übergeben. Für diese Aufrufe braucht mangetUniformLocation(). - Prüfung auf
INVALID_INDEX: Wegoptimierte oder falsch geschriebene Uniforms lieferngl.INVALID_INDEX(4294967295). Das wirft keinen Fehler. Prüft man den Wert nicht, führt er später zuINVALID_VALUEingetActiveUniforms(). - Programm muss gelinkt sein: Vor dem Aufruf mit
gl.getProgramParameter(program, gl.LINK_STATUS)prüfen. - Performance: Die Abfrage erfordert unter Umständen eine Synchronisation mit der GPU bzw. dem Treiber. Deshalb die Indizes einmal nach dem Linken ermitteln und zwischenspeichern, nicht in jedem Frame neu abfragen.
- Layout
std140: Hier sind die Offsets per Spezifikation festgelegt. Die Abfrage ist trotzdem ein sinnvoller Plausibilitätstest. - Kompatibilität: Nur im
webgl2-Kontext verfügbar, nicht in WebGL 1. Wird von allen aktuellen Browsern unterstützt (Chrome, Edge, Firefox, Safari ab 15).