Signatur
Beschreibung
EXT_color_buffer_half_float erlaubt es, in Farbpuffer mit 16-Bit-Gleitkommawerten zu rendern. Ohne sie kann WebGL 1 nur in 8-Bit-Formate mit normalisierten Werten zwischen 0 und 1 schreiben. Für HDR-Rendering, Tone-Mapping, Bloom, Deferred Shading, Partikelsimulationen oder GPGPU-Berechnungen reichen Wertebereich und Genauigkeit dann oft nicht aus. Half Float bietet Werte bis etwa ±65504 bei rund drei Dezimalstellen Genauigkeit und braucht dabei nur halb so viel Speicher und Bandbreite wie 32-Bit-Float.
Du aktivierst die Erweiterung mit gl.getExtension("EXT_color_buffer_half_float"). Das zurückgegebene Objekt hat keine Methoden, sondern nur Konstanten:
ext.RGBA16F_EXT(0x881A): internes Format für RGBA-Renderbuffer mit 16-Bit-Float-Werten.ext.RGB16F_EXT(0x881B): internes Format für RGB-Renderbuffer. Als Renderziel wird es in der Praxis selten unterstützt.ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT(0x8211): Abfrage-Schlüssel fürgetFramebufferAttachmentParameter(). Liefert den Komponententyp eines Anhangs.ext.UNSIGNED_NORMALIZED_EXT(0x8C17): möglicher Rückgabewert dieser Abfrage (normalisierte Ganzzahlen ohne Vorzeichen, also ein „normaler“ 8-Bit-Puffer). Bei Float-Anhängen wird stattdessengl.FLOATgeliefert.
In WebGL 1 brauchst du zum Rendern in eine Textur zusätzlich OES_texture_half_float. Die Textur legst du dann mit dem Typ HALF_FLOAT_OES (0x8D61) an. In WebGL 2 sind Half-Float-Texturen schon im Kern enthalten (gl.RGBA16F, gl.HALF_FLOAT). Hier sorgt die Erweiterung nur dafür, dass R16F, RG16F und RGBA16F als Renderziel gültig sind („color-renderable“). Wer auch 32-Bit-Float-Ziele braucht, nutzt in WebGL 2 stattdessen EXT_color_buffer_float. Diese Erweiterung schließt die 16-Bit-Formate mit ein.
Rückgabewert
gl.getExtension("EXT_color_buffer_half_float") gibt das Erweiterungsobjekt mit den Konstanten zurück. Wird die Erweiterung vom Browser oder der GPU nicht unterstützt, ist das Ergebnis null.Beispiele
WebGL 1: in eine Half-Float-Textur rendern
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const texExt = gl.getExtension('OES_texture_half_float');
const cbExt = gl.getExtension('EXT_color_buffer_half_float');
if (!texExt || !cbExt) {
throw new Error('Half-Float-Rendering wird nicht unterstützt');
}
const width = 512;
const height = 512;
// Textur mit 16-Bit-Float pro Kanal anlegen
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0,
gl.RGBA, texExt.HALF_FLOAT_OES, null);
// Lineares Filtern bräuchte OES_texture_half_float_linear
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, tex, 0);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log(status === gl.FRAMEBUFFER_COMPLETE ? 'HDR-FBO bereit' : 'FBO unvollständig');
WebGL 1: Renderbuffer mit RGBA16F_EXT
const gl = document.createElement('canvas').getContext('webgl');
const ext = gl.getExtension('EXT_color_buffer_half_float');
if (ext) {
const rb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
gl.renderbufferStorage(gl.RENDERBUFFER, ext.RGBA16F_EXT, 256, 256);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.RENDERBUFFER, rb);
// Komponententyp des Anhangs abfragen
const type = gl.getFramebufferAttachmentParameter(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
ext.FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT);
console.log(type === gl.FLOAT ? 'Float-Anhang' : 'Normalisierter Anhang');
}
WebGL 2: RGBA16F-Renderziel mit Fallback
const gl = document.createElement('canvas').getContext('webgl2');
// EXT_color_buffer_float deckt 16- und 32-Bit-Float ab
const canRenderHalf =
gl.getExtension('EXT_color_buffer_float') !== null ||
gl.getExtension('EXT_color_buffer_half_float') !== null;
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
if (canRenderHalf) {
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA16F, 1024, 1024);
} else {
// Fallback: 8-Bit, kein HDR
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1024, 1024);
}
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, tex, 0);
console.log(canRenderHalf ? 'Rendern in RGBA16F' : 'Fallback RGBA8');