Signatur
Beschreibung
Die schreibgeschützte Eigenschaft rangeMax eines WebGLShaderPrecisionFormat-Objekts gibt an, wie groß Werte in einem Shader-Typ höchstens werden können. Der Wert ist der Exponent zur Basis 2: Bei rangeMax = 127 reicht der darstellbare Bereich also bis etwa 2^127. Ein solches Objekt bekommt man über gl.getShaderPrecisionFormat(shaderType, precisionType).
Zusammen mit rangeMin (Exponent für den kleinsten darstellbaren Wert bzw. den negativen Bereich) und precision (Anzahl der Mantissenbits) beschreibt rangeMax, welche numerischen Eigenschaften lowp, mediump und highp auf der jeweiligen GPU tatsächlich haben. Diese Angaben unterscheiden sich je nach Gerät, besonders bei mobilen GPUs.
In der Praxis prüft man damit vor dem Kompilieren eines Shaders, ob z. B. highp float im Fragment-Shader unterstützt wird. Ist das nicht der Fall, sind alle drei Werte 0. Außerdem lässt sich abschätzen, ob Berechnungen mit großen Zahlen (Weltkoordinaten, Zeitwerte, Tiefenwerte) in mediump überlaufen würden.
Typische Werte: Bei IEEE-754-Floats mit einfacher Genauigkeit (highp float) ist rangeMax gleich 127, bei mediump float auf vielen Mobil-GPUs 15 (Half-Float, Maximum etwa 65504). Bei Ganzzahltypen (HIGH_INT usw.) liegt der Wert oft bei 31, bei 24 oder niedriger.
Rückgabewert
GLint): Basis-2-Logarithmus des Betrags des größten darstellbaren Werts. 0, wenn die Genauigkeitsstufe nicht unterstützt wird.Beispiele
rangeMax für highp float im Fragment-Shader auslesen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const fmt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
console.log('rangeMin:', fmt.rangeMin);
console.log('rangeMax:', fmt.rangeMax);
console.log('precision:', fmt.precision);
console.log('Maximalwert ≈', 2 ** fmt.rangeMax);
Passende Genauigkeit für den Shader wählen
const gl = document.createElement('canvas').getContext('webgl');
const supportsHighp = () => {
const { rangeMax, precision } =
gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
return rangeMax > 0 && precision > 0;
};
const precisionLine = supportsHighp()
? 'precision highp float;'
: 'precision mediump float;';
const fragmentSource = `${precisionLine}
void main() {
gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
}`;
console.log(precisionLine);
Überlauf-Risiko für große Werte prüfen
const gl = document.createElement('canvas').getContext('webgl');
// Passt ein Wert (z. B. vergangene Millisekunden) in mediump?
const fitsInPrecision = (value, shaderType, precisionType) => {
const { rangeMax } = gl.getShaderPrecisionFormat(shaderType, precisionType);
return Math.abs(value) < 2 ** rangeMax;
};
const elapsedMs = 120000;
console.log(
'mediump ok?',
fitsInPrecision(elapsedMs, gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT)
);
Alle Formate tabellarisch 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 [sName, s] of Object.entries(shaders)) {
for (const t of types) {
const f = gl.getShaderPrecisionFormat(s, gl[t]);
rows.push({ shader: sName, type: t, rangeMin: f.rangeMin, rangeMax: f.rangeMax, precision: f.precision });
}
}
console.table(rows);
// Wichtig · Fallstricke
- Nur ein Exponent:
rangeMaxist der Exponent und nicht der Maximalwert selbst. Den ungefähren Grenzwert erhält man mit2 ** rangeMax. - Kein Unterstützungs-Flag: Wird eine Genauigkeitsstufe nicht unterstützt (klassisch
HIGH_FLOATim Fragment-Shader älterer Mobil-GPUs), sindrangeMin,rangeMaxundprecisionalle0. - Desktop meldet oft überall highp: Viele Desktop-Treiber und ANGLE geben für
lowpundmediumpdieselben Werte wie fürhighpzurück (127). Tests auf dem Desktop sagen deshalb nichts über das Verhalten auf Mobilgeräten aus. - Ganzzahltypen: Bei
*_INTbeschreibtrangeMaxden Ganzzahlbereich, undprecisionist dann0. - Fingerprinting: Die Werte sind geräteabhängig und werden zum Browser-Fingerprinting genutzt. Datenschutz-Modi (z. B. Tor Browser, Firefox mit
resistFingerprinting) können vereinheitlichte Werte liefern. - Verlorener Kontext: Ist der WebGL-Kontext verloren, gibt
getShaderPrecisionFormat()nullzurück. Vor dem Zugriff aufrangeMaxalso aufnullprüfen. - Verfügbar in WebGL 1 und WebGL 2, in allen modernen Browsern unterstützt.