Z-Buffer
# Z-Buffer

Das Z-Buffering (auch Depth Buffering, Tiefenpuffer- oder Tiefenspeicher-Verfahren) ist ein Verfahren der Computergrafik zur Verdeckungsberechnung, also um die vom Betrachter aus sichtbaren dreidimensionalen Flächen in einer Computergrafik zu ermitteln. Durch Tiefeninformationen in einem sogenannten Z-Buffer („Z-Puffer“) stellt das Verfahren pixelweise fest, welche Elemente einer Szene gezeichnet werden müssen und welche verdeckt sind. Praktisch alle heutigen Grafikkarten implementieren Z-Buffering direkt in Hardware. Als Entwickler des Z-Buffer-Verfahrens gilt Edwin Catmull; allerdings beschrieb Wolfgang Straßer das Prinzip etwa zur gleichen Zeit in einem anderen Kontext. Die wichtigste Alternative zum Z-Buffering ist der Raytracing-Algorithmus.

## Funktionsweise

Das Prinzip des Z-Buffering ist sehr einfach. Neben dem sichtbaren Teil des Bildspeichers, der die aktuellen Farbwerte enthält, gibt es einen weiteren Speicher, den Z-Buffer, der die Tiefe des sichtbaren Objekts an jedem Pixel enthält. Alternativ können die Pixelwerte im Framebuffer um einen $z$-Wert erweitert werden. Zu Beginn werden die Einträge im Z-Buffer auf einen Wert gesetzt, der für eine unendliche Entfernung steht (Backplane Distance). Der Framebuffer wird mit der Hintergrundfarbe initialisiert. Jedes Polygon wird nun gerastert. Nur wenn der aktuell gerasterte Punkt des Polygons näher am Betrachter liegt als der Punkt, dessen Entfernung im Z-Buffer eingetragen ist, werden die Werte im Z-Buffer und im Framebuffer durch die Entfernung beziehungsweise die Farbe des aktuellen Polygons ersetzt.

    Prinzip des Z-Buffers am Beispiel zweier sich schneidender Polygone

Die Reihenfolge, in der die Polygone gerastert werden, ist im Prinzip beliebig. Nicht nur Polygone, sondern beliebige weitere grafische Primitive können mit Hilfe des Z-Buffers gerendert werden.

Die Speichergröße der Werte im Z-Buffer hat einen großen Einfluss auf die Qualität des gerenderten Bildes. Wenn zwei Objekte sehr eng beieinander liegen, können bei einem Z-Buffer mit 8 Bit pro Pixel leicht Artefakte entstehen. 16, 24 oder 32 Bit tiefe Z-Buffer erzeugen weniger Artefakte.

Auf aktuellen Grafikkarten beansprucht der Z-Buffer einen bedeutenden Teil des verfügbaren Speichers und der Datenübertragungsrate. Mit verschiedenen Methoden wird versucht, den Einfluss des Z-Buffers auf die Leistung der Grafikkarte zu reduzieren. Dies ist zum Beispiel durch die verlustfreie Kompression der Daten möglich, da das Komprimieren und Dekomprimieren der Daten kostengünstiger ist als die Erhöhung der Datenübertragungsrate einer Karte. Ein anderes Verfahren spart Löschvorgänge im Z-Buffer: die Tiefeninformation wird mit alternierendem Vorzeichen in den Z-Buffer geschrieben. Ein Bild wird mit positiven Vorzeichen gespeichert, das nächste Bild mit negativem, erst dann muss gelöscht werden. Eine weitere Möglichkeit zur Optimierung ist die Vorsortierung der Primitiven: Werden zunächst die näherliegenden Primitiven gerendert, kann bei den weiter entfernten später direkt entschieden werden, ob bzw. welche Pixel gerendert werden müssen und welche von Vordergrundobjekten verdeckt werden, wodurch Texturierungs- und Pixel-Shader-Vorgänge eingespart werden können.

## Algorithmus

### Pseudocode

Der Z-Buffer-Algorithmus löst das Sichtbarkeitsproblem, indem für jeden Pixel die Position des dargestellten Objektes und die Farbinformation gespeichert wird. Weil als Blickrichtung normalerweise die z-Richtung verwendet wird, entsprechen die x-Werte und y-Werte dieser Position denen der Abbildungsebene und es braucht nur der z-Wert gespeichert zu werden. Man braucht also zusätzlich zum Bildpuffer einen weiteren Speicherbereich, der für jedes Pixel einen Koordinatenwert (z-Wert) aufnehmen kann. Nun kann man alle Objekte in beliebiger Reihenfolge zeichnen. Die z-Werte des nächsten zu zeichnenden Objektes werden berechnet und mit den z-Werten der Pixel verglichen, in die das Objekt gezeichnet werden soll. Wenn der neue z-Wert näher zum Betrachter, also größer ist, dann wird das Objekt an dieser Stelle neu gezeichnet und der z-Wert im z-Puffer ebenfalls ersetzt. Andernfalls ist das neue Objekt verdeckt und an dieser Stelle wird nicht gezeichnet.

Der folgende Pseudocode zeigt die Struktur des Z-Buffer-Algorithmus:

## Codierung der Tiefeninformationen

Der Bereich der Tiefeninformation im Kameraraum, der zu rendern ist, wird häufig durch den nah-Wert und fern-Wert von $z$ definiert. Nach einer Perspektivtransformation wird der neue Wert von $z$, hier als $z'$ bezeichnet, wie folgt berechnet:

    $z'={\frac {{\mbox{fern}}+{\mbox{nah}}}{{\mbox{fern}}-{\mbox{nah}}}}+{\frac {1}{z}}\left({\frac {-2\cdot {\mbox{fern}}\cdot {\mbox{nah}}}{{\mbox{fern}}-{\mbox{nah}}}}\right)$

