Kapitel 7: Kameras

Wie eine Kamera (camera) in der Computergrafik realisiert wird, obwohl die GPU nur Geometrie im festen Normalized Device Space rendert: extrinsische Parameter (View-Matrix via lookAt), intrinsische Parameter (orthografische vs. perspektivische Projektion), Strahlensatz, View-Frustum und die komplette Vertex-Transformationskette.

Überblick

Die GPU rendert letztlich nur Geometrie innerhalb eines festen Wertebereichs, des Normalized Device Space (NDC). Bisher wurde Geometrie oft direkt in diesem Bereich definiert. Das Ziel dieses Kapitels ist es, die dargestellte Geometrie von einer frei platzierbaren Kamera abhängig zu machen.

Zentraler Gedanke: Statt die Kamera zu bewegen, wird die gesamte Szene so transformiert, dass die Kamera im Ursprung liegt und entlang der negativen Z-Achse blickt.

Die Kamera zerfällt in zwei Parametergruppen:

  • Äußere (extrinsische) Parameter (extrinsic parameters): Position und Ausrichtung der Kamera, umgesetzt durch die View-Matrix V (mittels lookAt).
  • Innere (intrinsische) Parameter (intrinsic parameters): welcher Bereich der Szene gerendert wird (Öffnungswinkel, Brennweite), umgesetzt durch die Projektionsmatrix M_proj (orthografisch oder perspektivisch).

Roter Faden:

  • Der NDC ist der Zielraum, ein Würfel [1,1]3[-1, 1]^3.
  • Die View-Matrix bringt die Szene in den View Space (Camera Space).
  • Die Projektion bildet das Sichtvolumen auf den NDC-Würfel ab.
  • Die perspektivische Projektion folgt aus dem Lochkamera-Modell und dem Strahlensatz.
  • Die gesamte Kette wird in einer Vertex-Shader-Zeile ausgeführt.

Normalized Device Space (NDC)

Der Normalized Device Space (normalized device space) ist der normierte Wertebereich [1,1]3[-1, 1]^3, ein Würfel von (1,1,1)(-1, -1, -1) bis (1,1,1)(1, 1, 1). Nur Vertices innerhalb dieses Würfels werden letztlich gerendert. Die Koordinaten in diesem Raum heißen Normalized Device Coordinates (NDC).

NDC=[1,1]3(Wu¨rfel von (1,1,1) bis (1,1,1))\text{NDC} = [-1, 1]^3 \quad\text{(Würfel von } (-1,-1,-1) \text{ bis } (1,1,1)\text{)}

Motivation: Das Blendenproblem

Das Blendenproblem (aperture problem) ist ein Motivationsbeispiel: Man sitzt im Zug und schaut aus dem Fenster; ein anderer Zug bewegt sich. Mit einem begrenzten Blick (Ausschnitt) ist unmöglich zu entscheiden, ob der eigene oder der andere Zug fährt.

Kernaussage: Bewegung ist relativ. Eine relative Bewegung erzeugt dasselbe visuelle Ergebnis. Das motiviert die Grundidee, statt der Kamera die Szene zu bewegen.

Kameraausrichtung: Szene statt Kamera bewegen

Grundprinzip: Anstatt die Kamera zu bewegen oder zu drehen, bewegt bzw. dreht man die gesamte Szene. Das liefert dasselbe Ergebnis, ist effizienter in der Umsetzung, und die benötigten Transformationen (Translation, Rotation) sind bereits bekannt.

Ziel: Die Kamera liegt im Ursprung und schaut entlang der negativen Z-Achse.

Äußere (extrinsische) Kameraparameter

Die extrinsischen Kameraparameter (extrinsic camera parameters) beschreiben Position und Ausrichtung der Kamera im Weltkoordinatensystem. Sie sind über drei Größen definiert:

  • Kamerazentrum c (camera center): Position der Kamera.
  • Betrachtungspunkt a (look-at point / target): das Blickziel.
  • up-Vektor u (up vector): legt die Oben-Richtung bzw. die Rotation um die Blickachse (Roll) fest.

