Tutorial OpenGL3 Scissor Clipping DepthTest

Aus DGL Wiki
Wechseln zu: Navigation, Suche

Clipping, Scissor und Tiefen-Test

Clipping, Scissor und Tiefen-Test sind Optimierungsprozesse welche dafür sorgen, dass der Datenpool minimiert wird. Dabei ist die Clipping Funktion dafür zuständig Vertice und damit verbundene Daten aus der Renderpipeline zu werfen. Die Scissor Funktion soll den Shading-Prozess beschleunigen, also das errechnen der Pixelfarben für ein Dreieck reduzieren. Der Tiefen-Test hat die gleiche Aufgabe wie der Scissor-Test aber reduziert die Datenmenge auf Basis anderer Informationen und soll zugleich das korrekte Zeichnen von sich überschneidender Geometry ermöglichen.

Clipping

Der Clipping-Prozess wird nach dem errechnen der Vertexpositionen auf dem Monitor durch geführt. Diese erhält man durch das Multiplizieren der Projektionsmatrix mit der Modelviewmatrix und dem anschliessenden multiplizieren mit der Vertexposition. Die neue Vertexposition hat zwar noch 4 Komponenten aber beim Clipping werden nur X und Y betrachtet. Man muss in allen OpenGL Versionen den Viewport einstellen, indem man glViewport verwendet. Als Parameter übergibt man X,Y,Width und Height, welche zusammen ein Rechteck ergeben. Dieses Rechteck ist nun der gültige Sichtebereich und alles ausserhalb von diesen ist nicht sichtbar und wird damit nicht in der Renderpipeline benötigt. Wenn nun also ein Dreieck nicht das Rechteck schneidet, dann wird es aus der Renderpipeline entfernt. Dies reduziert die zu behandelnden Dreiecke in den Anschliessenden Prozessschritten und spart Zeit ein.

Scissor

Der Scissor-Prozess wird vor dem Fragmentshader durch geführt, dieser Schritt muss nicht durchgeführt werden. Der Scissor-Test kann über glEnable#GL_SCISSOR_TEST aktiviert werden und mit Hilfe von glScissor konfiguriert werden. Genau wie beim Clipping wird die X und Y Koordinate des Bildschirmpixels als Eingabe genommen aber im gegensatz zum Clipping-Test wird im Scissor-Test nur ein X/Y Wertepaar benötigt und nicht 3. Der Test ist daher recht einfach und kann bei komplexeren Shadern immense Summen an Zeit heraus holen. Folgender Code zeigt ein einfachen InBound check.

bool InBoundCheck(const int X, const int Y, const int RectX, const int RectY, const unsigned int RectWidth, const unsigned int RectHeight)
{
  if ((X<=RectX+RectWidth) && (X>=RectX))
    if ((Y<=RectY+RectHeight) && (Y>=RectY))
      return true;
  return false;
}

Alle Pixel, die den Test bestehen, werden dann an den Fragmentshader weiter gereicht und der rest wird einfach verworfen. Wenn ein Shader sehr komplex ist und z.B. mehrere Texelzugriffe macht, AntiAliasing aktiviert ist und/oder komplexe Berechnungen im Fragmentshader getan werden, dann kann durch das Verwerfen von Pixeln viel Zeit eingespart werden.

Tiefen-Test

Der Tiefen-Test wird nach dem Scissor-Test ausgeführt und soll die Anzahl der zu verarbeitenden Pixel reduzieren und Dreiecksüberschneidungen korrekt darstellen. Wenn man in einen Artikel, Blog oder Forum von Overdraw redet, dann hat dies mit dem Tiefen-Test zu tun. Overdraw ist der Zustand, wenn ein Bildschirmpixel mehrfach gezeichnet wird, also mehrere Dreiecke die gleiche X-,Y-Koordinate auf dem Bildschirm haben. Der Tiefen-Test betrachtet die Z-Koordinate von dem Bildschirmpixel und schaut in einen Tiefenpuffer nach, ob das Fragment(aktueller Pixel vom Dreieck) sichtbar wäre. Jedes Fragment, welches durch ein Dreieck in der Pipeline verarbeitet wird, besitzt einen Tiefenwert Z und dieser wird in dem Tiefenpuffer Hinterlegt. Wenn man mit glEnable#GL_DEPTH_TEST den Tiefen-Test aktiviert, dann wird jedes Fragment mit einer definierten Funktion verarbeitet. Diese Funktion kann über glDepthFunc fest gelegt werden. Wenn die Funktion erfolgreich ist und true zurück gibt, dann wird der Z Wert in den Tiefenpuffer eingetragen und wird anschliessend vom Fragmentshader verarbeitet. Sollte der Test negativ ausfallen, dann wird der Tiefenwert nicht geschrieben und das Fragment verworfen. Es ist sinnvoll, die Tiefen-Test Funktion nur auf kleinere oder gleiche Z Werte, als im Tiefenpuffer, fest zu legen. Wenn man nun seine Dreiecke von vorne nach hinten sortiert und rendert, dann werden nur die vordersten Fragmente, der Dreiecke gezeichnet. Sollten man die Dreiecke von hinten nach vorne zeichnen, dann wird jedes Fragment in der Szene durch den Fragmentshader geschliffen und die Framerate bricht stark ein.

Info DGL.png Nvidia und ATI empfehlen das Rendern in 2 Schritten zu vollziehen. Im ersten Schritt wird mit Hilfe von glColorMask alle Kanälle ab geschalten, mit glDepthMask der Tiefenpuffer schreibar gemacht, der Tiefen-Test aktiviert, der Tiefen- und Farbpuffer geleert, die Texturen deaktivert(glDisable#GL_TEXTURE_2D) und die nicht Transparente Geometry gezeichnet. Dieser Schritt ist zum erfassen der Z-Koordinaten. Anschliessend aktiviert man wieder alle Farbkanälle, deaktiviert das schreiben im Tiefenpuffer, Texturen und zeichnet nun ganz normal seine nicht Transparente Geometry und dann die Transparente. Dieses 2 Schritt verfahren ist um ein vielfaches schneller und wird umso schneller, je komplexer Geometry und Shader werden.