Signatur
Beschreibung
setViewport() bestimmt, auf welchen rechteckigen Bereich der Render-Attachments die Ausgabe des Vertex-Shaders abgebildet wird. Die Clip-Space-Koordinaten (nach der perspektivischen Division im Bereich -1 bis 1 für x/y und 0 bis 1 für z) werden linear auf das Rechteck (x, y, width, height) in Pixeln und auf den Tiefenbereich minDepth bis maxDepth umgerechnet.
Typische Einsatzfälle sind Split-Screen-Ansichten (mehrere Kameras in einem Render-Pass), Minimaps und Bild-in-Bild-Darstellungen, das Rendern in einzelne Kacheln eines Texture-Atlas (z. B. Shadow-Map-Atlas) oder das Beschränken des Tiefenbereichs, etwa um ein Skybox- oder HUD-Element immer vorn bzw. hinten darzustellen.
Ohne Aufruf gilt standardmäßig ein Viewport, der das gesamte Attachment abdeckt, mit Tiefenbereich 0 bis 1. Der gesetzte Wert bleibt bis zum nächsten Aufruf von setViewport() oder bis zum Ende des Render-Passes gültig und betrifft alle folgenden Zeichenbefehle. Beachte: Der Viewport skaliert die Geometrie – er schneidet nicht ab. Zum reinen Abschneiden ohne Skalierung dient setScissorRect().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $x Pflicht | number | Minimaler X-Wert (linke Kante) des Viewports in Pixeln. Gleitkommawerte sind erlaubt. | |
| $y Pflicht | number | Minimaler Y-Wert (obere Kante) des Viewports in Pixeln. In WebGPU liegt der Ursprung oben links. | |
| $width Pflicht | number | Breite des Viewports in Pixeln, muss ≥ 0 sein. | |
| $height Pflicht | number | Höhe des Viewports in Pixeln, muss ≥ 0 sein. | |
| $minDepth Pflicht | number | Minimaler Tiefenwert, im Bereich 0.0 bis 1.0 und ≤ maxDepth. |
|
| $maxDepth Pflicht | number | Maximaler Tiefenwert, im Bereich 0.0 bis 1.0 und ≥ minDepth. |
Rückgabewert
Beispiele
Viewport explizit auf die ganze Canvas setzen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
const encoder = device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: { r: 0.1, g: 0.1, b: 0.1, a: 1 },
loadOp: 'clear',
storeOp: 'store'
}]
});
// Entspricht dem Standard-Viewport
pass.setViewport(0, 0, canvas.width, canvas.height, 0, 1);
// pass.setPipeline(pipeline); pass.draw(3);
pass.end();
device.queue.submit([encoder.finish()]);
Split-Screen: zwei Kameras in einem Render-Pass
// Annahme: pipeline, device, canvas, pass wie oben;
// bindGroupLeft/bindGroupRight enthalten je eine eigene Kamera-Matrix
const halfWidth = canvas.width / 2;
pass.setPipeline(pipeline);
// Linke Hälfte – Spieler 1
pass.setViewport(0, 0, halfWidth, canvas.height, 0, 1);
pass.setBindGroup(0, bindGroupLeft);
pass.draw(36);
// Rechte Hälfte – Spieler 2
pass.setViewport(halfWidth, 0, halfWidth, canvas.height, 0, 1);
pass.setBindGroup(0, bindGroupRight);
pass.draw(36);
pass.end();
Minimap mit Viewport und Scissor sowie Tiefenbereich
const size = 200;
const margin = 16;
const x = canvas.width - size - margin;
const y = margin;
// Hauptszene
pass.setViewport(0, 0, canvas.width, canvas.height, 0, 1);
pass.setBindGroup(0, mainCamera);
pass.draw(vertexCount);
// Minimap oben rechts; Tiefenbereich 0–0.1, damit sie vor der Szene liegt
pass.setViewport(x, y, size, size, 0, 0.1);
pass.setScissorRect(x, y, size, size); // Clear/Zeichnung auf Bereich begrenzen
pass.setBindGroup(0, topDownCamera);
pass.draw(vertexCount);
// Wichtig · Fallstricke
- Validierung: Verletzen die Werte die Regeln (
width/height< 0,minDepth/maxDepthaußerhalb von 0–1,minDepth > maxDepth, Viewport außerhalb der erlaubten Grenzen vonmaxTextureDimension2D), wird kein Fehler geworfen: Der Encoder wird ungültig, und der Fehler erscheint erst beifinish()/submit()als Validierungsfehler (z. B. überdevice.pushErrorScope('validation')oder die Konsole). - Koordinatensystem: Anders als in WebGL liegt der Ursprung oben links, und y wächst nach unten. Aus WebGL portierter Code, der
gl.viewport()mit Ursprung unten links nutzt, muss angepasst werden. - Viewport ≠ Scissor: Der Viewport skaliert die Geometrie; Fragmente außerhalb des Attachments werden zwar verworfen, ein Clear über
loadOp: 'clear'betrifft aber immer das gesamte Attachment. Zum BegrenzensetScissorRect()zusätzlich verwenden. - Canvas-Größe: Nutze
canvas.width/canvas.height(Pixelpuffer), nicht die CSS-Größe – sonst stimmt der Viewport beidevicePixelRatio≠ 1 nicht. - Der Zustand gilt nur für den aktuellen Render-Pass; jeder neue Pass beginnt wieder mit dem Standard-Viewport.
- Kompatibilität: WebGPU erfordert einen sicheren Kontext (HTTPS) und ist noch nicht in allen Browsern/Plattformen verfügbar – vorher auf
navigator.gpuprüfen.