Signatur
Beschreibung
Die Erweiterung OVR_multiview2 gehört zur WebGL-API und ist nur in einem WebGL2-Kontext verfügbar. Sie erlaubt es, dieselbe Szene in einem einzigen Draw-Call in mehrere Ansichten zu rendern. Jede Ansicht landet dabei in einer eigenen Ebene einer TEXTURE_2D_ARRAY. Typischer Einsatz ist Stereo-Rendering für VR/AR (WebXR): Man rendert nicht zweimal nacheinander, sondern einmal in zwei Ebenen. Das spart CPU-Zeit bei den Draw-Calls und bei Zustandswechseln.
Die Erweiterung bekommt man über gl.getExtension('OVR_multiview2'). Das zurückgegebene Objekt bietet die Methode framebufferTextureMultiviewOVR(). Mit ihr hängt man einen Bereich von Array-Ebenen als Multiview-Anhang an ein Framebuffer-Objekt. Außerdem enthält es diese Konstanten:
FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR: Anzahl der Ansichten eines AnhangsFRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR: erste Array-Ebene eines AnhangsMAX_VIEWS_OVR: höchste Zahl gleichzeitiger Ansichten, die die Hardware unterstützt (mindestens 2)FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR: Framebuffer-Status, wenn die Anhänge unterschiedlich viele Ansichten oder unterschiedliche Basis-Indizes haben
Im Shader (GLSL ES 3.00) wird die Erweiterung mit #extension GL_OVR_multiview2 : require eingeschaltet. Die Zahl der Ansichten legt man mit layout(num_views = N) in; fest. Die eingebaute Variable gl_ViewID_OVR (Typ uint) liefert den Index der aktuellen Ansicht. Damit wählt man zum Beispiel die passende View-Projektionsmatrix pro Auge. Im Gegensatz zur älteren OVR_multiview darf gl_ViewID_OVR in OVR_multiview2 nicht nur die Position, sondern jede Vertex-Ausgabe beeinflussen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | Framebuffer-Ziel: gl.FRAMEBUFFER, gl.DRAW_FRAMEBUFFER oder gl.READ_FRAMEBUFFER. Parameter von framebufferTextureMultiviewOVR(). |
|
| $attachment Pflicht | GLenum | Anhangspunkt, z. B. gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT oder gl.DEPTH_STENCIL_ATTACHMENT. |
|
| $texture Pflicht | WebGLTexture | null | Eine TEXTURE_2D_ARRAY-Textur. Mit null wird der Anhang gelöst. |
|
| $level Pflicht | GLint | Mipmap-Stufe der Textur, meist 0. |
|
| $baseViewIndex Pflicht | GLint | Index der ersten Array-Ebene, in die Ansicht 0 gerendert wird. | |
| $numViews Pflicht | GLsizei | Anzahl der Ansichten (Ebenen). Muss zwischen 1 und MAX_VIEWS_OVR liegen und zu num_views im Shader passen. |
Beispiele
Erweiterung prüfen und Grenzen abfragen
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const ext = gl?.getExtension('OVR_multiview2');
if (!ext) {
console.log('OVR_multiview2 nicht verfügbar – Rückfall auf zwei Render-Durchläufe');
} else {
const maxViews = gl.getParameter(ext.MAX_VIEWS_OVR);
console.log(`Multiview aktiv, maximal ${maxViews} Ansichten`);
}
Stereo-Framebuffer mit Farb- und Tiefenanhang anlegen
const gl = document.querySelector('canvas').getContext('webgl2');
const ext = gl.getExtension('OVR_multiview2');
const width = 1024, height = 1024, views = 2;
// Farb-Textur mit 2 Ebenen (linkes/rechtes Auge)
const colorTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, colorTex);
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, views);
// Tiefen-Textur ebenfalls als Array
const depthTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, depthTex);
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.DEPTH_COMPONENT24, width, height, views);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, colorTex, 0, 0, views);
ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, depthTex, 0, 0, views);
const status = gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER);
console.log(status === gl.FRAMEBUFFER_COMPLETE ? 'Framebuffer bereit' : `Fehler: 0x${status.toString(16)}`);
Vertex-Shader mit gl_ViewID_OVR und ein Draw-Call für beide Augen
const vsSource = `#version 300 es
#extension GL_OVR_multiview2 : require
layout(num_views = 2) in;
uniform mat4 u_viewProj[2]; // je eine Matrix pro Auge
uniform mat4 u_model;
in vec4 a_position;
void main() {
gl_Position = u_viewProj[gl_ViewID_OVR] * u_model * a_position;
}`;
const fsSource = `#version 300 es
precision mediump float;
out vec4 outColor;
void main() { outColor = vec4(0.2, 0.6, 1.0, 1.0); }`;
// ... Programm kompilieren/linken wie gewohnt (program), dann:
gl.useProgram(program);
const loc = gl.getUniformLocation(program, 'u_viewProj');
gl.uniformMatrix4fv(loc, false, new Float32Array([...leftViewProj, ...rightViewProj]));
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
gl.viewport(0, 0, 1024, 1024);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, vertexCount); // rendert in beide Ebenen