Diese drei Größen werden durch die View-Matrix integriert und lassen sich automatisch per lookAt in eine Matrix umrechnen.

lookAt

Die Funktion lookAt erzeugt die View-Matrix aus 9 Skalaren: Kamerazentrum, Betrachtungspunkt und up-Vektor.

lookAt( cx, cy, cz,   // Kamerazentrum c
        ax, ay, az,   // Betrachtungspunkt a
        ux, uy, uz ); // up-Vektor u

View Transformation und View-Matrix

Die View Transformation (view transformation) ist die Transformation der gesamten Szene, ausgedrückt als Matrixmultiplikation VV, so dass die Kamera im Ursprung liegt und entlang der negativen Z-Achse schaut. Zugrunde liegt ein rechtshändiges Koordinatensystem. Das resultierende Koordinatensystem heißt View Space bzw. Camera Space.

Die View-Matrix ist das Produkt aus einer Rotationsmatrix (die Kamera-Achsen als Zeilen, ausgedrückt in Weltkoordinaten) und einer Translationsmatrix (Verschiebung um c-c, das negative Kamerazentrum):

V=(xxwxywxzw0yxwyywyzw0zxwzywzzw00001)(100cxw010cyw001czw0001)V = \begin{pmatrix} x_{x_w} & x_{y_w} & x_{z_w} & 0 \\ y_{x_w} & y_{y_w} & y_{z_w} & 0 \\ z_{x_w} & z_{y_w} & z_{z_w} & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} \cdot \begin{pmatrix} 1 & 0 & 0 & -c_{x_w} \\ 0 & 1 & 0 & -c_{y_w} \\ 0 & 0 & 1 & -c_{z_w} \\ 0 & 0 & 0 & 1 \end{pmatrix}

Die Zeilen der linken (Rotations-)Matrix sind die Kamera-Achsen, jeweils in Weltkoordinaten (Index w_w):

  • rot = x-Achse (xxw,xyw,xzw)(x_{x_w}, x_{y_w}, x_{z_w})
  • grün = y-Achse (yxw,yyw,yzw)(y_{x_w}, y_{y_w}, y_{z_w})
  • blau/türkis = z-Achse (zxw,zyw,zzw)(z_{x_w}, z_{y_w}, z_{z_w})

Vertex-Transformationen bis jetzt (Model + View)

Die Model Transformation MModelM_{Model} (model transformation) ist die akkumulierte Kette aus Translation TT, Skalierung SS und Rotation RR, die Objekte in der Welt platziert. Zusammen mit der View-Matrix:

p=VTTSRMModelp\mathbf{p}' = V \cdot \underbrace{T \cdot \ldots \cdot T \cdot S \cdot R}_{M_{Model}} \cdot \mathbf{p}

Die logische Reihenfolge der Ausführung geht von rechts nach links: zuerst wirkt MModelM_{Model} (der Vertex wird in der Welt platziert), dann VV (die Welt wird in den Camera Space gebracht).

Innere (intrinsische) Kameraparameter

Die intrinsischen Kameraparameter (intrinsic camera parameters) legen fest, welcher Bereich der Szene gerendert wird. Bei einer echten Kamera entsprächen sie dem Öffnungswinkel und der Brennweite. Sie werden durch die Projektionsmatrix umgesetzt. Es gibt zwei Projektionsmöglichkeiten:

  • Orthografische / Parallelprojektion (orthographic / parallel projection)
  • Perspektivische Projektion (perspective projection)

Orthografische (Parallel-) Projektion

Bei der orthografischen Projektion verlaufen die Projektionsstrahlen parallel; es gibt keine perspektivische Verkleinerung mit der Entfernung. Definiert wird ein quaderförmiges Rendervolumen zwischen (l,b,n)(l, b, n) und (r,t,f)(r, t, f), das in das kanonische Volumen (NDC) transformiert wird.

Das Rendervolumen ist über seine Grenzen festgelegt:

(xmin,xmax)=(left,right)(x_{min}, x_{max}) = (\text{left}, \text{right}) (ymin,ymax)=(bottom,top)(y_{min}, y_{max}) = (\text{bottom}, \text{top}) (zmin,zmax)=(near,far)(z_{min}, z_{max}) = (\text{near}, \text{far})

