Occlusion Query
Inhaltsverzeichnis
Was sind ein Occlusion Queries?
Hinter dem Begriff "Occlusion Query" (zu deutsch etwa "Sichbarkeits Abfrage") versteht man eine Technik, mit deren Hilfe sich die Anzahl der Pixel, die den Z-Buffer Test bestehen, auslesen lässt.
Mögliche Anwendungsgebiete
Mögliche Anwendungen für diese Technik sind:
Sichtbarkeitserkennung für Objekte
Eine niedrig aufgelöste (tesselierte) Variante der Szene (zum Beispiel jeweils nur die Bounding Boxen) wird in ein kleines, nicht sichtbares VBO gerendert. Sind dort Pixel eines Objektes sichtbar, so kann auch das hochauflösende Objekt gerendert werden. Somit wird Leistung eingespart.
Lensflare Effekte
Die Intensität eines Lensflare-Effektes sollte abnehmen, je mehr von der Lichtquelle verdeckt ist. Über Occlusion Culling lässt herausfinden, wie viele Pixel der Lichtquelle überhaupt sichtbar sind. Somit kann der Effekt abgeschwächt werden.
Kollisionskontrolle
In Kombination mit dem Stencilbuffer und Occlusion Queries kann man herausfinden, ob zwei Objekte miteinander Kollidieren. Vor allem in 2D-Spielen findet diese Technik Verwendung. Dazu wird das erste Objekt gezeichnet und der Stencilwert bei geglücktem Z-Buffer Test von null auf eins erhöht. Als nächstes Zeichnet man das zweite Objekt. Jedoch werden über den Stencilbuffer nur dort Pixel gesetzt, wo der Stencilwert eins beträgt. Wird bei diesem Vorgang mehr als ein Pixel gezeichnet, so kollidieren die beiden Objekte.
Wie funktionieren Occlusion Queries?
Eine Occlusion Query kann man sich wie eine Art Stoppuhr vorstellen: Man Schaltet die Stoppuhr ein, drückt auf Start, zeichnet etwas, drückt auf Stopp und ließt die Anzahl der Pixel, die den Z-Buffertest bestanden haben, ab. Schließlich, wenn die Stoppuhr nicht mehr benötigt wird schaltet man sie wieder ab. Seit OpenGL-Version 1.5 gehören Occlusion Queries zur Standard OpenGL Definition. Das bedeutet, dass dafür keine Extensions benötigt werden.
Beispielhafte Benutzung in OpenGL
var QueryID: Cardinal; QueryState: Cardinal; PixelCount: Cardinal; //1. Ein OpenGL-Queryobjekt erstellen glGenQueries(1, @QueryID); //2. Die Abfrage starten glBeginQuery(GL_SAMPLES_PASSED, @QueryID); //3. Irgendetwas zeichnen //4. Die Abfrage anhalten glEndQuery(GL_SAMPLES_PASSED); //5. Die Pixelanzahl abhohlen //Warten bis die Pixelanzahl über die (Hardware-)Grafikschnittstelle bis zu unserem Programm vorgedrungen ist repeat glGetQueryObjectuiv(OGLQuery, GL_QUERY_RESULT_AVAILABLE, @QueryState) until Querystate = GL_TRUE; //Das Ergebnis aufschreiben glGetQueryObjectuiv(QueryID, GL_QUERY_RESULT, @PixelCount); //6. Das Queryobjekt freigeben, wenn es nicht mehr benötigt wird glDeleteQueries(1, @QueryID);
Wichtige Besonderheiten
Interessant ist Schritt Nummer 5: Die Pixelanzahl liegt unserem Anwendungsprogramm nicht direkt vor, sie muss sich erst ihren Weg von der GPU zur CPU bahnen. Darauf müssen wir warten. In diesem Schritt kann also recht viel Zeit vergehen. Daher sind einige Optimierungsmaßnahmen sinnvoll:
Zwischen dem Anhalten der Abfrage und dem Abholen des Ergebnisses können weiterhin Objekte gezeichnet werden und weiter Occlusion Queries stattfinden. Möchte man also für eine Reihe von Objekten eine Sichtbarkeitskontrolle durchführen, so liegt es nahe für jedes Objekt ein OpenGL-Query-Objekt zu erzeugen und alle Sichbarkeitstests vor dem abholen des Ergebnisses durchzuführen. Schließlich können in der Zeit des Test, die Ergebnisse schon unsere Anwendung (bzw. OpenGL) erreichen. Dann müssen wir nicht mehr darauf warten.
Außerdem ist es wichtig, sich klar zu machen, dass die Occlusion Queries nicht die gezeichneten Pixel, sondern die Pixel, die den Z-Buffer Test bestehen zählen. Ist der Z-Buffer abgeschaltet gibt es keinen Z-Buffer Test, der dann logischerweise auch nicht bestanden werden kann. Daraus folgt: Es werden keine Pixel gezählt, obwohl wir vielleicht unsere Szene sehen.
Siehe auch
glBeginQuery, glDeleteQueries, glEndQuery, glGetQuery, glGetQueryObject, glIsQuery, Tutorial NVOcclusionQuery
Links
http://www.gamedev.net/reference/programming/features/occlusionculling/ (Auch wenn es DirectX ist, das Konzept ist das selbe) http://kometbomb.net/2007/07/11/hardware-accelerated-2d-collision-detection-in-opengl/