Dabei ist $z'$ der neue Wert von $z$ im Kameraraum. Manchmal werden auch die Abkürzungen $w$ und $w'$ verwendet.

Die resultierenden Werte von $z'$ werden auf Werte zwischen −1 und 1 normiert, wobei die Fläche bei nah den Wert −1 und die Fläche bei fern den Wert 1 erhält. Werte außerhalb dieses Bereichs stammen von Punkten, die sich nicht im Sichtbereich befinden, und sollten nicht gerendert werden.

Bei der Implementierung eines Z-Buffers werden die Werte der Scheitelpunkte eines Polygons linear interpoliert und die $z'$-Werte einschließlich der Zwischenwerte im Z-Buffer gespeichert. Die Werte von $z'$ sind wesentlich enger an der Nah-Fläche verteilt und wesentlich mehr zur Fern-Fläche hin verstreut, was zu einer höheren Genauigkeit der Darstellung nahe dem Kamerastandpunkt führt. Je enger die Nah-Fläche an die Kamera gesetzt wird, desto geringer ist die Präzision im Fernbereich. Eine häufige Ursache für unerwünschte Artefakte bei entfernten Objekten ist, dass die Nah-Fläche zu eng an die Kamera gesetzt wurde. Diese als Z-Fighting (Z-Konflikt, Tiefenkonflikt) bezeichneten Artefakte treten insbesondere dann auf, wenn zwei koplanare Flächen sehr nahe beieinander sind, beispielsweise eine Wand und ein darauf angebrachtes Plakat. Welches von beiden Polygonen dann im Vordergrund liegt, ist im Wesentlichen zufällig und kann sich auch durch geringfügige Änderungen des Kamerastandortes ändern. Zur Abhilfe müssen vom Programmierer explizit Maßnahmen ergriffen werden, etwa indem die Z-Werte des Plakates künstlich verändert werden oder durch den Einsatz eines sogenannten Stencilbuffers.

Da die Abstandswerte nicht gleichmäßig im Z-Buffer abgelegt werden, werden nahe Objekte besser dargestellt als ferne, da ihre Werte genauer abgespeichert sind. Allgemein ist dieser Effekt erwünscht, er kann aber auch zu offensichtlichen Artefakten führen, wenn sich Objekte voneinander entfernen. Eine Variation des Z-Bufferings mit ausgeglicheneren Entfernungswerten ist das sogenannte W-Buffering. Um einen W-Buffer zu implementieren, werden die unveränderten Werte von $z$ bzw. $w$ in den Buffer gespeichert, im Allgemeinen als Gleitkommazahlen. Diese Werte können nicht linear interpoliert werden, sondern müssen invertiert, interpoliert und wieder invertiert werden. Die resultierenden $w$-Werte sind, im Gegensatz zu $z$, gleichmäßig zwischen nah und fern verteilt. Ob ein Z-Buffer oder ein W-Buffer zu besseren Bildern führt, hängt vom jeweiligen Anwendungszweck ab.

## Vor- und Nachteile

* Vorteile
   * einfache Implementierung (sowohl in Software als auch direkt in Hardware)
   * keine Vorsortierung der Eingabe nötig
   * sehr schnell
   * einfache Parallelisierung möglich (z. B. Unterteilung in kleinere Quadranten)
   * kein wahlfreier Zugriff auf die Szene nötig
* Nachteile
   * jedes Polygon der Eingabe wird gerendert
   * die Laufzeit wächst linear mit der Eingabegröße
   * es werden keine Zusammenhänge der Objekte ausgenutzt

## Randomisierter Algorithmus

Ein neuer, randomisierter Z-Buffer-Algorithmus erzeugt ein gerendertes Bild einer beliebigen dreidimensionalen Szene, die aus dreieckigen Figuren besteht. Dieser Ansatz ist unabhängig von der Topologie der Figuren. Die resultierende Laufzeit des Algorithmus wächst nur logarithmisch mit der Anzahl der Dreiecke in der Szene. Die automatische Identifizierung weniger detaillierter Komponenten stellt sicher, dass die Geschwindigkeit des randomisierten Algorithmus nicht unter den herkömmlichen Z-Buffer-Algorithmus fallen kann. Es gibt experimentelle und analytische Beweise dafür, dass die Bildqualität mit dem des herkömmlichen Algorithmus vergleichbar ist. Die vorübergehenden Datenstrukturen des randomisierten Z-Buffers ermöglichen interaktive dynamische Aktualisierungen der Szene. Ihre Speicheranforderungen wachsen nur linear mit der Anzahl der Dreiecke und ermöglichen ein Instantiierungsschema, um den Speicherverbrauch weiter zu reduzieren.

Der Algorithmus verwendet beliebige Modelle, die aus Dreiecken bestehen, als Eingabe. Die Wiedergabezeit für eine Szene, die aus $n$ Dreiecken besteht, die einen auf dem Bildschirm projizierten Bereich von $a$ Pixeln abdecken, liegt in $O(a\cdot \log(n))$. Das logarithmische Wachstum der Laufzeit erlaubt das Rendern hochkomplexer Szenen. Eine Caching-Strategie für Samplesets wird verwendet, um die Grafikhardware optimal zu nutzen. Der Algorithmus verwendet $O(n)$ Speicher und benötigt $O(n\cdot \log(n))$ Vorberechnungszeit. Das Einfügen und Entfernen eines Objekts kann in der Laufzeit $O(t)$ durchgeführt werden, wobei $t$ die Höhe eines Octrees ist, der für die Objekte in der Szene erstellt wurde. Dies ermöglicht interaktive Aktualisierungszeiten für lokale Modifikationen der Szene.