Unterschiedliche Seitenverhältnisse werden simuliert, indem die gesamte Szene transformiert wird. Das Seitenverhältnis (aspect ratio) von Kamera und Fenster sollte gleich sein, sonst entstehen Verzerrungen (die Fensterauflösung muss ggf. angepasst werden).

glOrtho( GLdouble left, GLdouble right,
         GLdouble bottom, GLdouble top,
         GLdouble near, GLdouble far );

Perspektivische Wahrnehmung

Die perspektivische Projektion ist die "natürliche Darstellung" und die am meisten verwendete Projektionsart. Die Sehstrahlen treffen sich in einem Fluchtpunkt (vanishing point). Je weiter hinten ein Objekt liegt, desto kleiner erscheint es (perspektivische Verkleinerung). Das Rendervolumen ist ein Pyramidenstumpf (Frustum).

Zentrale Begriffe der Zentralperspektive (central perspective): der Fluchtpunkt am Horizont, in dem sich parallele Fluchtlinien (die Sehstrahlen) scheinbar treffen, sowie der Betrachter-Standort. Wird die Regel "je weiter hinten, desto kleiner" gebrochen, entsteht eine fehlerhafte Größeninformation (optische Täuschung).

Perspektivische Projektion: Lochkamera und Strahlensatz

Das physikalische Modell hinter der perspektivischen Projektion ist die Lochkamera (pinhole camera): eine Schachtel mit einem Loch. Für ein "punktgroßes" Loch entsteht ein perfektes, scharfes Bild. Die Lichtstrahlen des Objekts kreuzen sich im Loch und erzeugen ein umgekehrtes (auf dem Kopf stehendes, seitenverkehrtes) Bild auf der gegenüberliegenden Innenwand (der Bildebene).

Im mathematischen Modell wird die Bildebene (image plane) vor die Kamera gelegt (Abstand nn = near), so dass das projizierte Bild nicht umgedreht ist.

Herleitung über den Strahlensatz

Grundlage der perspektivischen Projektion ist der Strahlensatz (intercept theorem / similar triangles). Aus ähnlichen Dreiecken folgt die Beziehung zwischen der projizierten Koordinate pyp'_y (auf der Bildebene im Abstand nn) und der tatsächlichen y-Koordinate pyp_y in Tiefe pzp_z:

