Registriert: Mi Dez 03, 2008 12:01 Beiträge: 167 Wohnort: /country/germany
Programmiersprache: C++ / FreeBASIC
Hi,
ich mache mir momentan Gedanken über Licht und Schatten in meiner 3D-Engine. Leider hab ich nur Tutorials gefunden, die den Stencil-Buffer verwenden, und ich habe gerhört das es nicht empfolen wird den zu nehmen.
Daher will ich hier mal fragen, ob mir jemand erklären kann wie ich Licht- und Schatten-Effekte am besten in mein Programm einbaue, und wie das mit Licht und Schatten zusammenhängt, oder ob ihr da ein gutes Tutorial kennt.
Am besten wäre es natürlich, wenn das Tut das sehr detailiert erklären würde.
Schatten entsteht dadurch das Licht an einigen Stellen NICHT auf eine Oberfläche fällt. Aus diesem Grund kann man Schatten nicht etwa durch rendern zusätzlicher dunkler Geometrie oder ähnliches realisieren.
Im wesentlichen gibt es zwei Ansätze:
1. Shadow Volumes
2. Shadow Maps
Der erste Ansatz wird meist über den Stencil-Buffer realisiert. Das ganze erzeugt sehr exakte Schatten da wirklich die Geometrie des Schattens berechnet wird. Mit dieser Technik sind keine Soft-Shadows (siehe Bild in meiner Proseminararbeit, Abschnitt 4) möglich bzw. nur mit großem Aufwand. Außerdem funktioniert die Technik nur für echte Geometrie die auch speziell vorbereitet werden muss. Schatten von Partikeln oder Bäumen (die über Alpha-Texturen realisiert sind) sind nicht (effizient) möglich. Während dem Render-Vorgang muss in jedem Frame zusätzliche Geometrie erzeugt werden. Dies geht nur über die CPU (langsam!) bzw. mit einem Geometryshader (ShaderModell 4.0). Desweiteren ist die Technik sehr Füllraten intensiv.
Der zweite Ansatz ist sehr schnell und universell. Er lässt sich in quasi jede beliebige Szene einbauen. Die Szene wird aus der Perspektive der Lichtquelle gerendert und der erhaltene Z-Buffer dann im eigentlichen Render-Vorgang verwendet um zu berechnen wo Schatten ist und wo nicht. Es handelt sich um eine Image-Space-Technik, daher kann es zu Problemen mit der Auflösung kommen, auch Aliasing genannt. Das passiert insbesondere dann, wenn die Kamera genau auf die Lichtquelle blickt. Der Ansatz eignet sich insbesondere für Spot-Lichtquellen. Es gibt verschiedene Techniken die sich insbesondere um das Aliasing kümmern. Genannt werden sollten hier die "Perspective Shadow Maps" sowie vielleicht "Parallel Spilt Shadow Maps".
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Es gibt noch Techniken, die mit hilfe von Raytracing und Shadowmap sowie ShadowVolume ihre Schatten realisieren aber werden sehr wenige Strahlen verwendet(hält sich je nach PC nur schwer im Echtzeitbereich). Es gibt auch noch möglichkeiten, Schatten realistischer zu machen, indem man das ungenaue Soft Shadow verwendet oder das genauere Penumbra Shadow(http://dee.cz/fcss/ ).
Am beliebtesten sind momentan die PSSM(Parallel Split Shadow Maps), da man hier je nach Hardware gut am Regler drehen kann und man sehr schnell den Treppeneffekt los wird. Im NV SDK wird das meines wissens über Texturarrays gelöst, die aber erst mit OpenGL3 verfügbar sind. Bei OpenGL2 und darunter werden einfach alle Teiltexturen einzeln gebunden. http://hax.fi/asko/PSSM.html
Weitere Schattierungsmöglichkeiten sind AO(Ambient Oclussion), realtime radiosity, screen space ambient oclussion(ssao) und spherical harmonic lighting.
Diese sind zum unterstützen sehr gut geeignet aber für sich selbst stehend kaum sinnvoll.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
@Coolcat: Wenn deine Arbeit noch soweit aktuell ist, dann kannst du daraus ja einen Auszug als Artikel ins Wiki stellen und deine Arbeit drinnen verlinken. Ich finde das als Zusammenfassung verschiedener Ansätze recht gut gelungen (auch wenn ich nur kurz drüber geschaut habe).
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Es gibt neuere Techniken (wie die besagten PSSM, etc.), aber als Einstieg in die Materie ist der Artikel wahrscheinlich immer noch ganz ok. Eine Überarbeitung kann aber sicher nicht schaden.
Ich bin im Augenblick ziemlich knapp mit der Zeit. Aber der Artikel darf gerne unter der Lizenz des Wikis verwendet werden. Also unter GNU Free Documentation License 1.2. Ausgenommen sind die Bilder die ursprünglich aus GPU Gems bzw. einem der Literatur-Paper stammen. Ich hänge einfach mal den Quellcode der Arbeit an....dann kann sich jemand der Zeit hat damit beschäftigen. Die Bilder an denen ich nicht die vollen Rechte besitze habe ich entfernt.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Registriert: Mi Dez 03, 2008 12:01 Beiträge: 167 Wohnort: /country/germany
Programmiersprache: C++ / FreeBASIC
Danke, ihr habt mir schon mal sehr geholfen Ich werde mir das ganze Material mal genau durchlesen, falls es Probleme geben sollte melde ich mich wieder.
Registriert: Mi Dez 03, 2008 12:01 Beiträge: 167 Wohnort: /country/germany
Programmiersprache: C++ / FreeBASIC
So, die ersten Fragen sind schon aufgetaucht Also, Schatten entstehen, indem ich die anderen Pixel aufhelle, aber die "schattigen" nicht. Stimmt das so?
Ich habe mich jetzt mal für Shadow Maps entschieden. Mal sehen, ob ich das verstanden habe:
Ich rendere zuerst einzeln aus der Sicht jeder einzelnen Lichtquelle, die Texturen sind ausgeschaltet. Die Werte des depth-buffers werden im in einer Textur addiert. Beim rendern der "User-Ansicht" berechne ich dann im Fragment-Shader aus den Werten des depth-Buffers, um wieviel ich den Pixel aufhellen muss, die Texturen sind wieder aktiviert. Die "Fragmente" werden dazu in den Projektionsraum der Lichtquelle transformiert, ist die Entfernung kleiner als der Wert in der depth-Buffer-Textur wird der Pixel entsprechend der Entfernung aufgehellt, ansonsten nicht. Ist das alles richtig?
Momentan hab ich noch keine Ahnung wie ich das anstelle das die depth-Buffer-Werte in einer Textur addiert werden. Wie geht denn das?
Und wie mache ich das mit dem Öffnungswinkel der Lichtquelle? Was muss ich dazu an der "Kamera" verändern?
Und wie geht das mit dem Transformieren? Wie berechne ich die Entfernung?
Ich muss also für jede Lichtquelle zweimal rendern: Einmal für die depth-Textur, und dann mit dem Shader.
Wo speichere ich jetzt hin, umd wieviel der Pixel letzendlich aufgehellt wird?
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
also wie das beim forward rendern geht weiß ich nicht. Beim deferred rendern gehts im etwa so:
man erstellt ein FBO (FramebufferObject) das repräsentiert eine "unsichtbare" Zeichenfläche in größe deines Viewports. An dieses FBO fügst du verschiedene Ebenen an. Diese sind dann entweder Texturen, oder Renderbuffer. Wenn du das FBO aktivierst und zeichnest, dann landet alles was du zeichnest in den Ebenen des FBOs anstelle deiner sichtbaren Zeichenfläche. Der Trick an der Sache ist jetzt, dass du alle wichtigen Daten der Szene, wie Depthbuffer, Normalen, Farben in dieses FBO zeichnest. Damit das FBO weiß, welche information deiner Geometrie in welche Ebene gehört musst du dir einen Fragment- und Vertexshader schreiben. Das ist nur die Vorbereitungsphase für das Szenarion. An dieser Stelle hast du eine nichtsichtbare Kopie deiner Szene in der Grafikkarte abgelegt.
In der zweiten Phase, nch dem sammeln der Szeneninformationen, kümmert man sich jetzt um die Lichtquellen. zunächst wird geprüft, welche Lichtquelle auf dem Bildschirm sichtbar ist. dazu kann man einen Octree verwenden und den Mittelpunkt + Radius der Lichtquelle. Jedes Licht das sichtbar ist zeichnet jetzt mit einem zweiten FBO in eine DepthTexture (du kannst für alle Lichter die selbe nehmen, da sie nur zum Zeitpunkt des Zeichnens gebraucht wird) die Szene von der Lichquelle aus betrachtet. Unmittelbar nach dem erstellen dieser DepthTextur zeichnet man an der Position der Lichtquelle ein Billboardquad mit der Kantenlänge des doppelten Radius der Lichtquelle, augerichtet auf den Betrachter. Für das zeichnen dieser Quads muss ein anderer Shader aktiv sein, als der, der in der ersten Phase die Daten gesammelt hat. Der jetztige Shader muss an jedem Punkt des gezeichneten Quads (das unsere Lichtquelle darstellt) den Test für die Sichtbarkeit durchführen. Dazu braucht der Shader die zuvor erstellte DepthTexture, den Betrachter vektor, die Position der Lichquelle und die Richtung der Lichtquelle. Aus der Tiefe des Pixels auf in dem FBO und der Position sowie der Blickrichtung des Betrachters kann man feststellen, an welcher Stelle sich ein Punkt befindet. Mit diesem Wissen kann man mit hilfe der Position der Lichtquelle die Distanz zwischen den beiden Punkten feststellen. Diese distanz rechnet man wieder um in einen Depthwert. Anschließend muss herrausgefunden werden wo in der DepthTexture die Tiefe des selben Punktes zu finden ist (frag mich nicht wie das geht). Hat man den Punkt gefunden braucht man nur noch die beiden entfernungen vergleichen.
Jetzt kommt das große Kino. Ist die Distanz ungefähr gleich der Entfernung vom Betrachter, so kann man en gewohnten Lichtalgorhytmus auf den Pixel anwenden, ansonsten steigt man einfach aus via discard. Wichtig ist, dass man an dieser Stelle kein FBO gebunden hat, damit das ergebnis wieder auf dem Bildschirm landet.
Mitglieder in diesem Forum: 0 Mitglieder und 9 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.