Start · Sprachen · JavaScript · Referenz · EXT_sRGB extension

EXT_sRGB extension

Schnittstelle

WebGL-1-Erweiterung mit sRGB-Formaten für Texturen und Renderbuffer. Die GPU rechnet Farben damit automatisch zwischen sRGB und linearem Farbraum um.

seit JavaScript WebGL 1 (Erweiterung); in WebGL 2 fester Bestandte Kategorie: webapi

Signatur

interface EXT_sRGB

Beschreibung

Die Erweiterung EXT_sRGB erweitert einen WebGLRenderingContext (WebGL 1) um drei Formate: SRGB_EXT, SRGB_ALPHA_EXT und SRGB8_ALPHA8_EXT. Dazu kommt die Abfragekonstante FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT. Texturen in diesen Formaten speichern ihre Farbwerte gamma-kodiert (sRGB). Liest ein Shader sie mit texture2D(), wandelt die GPU die Werte vor der Filterung in lineare Werte um. Beim Schreiben in einen Framebuffer mit sRGB-Anhang läuft die Umrechnung umgekehrt (linear → sRGB), und zwar auch beim Blending.

Das ist die Grundlage für physikalisch korrekte Beleuchtung. Lichtberechnung, Farbmischung, Texturfilterung und Blending stimmen mathematisch nur im linearen Farbraum. Bilddateien wie PNG oder JPEG liegen aber fast immer in sRGB vor. Ohne die Erweiterung muss man die Umrechnung im Shader von Hand nachbilden, etwa mit pow(color, vec3(2.2)). Das ist ungenauer und kostet Rechenzeit. Außerdem filtert die GPU dann auf nichtlinearen Werten, und dadurch entstehen z. B. zu dunkle Kanten bei bilinearer Filterung.

Die Erweiterung erhält man über gl.getExtension('EXT_sRGB'). Der Aufruf liefert ein Objekt mit den Konstanten oder null, wenn Gerät oder Browser die Erweiterung nicht unterstützen. Das Objekt hat keine Methoden, nur diese Konstanten:

  • ext.SRGB_EXT (0x8C40): sRGB-Format ohne Alphakanal, nur für Texturen
  • ext.SRGB_ALPHA_EXT (0x8C42): sRGB mit linearem Alphakanal, für Texturen
  • ext.SRGB8_ALPHA8_EXT (0x8C43): internes Format für renderbufferStorage()
  • ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT (0x8210): Abfrage mit getFramebufferAttachmentParameter(), liefert gl.LINEAR oder ext.SRGB_EXT

Rückgabewert

Typ
EXT_sRGB | null
Beschreibung
gl.getExtension('EXT_sRGB') liefert das Erweiterungsobjekt mit den vier Konstanten. Wird die Erweiterung nicht unterstützt, ist das Ergebnis null.

Beispiele

Erweiterung aktivieren und eine sRGB-Textur laden

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const ext = gl.getExtension('EXT_sRGB');

const loadSRGBTexture = (url) => new Promise((resolve, reject) => {
  const img = new Image();
  img.crossOrigin = 'anonymous';
  img.onload = () => {
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    // Mit der Erweiterung: sRGB-Format, sonst Rückfall auf RGBA
    const fmt = ext ? ext.SRGB_ALPHA_EXT : gl.RGBA;
    // In WebGL 1 müssen internalformat und format gleich sein
    gl.texImage2D(gl.TEXTURE_2D, 0, fmt, fmt, gl.UNSIGNED_BYTE, img);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    resolve(tex);
  };
  img.onerror = reject;
  img.src = url;
});

const tex = await loadSRGBTexture('albedo.png');
console.log(ext ? 'sRGB-Textur, Shader liest lineare Werte' : 'Fallback: manuelle Gamma-Korrektur nötig');
sRGB-Textur, Shader liest lineare Werte

Framebuffer mit sRGB-Renderbuffer anlegen und Kodierung prüfen

const gl = document.querySelector('canvas').getContext('webgl');
const ext = gl.getExtension('EXT_sRGB');
if (!ext) throw new Error('EXT_sRGB nicht verfügbar');

const fb = gl.createFramebuffer();
const rb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
gl.renderbufferStorage(gl.RENDERBUFFER, ext.SRGB8_ALPHA8_EXT, 512, 512);

gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);

const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log('vollständig:', status === gl.FRAMEBUFFER_COMPLETE);

const encoding = gl.getFramebufferAttachmentParameter(
  gl.FRAMEBUFFER,
  gl.COLOR_ATTACHMENT0,
  ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT
);
console.log('sRGB-kodiert:', encoding === ext.SRGB_EXT);
vollständig: true sRGB-kodiert: true

Shader mit und ohne Erweiterung (Fallback)

const gl = document.querySelector('canvas').getContext('webgl');
const hasSRGB = gl.getExtension('EXT_sRGB') !== null;

// Ohne Erweiterung dekodiert der Shader selbst (Näherung mit Gamma 2.2)
const fragmentSource = `
precision mediump float;
uniform sampler2D uAlbedo;
varying vec2 vUv;
void main() {
  vec3 albedo = texture2D(uAlbedo, vUv).rgb;
  ${hasSRGB ? '' : 'albedo = pow(albedo, vec3(2.2));'}
  vec3 lit = albedo * 0.8; // Beleuchtung im linearen Raum
  // Canvas-Framebuffer ist nicht sRGB: Ausgabe von Hand kodieren
  gl_FragColor = vec4(pow(lit, vec3(1.0 / 2.2)), 1.0);
}`;

const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fragmentSource);
gl.compileShader(shader);
console.log(gl.getShaderParameter(shader, gl.COMPILE_STATUS));
true