Signatur
Beschreibung
Die Eigenschaft precision eines WebGLShaderPrecisionFormat-Objekts gibt als Ganzzahl an, wie viele Bits Genauigkeit ein Zahlenformat im Shader hat. Genauer gesagt ist es der Logarithmus zur Basis 2 der relativen Genauigkeit: Beim Wert 23 (typisch für highp float, also IEEE-754 single precision) lassen sich Werte mit einer relativen Genauigkeit von etwa 2-23 darstellen.
Das Objekt selbst bekommst du nicht über einen Konstruktor, sondern über gl.getShaderPrecisionFormat(shaderType, precisionType). shaderType ist gl.VERTEX_SHADER oder gl.FRAGMENT_SHADER, precisionType einer der Werte LOW_FLOAT, MEDIUM_FLOAT, HIGH_FLOAT, LOW_INT, MEDIUM_INT oder HIGH_INT.
Gebraucht wird das vor allem, wenn du zur Laufzeit entscheiden willst, ob ein Fragment-Shader mit precision highp float; oder mit mediump kompiliert werden soll. Auf Mobilgeräten liefert mediump oft nur 10 Bits (ein Half-Float). Das reicht nicht für Aufgaben wie Weltkoordinaten, Tiefenwerte oder feine Texturkoordinaten in großen Texturen.
Bei Ganzzahlformaten (*_INT) ist precision immer 0, weil Ganzzahlen exakt dargestellt werden. Dort ist nur der Wertebereich über rangeMin und rangeMax wichtig.
Rückgabewert
*_INT-Formaten immer 0. Unterstützt das Gerät ein Format nicht (z. B. highp im Fragment-Shader auf alter GLES2-Hardware), sind precision, rangeMin und rangeMax alle 0.Beispiele
Präzision von highp float im Fragment-Shader abfragen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const fmt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
console.log(`precision: ${fmt.precision}, range: [-2^${fmt.rangeMin}, 2^${fmt.rangeMax}]`);
Passende Float-Präzision für den Fragment-Shader wählen
const pickFragmentPrecision = (gl) => {
const high = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
// precision === 0 bedeutet: highp wird nicht unterstützt
return high && high.precision > 0 ? 'highp' : 'mediump';
};
const gl = document.createElement('canvas').getContext('webgl');
const precision = pickFragmentPrecision(gl);
const fragmentSource = `precision ${precision} float;
void main() {
gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
}`;
console.log(fragmentSource.split('\n')[0]);
Alle Präzisionsformate als Tabelle ausgeben
const gl = document.createElement('canvas').getContext('webgl');
const shaders = { VERTEX: gl.VERTEX_SHADER, FRAGMENT: gl.FRAGMENT_SHADER };
const types = ['LOW_FLOAT', 'MEDIUM_FLOAT', 'HIGH_FLOAT', 'LOW_INT', 'MEDIUM_INT', 'HIGH_INT'];
const rows = [];
for (const [shaderName, shaderType] of Object.entries(shaders)) {
for (const type of types) {
const { precision, rangeMin, rangeMax } = gl.getShaderPrecisionFormat(shaderType, gl[type]);
rows.push({ shader: shaderName, type, precision, rangeMin, rangeMax });
}
}
console.table(rows);
// Wichtig · Fallstricke
- Nur lesbar: Wenn du der Eigenschaft einen Wert zuweist, passiert nichts (im Strict Mode gibt es einen
TypeError). - Desktop gegen Mobil: Desktop-GPUs geben oft für alle Float-Stufen
23zurück, weil sie intern immer mit 32 Bit rechnen. Tests auf dem Desktop verdecken deshalb leicht Präzisionsfehler, die erst auf Mobilgeräten mitmediump=10sichtbar werden. - Kein Support = 0: Wird ein Format nicht unterstützt, sind alle drei Werte
0. Prüfe immerprecision > 0, bevor duhighpim Fragment-Shader verwendest (unter WebGL 1 ist das optional, unter WebGL 2 Pflicht). - Verlorener Kontext: Ist der WebGL-Kontext verloren, gibt
getShaderPrecisionFormat()nullzurück. Greife also nicht ungeprüft auf.precisionzu. - Datenschutz: Die Werte gehören zu den Merkmalen für Browser-Fingerprinting. Manche Browser (z. B. mit Schutz gegen Fingerprinting) geben daher vereinheitlichte Werte zurück.
- Verfügbar in
WebGLRenderingContextundWebGL2RenderingContextin allen modernen Browsern.