[OpenGL] Der Stencilbuffer - eine Schablone fürs Zeichnen
Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials
LobbyBetreff: [OpenGL] Der Stencilbuffer - eine Schablone fürs Zeichnen |
Sa, März 30, 2013 17:21 Antworten mit Zitat |
|
---|---|---|
In diesem Tutorial wird es darum gehen wie man den sogenannten Stencilbuffer in OpenGL verwendet. Mit Hilfe dieses Buffers lässt sich pixelgenau bestimmen, wo andere Zeichenbefehle zeichnen dürfen. Es werden keinerlei OpenGL-Kenntnisse vorausgesetzt. Man könnte damit beispielsweise so etwas realisieren:
Es handelt sich hierbei um die runde Minimap eines Weltraumspiels, dabei ist zu sehen, dass die Asteroiden die sich am Rand der Minimap befinden nur innerhalb dieser gezeichnet werden. Was ist der Stencilbuffer? Der Stencilbuffer selbst ist wie ein Bildbuffer der für jeden Pixel des Grafikbereichs mindestens 8 Bit, also ein Byte, an Speicher zur Verfügung stellt. Jeder Pixel des Stencilbuffers kann beliebig mit einem Wert, der in eben dieses Byte passt, beschrieben werden. Abhängig von den im Stencilbuffer gespeicherten Werten kann man nun festlegen, welche Pixel durch Zeichnenoperationen (wie zum Beispiel DrawRect, DrawLine, DrawImage und DrawText) in ihrer Farbe beeinflusst werden können. Will man, dass nur innerhalb eines ungedrehten, rechteckigen Bereiches gezeichnert werden kann, so kann man das max2d eigene SetViewport(x, y, w, h) verwenden. Für beliebige Formen aber eignet sich der hier vorgestellte Stencilbuffer. Eine kleine Hilfsklasse für den Stencilbuffer in OpenGL Da reines OpenGL nicht immer gut lesbar oder nachvollziehbar ist, habe ich die wichtigsten Funktionen für den Stencilbuffer in einer eigenen Klasse TGLStencil gekapselt. BlitzMax: [AUSKLAPPEN] Rem Diese Klasse stellt folgende Methoden zur Verfügung: -Enable() Aktiviert den Stencilbuffer, dies sollte immer gemacht werden, bevor man den Stencilbuffer benutzt. -Disable() Sobald man mit der Verwendung des Stencilbuffers fertig ist, sollte man diese Methode aufrufen. -BeginMask(ref:Int = 1) Zeichnenoperationen die nach Aufruf dieser Methode aufgerufen werden, setzen den Wert aller Pixel, die dabei beschrieben werden würden, im Stencilbuffer auf den Wert ref. Der aktuelle Grafikbuffer (in der Regel der Backbuffer) wird hierbei nicht beschrieben. -EndMask(mode:Int = GL_EQUAL, ref:Int = 1, mask:Int = %11111111) Nachdem man alle Werte im Stencilbuffer wie gewünscht gesetzt hat, kann man mit dieser Methode festlegen, wo folgende Zeichnenoperationen im Abhängigkeit von den im Stencilbuffer gespeicherten Werten auf den aktuellen Grafikbuffer schreiben dürfen. Mode gibt dabei an, in welcher Beziehung ref zu den Werten im Stencilbuffer stehen muss, damit ein Pixel beschrieben werden darf. Es gibt folgende Werte, wobei stencil im Folgenden der jeweilige Wert im Stencilbuffer sei, an dem gezeichnet werden soll:
-clearMask() Setzt alle im Stencilbuffer gespeicherten Werte auf 0 zurück. Wenn man sich nicht auf vorherige Werte beziehen will, sollte man diese Methode immer aufrufen, bevor man den Stencilbuffer neu beschreiben will. Wie sieht die konkrete Anwendung aus? Die Dokumentation der Klasse TGLStencil ist etwas lang ausgefallen, weil der Stencilbuffer eben all diese Möglichkeiten (und eigentlich noch mehr) bietet. Aber in der tatsächlichen Anwendung sollten meist die Standardwerte für die Methoden vollkommen ausreichen. Daher auch im folgenden ein kleiner, lauffähiger Beispielcode der zeigt wie man ein Rechteck so zeichnet, dass es nur innerhalb eines Kreises angezeigt wird. BlitzMax: [AUSKLAPPEN] SuperStrict Der Beispielcode sollte zu folgendem Ergebnis führen: Im Code fällt vielleicht diese Zeile auf. BlitzMax: [AUSKLAPPEN] SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_STENCILBUFFER) Sie ist notwendig um einerseits den Grafiktreiber auf OpenGL zu setzen (siehe brl.glmax2d), und andererseits um festzulegen, dass Graphics den Grafikkontext mit Stencilbuffer erstellen soll (ich habe festgestellt, dass das auf modernen Grafikkarten nicht selten automatisch geschieht, auch wenn der Flag nicht gesetzt wurde, aber darauf kann man sich im Allgemeinen nicht verlassen). Wofür kann man den Stencilbuffer denn verwenden? Ein simpler Anwendungsbereich ist die zu Anfang gezeigte Minimap, bei der man mit Hilfe des Stencilbuffers genau bestimmen kann, was noch gezeichnet werden soll und was nicht. Generell lässt sich der Stencilbuffer immer dann verwenden, wenn man etwas nur an bestimmten Pixeln zeichnen möchte. Wissenswertes Sehr mit dem Stencilbuffer verwandt ist der Z-Buffer beziehungsweise Tiefenbuffer. Er verfügt heutzutage oftmals über mehr als 8 Bit Speicher für jeden einzelnen Pixel, wobei in diesem jeweils gespeichert wird, wie weit der Pixel vom Betrachter entfernt ist (bzw. der Punkt eines Dreiecks, der dem Pixel seine Farbe gegeben hat). Beim Zeichnen ein jedes Dreiecks einer 3D-Szene wird ein Pixel nur dann überschrieben, wenn der neue Wert kleiner wäre als der vorherige - so erscheinen nachher alle Dreiecke in der richtigen Reihenfolge gezeichnet worden zu sein. Die Range der Kamera wird auf die Werte des Z-Buffers projiziert, daher nehmen mit steigender Range auch die Bildfehler bezüglich der Zeichenreihenfolge nahe beieinander liegender Dreiecke zu, da die Abstandsangaben im Z-Buffer zu ungenau werden. Der Stencilbuffer ist nicht OpenGL-only, ich beschränke mich hier vor allem der Einfachheit wegen auf OpenGL. Aber es gäbe da auch noch ein Stencilbuffer-Modul von btbn das neben OpenGL auch DirectX9 unterstützt. Dieses Tutorial erhebt keinen Anspruch auf Richtigkeit, Vollständigkeit, Qualität und Funktionsweise des bereitgestellten Codes. Ich wünsche noch viel Spaß beim selbst Experimentieren. Lobby Divinus |
||
TheoTown - Eine Stadtaufbausimulation für Android, iOS, Windows, Mac OS und Linux |
Übersicht BlitzMax, BlitzMax NG FAQs und Tutorials
Powered by phpBB © 2001 - 2006, phpBB Group