Signatur
Beschreibung
WebGLShaderPrecisionFormat ist ein reines Datenobjekt der WebGL-API. Man erzeugt es nicht selbst. Man bekommt es als Rückgabewert von WebGLRenderingContext.getShaderPrecisionFormat(shaderType, precisionType) bzw. der gleichnamigen Methode von WebGL2RenderingContext. Das Objekt sagt, wie genau die GPU Gleitkomma- oder Ganzzahlen einer bestimmten Präzisionsstufe (lowp, mediump, highp) im Vertex- oder Fragment-Shader tatsächlich darstellt.
Es hat drei schreibgeschützte Eigenschaften:
rangeMin(number): Basis-2-Logarithmus des Betrags der kleinsten darstellbaren Zahl, z. B.127für etwa −2127.rangeMax(number): Basis-2-Logarithmus des Betrags der größten darstellbaren Zahl.precision(number): Anzahl der Bits Genauigkeit (Mantisse). Bei Ganzzahlformaten ist der Wert0.
In der Praxis nutzt man die Schnittstelle vor allem, um herauszufinden, ob highp im Fragment-Shader unterstützt wird. Auf manchen mobilen GPUs liefert sie dann precision === 0. Mit dieser Information kann man GLSL-Code mit passender precision-Deklaration erzeugen oder Genauigkeitsfehler (Banding, Flackern, Z-Fighting bei Berechnungen im Shader) erklären.
Rückgabewert
gl.getShaderPrecisionFormat(). Die Methode gibt null zurück, wenn der Kontext verloren ist (context lost).Beispiele
Präzisionsformat abfragen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const fmt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
console.log(fmt instanceof WebGLShaderPrecisionFormat);
console.log(fmt.rangeMin, fmt.rangeMax, fmt.precision);
highp-Unterstützung im Fragment-Shader prüfen und GLSL anpassen
const gl = document.createElement('canvas').getContext('webgl');
const supportsHighpFragment = (gl) => {
const fmt = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT);
return fmt !== null && fmt.precision > 0;
};
const precision = supportsHighpFragment(gl) ? 'highp' : 'mediump';
const fragmentSource = `precision ${precision} float;
void main() {
gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);
}`;
console.log(`Verwende ${precision}`);
Übersicht aller Formate 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, shader] of Object.entries(shaders)) {
for (const type of types) {
const { rangeMin, rangeMax, precision } = gl.getShaderPrecisionFormat(shader, gl[type]);
rows.push({ shader: shaderName, type, rangeMin, rangeMax, precision });
}
}
console.table(rows);
// Wichtig · Fallstricke
- Kein Konstruktor:
new WebGLShaderPrecisionFormat()wirft einenTypeError. Instanzen liefert nurgetShaderPrecisionFormat(). rangeMin/rangeMaxsind Exponenten (log2), keine absoluten Werte.rangeMinsteht für den Betrag des negativen Grenzwerts und ist deshalb positiv.- Desktop gegen Mobil: Desktop-Browser melden oft für alle Stufen die Werte von
highp(127/127/23), weil die GPU intern immer mit 32 Bit rechnet. Wenn der Desktopmediumpmeldet, heißt das also nicht, dass Mobilgeräte es genauso umsetzen. Auf mobilen Geräten deshalb gezielt testen. - Ganzzahlformate: Bei
LOW_INT,MEDIUM_INTundHIGH_INTistprecisionimmer0. - Kontextverlust: Ist der Kontext verloren, gibt
getShaderPrecisionFormat()nullzurück. Vor dem Zugriff auf die Eigenschaften also aufnullprüfen. - Fingerprinting: Die Werte verraten Eigenschaften der Hardware. Datenschutzorientierte Browser (z. B. Firefox mit
privacy.resistFingerprinting, Tor Browser) können vereinheitlichte Werte melden. - Kompatibilität: Wird in allen modernen Browsern unterstützt, in WebGL 1 und WebGL 2 gleich.