Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.viewport()

WebGLRenderingContext.viewport()

Methode

Legt den Viewport fest, also die affine Abbildung von normalisierten Gerätekoordinaten (NDC) auf Fensterkoordinaten im Zeichenpuffer.

seit JavaScript WebGL 1.0 – Baseline: alle Browser Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.viewport(x, y, width, height)

Beschreibung

viewport() bestimmt, auf welchen rechteckigen Bereich des Zeichenpuffers WebGL die Ausgabe des Vertex-Shaders abbildet. Die Clip-Space-Koordinaten werden nach der perspektivischen Division zu normalisierten Gerätekoordinaten im Bereich -1 bis 1. Diese werden dann linear auf das Rechteck (x, y, width, height) in Pixeln umgerechnet: x_w = (x_ndc + 1) * width / 2 + x, entsprechend für y.

Wenn ein WebGL-Kontext erstellt wird, entspricht der Viewport anfangs der Größe des Canvas. Ändert sich später die Größe des Zeichenpuffers (canvas.width/canvas.height), wird der Viewport nicht automatisch angepasst. Du musst viewport() also nach jeder Größenänderung selbst aufrufen, sonst wird das Bild verzerrt oder nur ein Teil der Fläche gefüllt.

Typische Einsatzfälle sind: Größenanpassung nach dem Ändern der Canvas-Größe, geteilte Bildschirme (Split-Screen, mehrere Kameras in einem Canvas), Minimaps und das Rendern in Framebuffer-Objekte, deren Größe sich vom Canvas unterscheidet (z. B. Shadow-Maps oder Post-Processing-Texturen).

Der Ursprung (0, 0) liegt in WebGL unten links, nicht oben links wie bei CSS oder Canvas 2D.

Parameter

Name Typ Default Beschreibung
$x Pflicht number (GLint) 0 Horizontale Position der unteren linken Ecke des Viewports in Pixeln.
$y Pflicht number (GLint) 0 Vertikale Position der unteren linken Ecke des Viewports in Pixeln (von unten gemessen).
$width Pflicht number (GLsizei) Breite des Canvas Breite des Viewports in Pixeln. Negative Werte erzeugen den Fehler gl.INVALID_VALUE.
$height Pflicht number (GLsizei) Höhe des Canvas Höhe des Viewports in Pixeln. Negative Werte erzeugen den Fehler gl.INVALID_VALUE.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert. Den aktuellen Viewport liest du mit gl.getParameter(gl.VIEWPORT) als Int32Array aus.

Beispiele

Viewport an die Canvas-Größe anpassen (inkl. HiDPI)

const canvas = document.querySelector('#glcanvas');
const gl = canvas.getContext('webgl');

const resize = () => {
  const dpr = window.devicePixelRatio || 1;
  const width = Math.round(canvas.clientWidth * dpr);
  const height = Math.round(canvas.clientHeight * dpr);

  if (canvas.width !== width || canvas.height !== height) {
    canvas.width = width;
    canvas.height = height;
  }
  // Viewport an den tatsächlichen Zeichenpuffer anpassen
  gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
  console.log(gl.getParameter(gl.VIEWPORT));
};

new ResizeObserver(resize).observe(canvas);
resize();
Int32Array(4) [0, 0, 1600, 900] // z. B. bei 800×450 CSS-Pixeln und DPR 2

Split-Screen: zwei Ansichten in einem Canvas

const gl = document.querySelector('canvas').getContext('webgl');
const w = gl.drawingBufferWidth;
const h = gl.drawingBufferHeight;

gl.enable(gl.SCISSOR_TEST);

// Linke Hälfte: rot
gl.viewport(0, 0, w / 2, h);
gl.scissor(0, 0, w / 2, h);
gl.clearColor(1, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// hier z. B. drawScene(cameraLinks)

// Rechte Hälfte: blau
gl.viewport(w / 2, 0, w / 2, h);
gl.scissor(w / 2, 0, w / 2, h);
gl.clearColor(0, 0, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// hier z. B. drawScene(cameraRechts)

gl.disable(gl.SCISSOR_TEST);

In ein Framebuffer-Objekt anderer Größe rendern

const gl = document.querySelector('canvas').getContext('webgl');
const size = 512;

const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);

// Viewport auf Texturgröße setzen
gl.viewport(0, 0, size, size);
gl.clearColor(0, 1, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

// Zurück zum Canvas – Viewport wiederherstellen!
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
console.log(gl.getParameter(gl.VIEWPORT));
Int32Array(4) [0, 0, 300, 150] // Standardgröße eines Canvas

// Wichtig · Fallstricke

  • Keine automatische Anpassung: Wenn du canvas.width/canvas.height änderst, bleibt der Viewport gleich. Rufe danach immer gl.viewport() auf.
  • Nutze drawingBufferWidth/drawingBufferHeight statt canvas.width: Der Browser kann einen kleineren Zeichenpuffer anlegen, als angefordert wurde (z. B. bei Speicherknappheit).
  • Viewport ≠ Clipping: gl.clear() beachtet den Viewport nicht und löscht immer den gesamten Puffer. Um nur einen Bereich zu löschen, brauchst du zusätzlich gl.scissor() mit gl.SCISSOR_TEST. Auch Punkte und breite Linien können über den Viewport-Rand hinaus gezeichnet werden.
  • Obergrenze: Breite und Höhe werden stillschweigend auf gl.getParameter(gl.MAX_VIEWPORT_DIMS) begrenzt. Negative Werte führen zu gl.INVALID_VALUE (auslesbar mit gl.getError()).
  • Koordinatensystem: y wird von unten gemessen. Wenn du Mauskoordinaten aus DOM-Events umrechnest, musst du die y-Achse spiegeln.
  • Der Viewport ist globaler Kontext-Zustand und gehört nicht zum Framebuffer. Nach dem Wechsel des Framebuffers musst du ihn also selbst neu setzen.
  • Die Methode gibt es in allen Browsern mit WebGL-Unterstützung. In WebGL2RenderingContext funktioniert sie genauso.