Viewport-Transformation
Nach der perspektivischen Division liegen die Positionen unserer Vertices in den normalisierten Gerätekoordinaten (Normalized Device Coordinates, kurz NDC) vor.
Für die X- und Y-Koordinaten bedeutet das:
x = -1bezeichnet den linken Rand des sichtbaren Bereichs.x = 1bezeichnet den rechten Rand.y = -1bezeichnet den unteren Rand.y = 1bezeichnet den oberen Rand.
Diese Werte sind unabhängig von der Größe unseres Canvas. Ein Canvas mit 400 × 300 Pixeln verwendet denselben NDC-Bereich wie eines mit 1200 × 900 Pixeln.
Damit WebGPU unsere Geometrie tatsächlich zeichnen kann, müssen diese Koordinaten auf den Viewport übertragen werden. Das ist der rechteckige Bereich, in dem WebGPU das Bild rendert.
Diesen Schritt nennt man Viewport-Transformation.
Von NDC zu Pixelkoordinaten
Abschnitt betitelt „Von NDC zu Pixelkoordinaten“Nehmen wir ein Canvas mit einer Breite von 800 und einer Höhe von 600 Pixeln. Wir verwenden den gesamten Canvas als Viewport.
Die X-Koordinaten müssen dann vom Bereich -1 bis 1 auf den Bereich 0 bis 800 abgebildet werden.
Das geschieht in zwei Schritten:
- Wir addieren
1, damit aus dem Bereich-1bis1zunächst der Bereich0bis2wird. - Wir multiplizieren mit der halben Viewport-Breite, damit daraus
0bis800wird.
Die Rechnung lautet:
viewportX = (ndcX + 1) * width / 2Für die Mitte des Bildes, also ndcX = 0, ergibt sich:
viewportX = (0 + 1) * 800 / 2 = 400Der Mittelpunkt liegt damit bei 400 Pixeln.
Bei der Y-Koordinate müssen wir berücksichtigen, dass die Y-Achse der WebGPU-Viewport-Koordinaten nach unten zeigt. Ein NDC-Wert von y = 1 wird deshalb auf den oberen Rand des Viewports abgebildet, ein Wert von y = -1 auf den unteren.
Die Formel lautet daher:
viewportY = (1 - ndcY) * height / 2Bei ndcY = 0 erhalten wir:
viewportY = (1 - 0) * 600 / 2 = 300Der Punkt mit den NDC-Koordinaten (0, 0) landet also in der Mitte unseres Viewports bei (400, 300).
WebGPU berücksichtigt die Umkehrung der Y-Achse bei der Viewport-Transformation automatisch.
WebGPU übernimmt die Transformation
Abschnitt betitelt „WebGPU übernimmt die Transformation“Anders als bei unseren bisherigen Transformationen benötigen wir für diesen Schritt keine eigene Matrix im Vertex-Shader.
WebGPU führt die Viewport-Transformation automatisch durch, nachdem die Clip-Koordinaten verarbeitet und durch w geteilt wurden.
Standardmäßig verwendet WebGPU den gesamten Bereich des aktuellen Render-Targets als Viewport. Wir können diesen Bereich aber auch selbst festlegen.
Dafür gibt es die Methode setViewport() am Render-Pass-Encoder:
passEncoder.setViewport( 0, // x: linker Rand 0, // y: oberer Rand canvas.width, // Breite canvas.height, // Höhe 0, // minimale Tiefe 1, // maximale Tiefe);Die ersten beiden Werte bestimmen, wo der Viewport beginnt. Danach folgen seine Breite und Höhe.
Die letzten beiden Werte legen fest, auf welchen Tiefenbereich die normalisierten Z-Koordinaten abgebildet werden. Mit 0 und 1 verwenden wir den üblichen Tiefenbereich von WebGPU.
Dieser Aufruf ist optional, solange wir den gesamten Canvas verwenden möchten.
Ein kleinerer Viewport
Abschnitt betitelt „Ein kleinerer Viewport“Wir können auch nur einen Teil des Canvas zum Rendern verwenden.
Beispielsweise lässt sich der Viewport auf die linke Hälfte eines 800 × 600 Pixel großen Canvas beschränken:
passEncoder.setViewport(0, 0, 400, 600, 0, 1);Unsere Geometrie wird dadurch nicht verändert. WebGPU bildet dieselben NDC-Koordinaten lediglich auf einen kleineren rechteckigen Bereich ab.
Wichtig ist dabei: Ein Viewport begrenzt nicht automatisch alle gezeichneten Pixel auf dieses Rechteck. Dafür können wir zusätzlich setScissorRect() verwenden.
Der Weg eines Vertex
Abschnitt betitelt „Der Weg eines Vertex“Damit haben wir die gesamte Folge der Koordinatentransformationen kennengelernt:
Lokale Koordinaten | | Model-Matrix vWeltkoordinaten | | View-Matrix vKamerakoordinaten | | Projektionsmatrix vClip-Koordinaten | | Clipping und perspektivische Division vNormalisierte Gerätekoordinaten (NDC) | | Viewport-Transformation vViewport-KoordinatenModel-, View- und Projektionsmatrix wenden wir im Vertex-Shader an. Clipping, perspektivische Division und Viewport-Transformation gehören dagegen zu den anschließenden Schritten der WebGPU-Grafikpipeline.
Den vollständigen Transformationsweg von der lokalen Vertex-Position über die Model- und View-Matrix bis zur Projektion kannst du in Beispiel 20 – Vertex-Transformationen nachvollziehen. Dort wenden wir alle drei Matrizen auf unseren Würfel an.