pyn=pypzpy=npypz\frac{p'_y}{n} = \frac{p_y}{p_z} \quad\Longrightarrow\quad p'_y = \frac{n \, p_y}{p_z}

Dabei ist nn der Abstand der Bildebene (near) zur Kamera, pyp_y die y-Koordinate des Punktes, pzp_z die Tiefe (z-Abstand) und pyp'_y die projizierte y-Koordinate. Analog gilt für xx: px=npx/pzp'_x = n\,p_x / p_z.

Die Division durch pzp_z erzeugt die perspektivische Verkleinerung: Bei fester Höhe pyp_y wird die Projektion umso kleiner, je größer die Tiefe pzp_z ist.

View-Frustum und Clipping-Ebenen

Das View-Frustum (view frustum) ist der pyramidenstumpfförmige Sichtbereich zwischen der near-plane (Nah-Clipping-Ebene) und der far-plane (Fern-Clipping-Ebene). Nur Geometrie innerhalb des Frustums wird gerendert. Erst die Clipping-Ebenen ermöglichen es, die Projektion als Matrixmultiplikation zu realisieren.

  • near und far sind Abstände in Bezug auf die Kamera.
  • Der Öffnungswinkel ergibt sich aus dem Abstand der near-Plane zur Kamera.
  • top, bottom, left, right sind die Abstände zum Mittelpunkt auf der nahen Ebene.

Frustum-Definition

Zwei Wege, ein Frustum zu definieren:

// Auch asymmetrisches Frustum moeglich
glm::frustum(float left, float right, float top, float bottom,
             float near, float far);

// Nur symmetrisches Frustum
glm::perspective(float theta, float aspect, float near, float far);
  • glm::frustum definiert ein (auch asymmetrisches) Frustum über left, right, top, bottom, near, far.
  • glm::perspective ist die Alternative über theta (vertikaler Öffnungswinkel / field of view), aspect (Seitenverhältnis Höhe : Breite), near, far. Einschränkung: nur symmetrisches Frustum.

Perspektivische Projektionsmatrix

Nicht klausurrelevant! Die folgende perspektivische Projektionsmatrix ist in den Folien ausdrücklich (oben rechts) als "Nicht klausurrelevant!" markiert. Sie ist hier nur zur Vollständigkeit dokumentiert. Konzeptionell relevant ist hingegen die Wirkung der Projektion (nichtlineare z-Skalierung, x/y perspektivisch skaliert, mehr Präzision für nahe Objekte).

Die Matrix, angewendet auf einen homogenen Punkt:

(pxpypzw)=(1000010000n+fnf001n0)(pxpypz1)\begin{pmatrix} p'_x \\ p'_y \\ p'_z \\ w \end{pmatrix} = \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & \frac{n+f}{n} & -f \\ 0 & 0 & \frac{1}{n} & 0 \end{pmatrix} \begin{pmatrix} p_x \\ p_y \\ p_z \\ 1 \end{pmatrix}

Ergebnis vor der perspektivischen Division:

(pxpypzw)=(pxpypzn+fnfpz/n)\begin{pmatrix} p'_x \\ p'_y \\ p'_z \\ w \end{pmatrix} = \begin{pmatrix} p_x \\ p_y \\ p_z \cdot \frac{n+f}{n} - f \\ p_z / n \end{pmatrix}

Nach der perspektivischen Division (durch w=pz/nw = p_z / n):

(npx/pznpy/pzn+fnf/pz1)\begin{pmatrix} n\,p_x / p_z \\ n\,p_y / p_z \\ n + f - n f / p_z \\ 1 \end{pmatrix}

Man beachte: xx und yy ergeben die aus dem Strahlensatz bekannte Form np/pzn\,p / p_z; die zz-Komponente ist nichtlinear in pzp_z (mehr Präzision für nahe Objekte).

Perspektivische Division und Tiefenpräzision

Die perspektivische Division / Homogenisierung (perspective division) teilt die homogenen Koordinaten durch die ww-Komponente (hier w=pz/nw = p_z / n). Erst dadurch entsteht die eigentliche perspektivische Verkleinerung. Der Vertex-Shader gibt die Position vor dieser Division aus.

Nichtlineare Tiefenskalierung (nonlinear depth scaling): Punkte auf der Nahbereichsebene bleiben unverändert; x,yx, y werden perspektivisch skaliert; zz wird nichtlinear skaliert. Folge: mehr Tiefenpräzision für nahe Objekte. Eine sehr ferne far-Ebene bei sehr naher near-Ebene führt zu Präzisionsverlust in der Ferne (Motivation für z-fighting bzw. eine sinnvolle near/far-Wahl).

Negation der z-Koordinate (Rechts- zu Linkshänder)

Der NDC ist linkshändig (positive z-Werte als Entfernung), während im Camera Space die Kamera entlang Z-Z schaut (rechtshändig). Die Matrix MRLM_{R \to L} multipliziert die z-Werte mit 1-1, um zwischen den Systemen zu wechseln. Diese Invertierung ist in den gl-Methoden bereits integriert.

(pxpypz1)=(1000010000100001)MRL(pxpypz1)\begin{pmatrix} p'_x \\ p'_y \\ p'_z \\ 1 \end{pmatrix} = \underbrace{ \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}}_{M_{R \to L}} \begin{pmatrix} p_x \\ p_y \\ p_z \\ 1 \end{pmatrix}

Die komplette Transformationskette

Die Projection Transformation MprojM_{proj} (projection transformation) bildet das Kamera-Frustum auf den Würfel ab; sie ist entweder MorthoM_{ortho} oder MpersM_{pers}. Die vollständige Vertex-Transformationskette (inklusive z-Negation):

p=MOrthoMPerspMRLMortho oder MpersVTTSRMModelp\mathbf{p}' = \underbrace{M_{Ortho} \cdot M_{Persp} \cdot M_{R \to L}}_{M_{ortho}\ \text{oder}\ M_{pers}} \cdot V \cdot \underbrace{T \cdot \ldots \cdot T \cdot S \cdot R}_{M_{Model}} \cdot \mathbf{p}

Als Zwischenstufe (ohne explizites MRLM_{R \to L}) wird sie oft kompakt geschrieben:

p=MprojVMModelp(Mproj=Mortho oder Mpers)\mathbf{p}' = M_{proj} \cdot V \cdot M_{Model} \cdot \mathbf{p} \qquad (M_{proj} = M_{ortho}\ \text{oder}\ M_{pers})

Die drei Raumstufen der Pipeline: Camera View (finales gerendertes Bild), Camera Space (Objekte im Frustum) und Normalized Device Space (Objekte im NDC-Würfel, durch die Projektion "gestreckt").

Umsetzung im Vertex-Shader

Die gesamte Kette wird in nur einer Zeile GLSL umgesetzt:

#version 330
layout(location = 0) in vec3 vertex;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(vertex, 1.0);
}

Der Output ist die Vertex-Position in homogenen Koordinaten, vor der perspektivischen Division (Homogenisierung, die nach dem Vertex-Shader erfolgt). Reihenfolge: projection wird zuerst angeschrieben, wirkt aber zuletzt (Matrizen wirken von rechts nach links auf den Vertex).

Worked Examples

Beispiel 1: Perspektivische Projektion eines Punktes (Strahlensatz)

Gegeben ein Punkt pp mit Höhe pyp_y in Tiefe pzp_z und eine Bildebene im Abstand nn vor der Kamera. Gesucht: die projizierte Höhe pyp'_y.

Über ähnliche Dreiecke (Strahlensatz):

pyn=pypzpy=npypz\frac{p'_y}{n} = \frac{p_y}{p_z} \quad\Longrightarrow\quad p'_y = \frac{n \, p_y}{p_z}

Interpretation: Bei fester Höhe pyp_y wird die Projektion umso kleiner, je größer die Tiefe pzp_z ist (perspektivische Verkleinerung). Analog für xx.

Beispiel 2: Perspektivische Projektionsmatrix angewendet (nicht klausurrelevant)

Die Anwendung der 4x4-Matrix auf (px,py,pz,1)T(p_x, p_y, p_z, 1)^T liefert vor der Division (px, py, pzn+fnf, pz/n)T(p_x,\ p_y,\ p_z\frac{n+f}{n} - f,\ p_z/n)^T. Nach der perspektivischen Division durch w=pz/nw = p_z/n erhält man (npx/pz, npy/pz, n+fnf/pz, 1)T(n\,p_x/p_z,\ n\,p_y/p_z,\ n+f - nf/p_z,\ 1)^T. Die x,yx, y-Komponenten reproduzieren den Strahlensatz; die zz-Komponente n+fnf/pzn+f-nf/p_z ist nichtlinear in pzp_z (mehr Präzision nahe der Kamera).

Beispiel 3: Vertex-Shader (GLSL)

Nur 4 wesentliche Zeilen: die drei Uniforms model, view, projection plus die eine Zuweisung gl_Position = projection * view * model * vec4(vertex, 1.0). Output ist die Vertex-Position in homogenen Koordinaten, vor der perspektivischen Division. Reihenfolge: projection steht links (wirkt zuletzt), model steht rechts (wirkt zuerst).

Prüfungsrelevanz

  • Grundidee: "Szene bewegen statt Kamera" - relative Bewegung, gleiches Ergebnis, effizienter.
  • Die drei extrinsischen lookAt-Parameter: Kamerazentrum cc, Betrachtungspunkt aa, up-Vektor uu. Die Zuordnung der 9 lookAt-Skalare kennen.
  • Aufbau der View-Matrix als Rotation (Kamera-Achsen als Zeilen, in Weltkoordinaten) \cdot Translation(c)(-c).
  • Strahlensatz-Herleitung: py=npy/pzp'_y = n\,p_y / p_z (aus ähnlichen Dreiecken).
  • Unterschied orthografisch vs. perspektivisch (parallele Strahlen / Quader vs. Fluchtpunkt / Frustum).
  • View-Frustum mit near/far/left/right/top/bottom; glm::frustum vs. glm::perspective.
  • Die komplette Transformationskette p=MprojVMModelp\mathbf{p}' = M_{proj} \cdot V \cdot M_{Model} \cdot \mathbf{p} und die eine Shader-Zeile.
  • Konzeptionell relevant (auch ohne die Matrix selbst): die Wirkung der perspektivischen Projektion (nichtlineare z-Skalierung, x/y perspektivisch skaliert, mehr Präzision für nahe Objekte).

Ausdrücklich NICHT klausurrelevant: die perspektivische Projektionsmatrix (Seite 30, in den Folien oben rechts markiert). Nur die Matrix selbst ist ausgenommen, nicht ihre konzeptionelle Wirkung.

Typische Fehler

  • Matrix-Reihenfolge: p=MprojVMModelp\mathbf{p}' = M_{proj} \cdot V \cdot M_{Model} \cdot \mathbf{p} wirkt von rechts nach links. Im Shader projection * view * model * vertex: model wirkt zuerst, projection zuletzt. Reihenfolge nicht vertauschen.
  • Blickrichtung: Im Camera/View Space blickt die Kamera entlang der NEGATIVEN Z-Achse (rechtshändig). Der NDC ist linkshändig (positive z = Entfernung). Deshalb die Negation MRLM_{R \to L} (z1z \cdot -1), in den gl-Methoden bereits integriert.
  • Seitenverhältnis: Kamera-Aspect und Fenster-Aspect müssen gleich sein, sonst Verzerrung. Bei glOrtho auch die Fensterauflösung anpassen.
  • up-Vektor: uu legt die Rotation um die Blickachse fest; ohne korrekten up-Vektor ist die Ausrichtung unterbestimmt.
  • glm::perspective-Einschränkung: erzeugt nur symmetrische Frusta; asymmetrische Frusta erfordern glm::frustum.
  • Parameter-Reihenfolge glm::frustum: left, right, TOP, BOTTOM, near, far (top vor bottom - abweichend von glOrtho, das bottom vor top hat).
  • Tiefenpräzision: sehr nahe near-Ebene bei sehr ferner far-Ebene führt zu Präzisionsverlust hinten (z-fighting).
  • Perspektivische Division nicht vergessen: Shader-Output ist homogen (vor Division durch ww); die eigentliche Verkleinerung entsteht erst durch die Homogenisierung nach dem Vertex-Shader.

Glossar

DeutschEnglish
Normalisierter Geräteraum (NDC)normalized device space
Normalisierte Gerätekoordinatennormalized device coordinates
Blendenproblemaperture problem
äußere / extrinsische Kameraparameterextrinsic camera parameters
innere / intrinsische Kameraparameterintrinsic camera parameters
Kamerazentrum (c)camera center
Betrachtungspunkt (a)look-at point / target
up-Vektor (u)up vector
Sichttransformation / View-Matrix (V)view transformation / view matrix
lookAt-FunktionlookAt function
Sichtraum / Kameraraumview space / camera space
Modelltransformation (M_Model)model transformation
Projektionstransformation (M_proj)projection transformation
orthografische / Parallelprojektionorthographic / parallel projection
perspektivische Projektionperspective projection
Fluchtpunktvanishing point
Zentralperspektivecentral perspective
Fluchtlinienvanishing lines
Horizonthorizon
Lochkamerapinhole camera
Bildebeneimage plane
Strahlensatzintercept theorem / similar triangles
Sichtpyramidenstumpf / Sichtvolumenview frustum
Nah- / Fern-Clipping-Ebenenear / far clipping plane
Öffnungswinkel (theta)opening angle / field of view
Seitenverhältnisaspect ratio
perspektivische Division / Homogenisierungperspective division / homogenization
nichtlineare z-Skalierungnonlinear depth scaling
Negation der z-Koordinate (M_R->L)z-negation, right- to left-handed conversion
homogene Koordinatenhomogeneous coordinates
Vertex-Shadervertex shader