Methode zur indirekten diffusen Beleuchtung gesucht!
-
Echtzeit oder vorberechnet? Statische oder dynamische Szene? Lightmapping und Radiosity sind dir ein Begriff?
-
Ich empfehle dir Photonmapping. Ist zumindest besser als Radiosity und muss für statische Objekte nur einmal berechnet werden. Außerdem kann man im Gegensatz zu Radiosity Lichtbündelungen(Caustiken) besser realisieren. Über KD-Bäume kannst du Photonmapping auch bei dynamischen Szenen verwenden.
-
Vielen Dank für die vielen Vorschläge!
Die Beleuchtung kann vorberechnet werden, aber der Spieler ist in der Lage in kurzer Zeit die Umgebung zu verändern also sollte die einzelne Berechnung nicht zu lange dauern. Sobald sich ein Objekt der Szene ändert, kann es durchaus sein dass sich die komplette Beleuchtung ändert. Außerdem gibt es eine dynamische Sonne. Z.B. wenn sich der Spieler in einem dunkelen Gebäude befindet und sich plötzlich einen Ausgang ins Freie verschafft. Photonmapping klingt attraktiv, vor allem weil ich nur bis zur zweiten Reflexion rechnen muss. Den KD-Baum übergebe ich dann per Constant Buffer?
-
Du kannst das Photonmapping an zwei Stellen berechnen:
Weg 1: CPU
-Versende erst Photonen
-Schaue für jedes 3D-Objekt, an welchen stellen es von Photonen getroffen wurde. Dazu wird jedes Photon (3D-Punkt) in 2D-Texturkoordinaten umgerechnet. Das 3D-Objekt braucht also Texturkoordinaten bei seinen Vertixen(Eckpunkten).
-Nun hast du für jedes Objekt eine Textur, auf der die soeben eingezeichneten Photonen liegen. Alle restlichen Punkte der Textur, die kein Photon erhalten haben werden über Interpolation(Gaußfilter/ Conefilter) mit den Punkten, die schon da sind, berechnet.
-Dein 3D-Objekt haben nun also alle eine Farbtextur, welche über Photonmapping berechnet wurde. Diese Textur gibst du nun in die Grafikkarte.Weg 2: Alles auf der GPU berechnen:
-Schau mal unter den Stichworten "realtime photonmapping", CUDA, Optix.NVidia gibt sich da echt Mühe um schöne Bilder zu erzeugen^^
-
Ich könnte es ja so machen, dass ich die Positionen der Photonen im CPU berechne, und dann dessen 3D Koordinaten als Farbpunkte in die Grafikkarte gebe und für jedes Objekt (z.B. eine Box) für jede sichtbare Seite eine Photon-textur rendere. Dann schicke ich das Photon-textur-array zum Rendern der fertigen Szene wieder an die Grafikkarte. Oder sollte ich die 2D Position gleich durch die CPU berechnen lassen?
Wie kann ich denn heraus finden wo ich die anfangs Photonen setzen soll?
Sollte ich in der Shadowmap außer den Tiefeninformationen noch 3d Koordinaten speichern?
Vielen Dank für die hilfreichen InfosEDIT: Ich rendere natürlich nicht für jedes Objekt nochmal eine Photon textur sondern eine 2d Photon Map aus der Sicht der Kamera. Dann lege ich die Photon Map additiv über meine gerenderte Szene unter Berücksichtigung der Tiefeninformationen. Es war wahrscheinlich noch zu früh für mich
-
Du hast mich ehrlich gesagt wirklich noch auf ein 3. Weg gebracht.
Mit der CPU versendest du die Photonen und erhälst als Ergebniss eine Liste von Farbigen 3D-Punkten.
Diese Liste gibst du nun als ConstantBuffer in der Grafikkarte und über den Pixelshader fragst du dann für jeden Pixel ab, welche Photonen dort in der Nähe liegen. Der Tiefentest muss dazu abgeschaltet sein.
Die offene Frage für mich wäre dann nur noch: Du hast für jeden Pixel nun den Farbwert berechnet. Wie kannst du diese Information (Texturkoordinate + Farbwert) nun wieder zurück in den Hauptspeicher kopieren?
Punkt 2: Was passiert mit Dreiecken die nah oder weit weg sind? Das Verfahren soll eigentlich unabhängig von der Position der Kamera die Farbberechnungen durchführen.
Anfangsposition der Photonen? Na von der Lichtquelle und dann Schnittpunkt zwischen Strahl und Dreieck berechnen, um Photonenaufschlagspunkt zu berechnen.
-
Vielen Dank für die Hilfe!
Ich war nun in der Lage, die Photonen im Voraus durch die CPU berechnen zu lassen, dabei habe ich erstmal nur bis zum zweiten Bounce gerechnet und die 3d Punkte in einer eigenen Textur gerendert. Zum Schluss wird die Photonen-map über das Szenenbild gelegt. Hier ist das Resultat: http://image-upload.de/file/6CwId2/b08380f1a0.pngNun muss ich die Pixel dazwischen nur noch durch einen Filter interpolieren.
Ich habe zunächst von einer Farbveränderung der Photonen abgesehen. Außerdem lasse ich zunächst die Photonen nur reflektieren.
-
Ich finds super, wenn ich dir weiterhelfen konnte. Zeig dann mal ein Bild, wenn du die Interpolation auch noch implementiert hast.
Hier mal eine Formel, die ich bei mein Photonmapping verwende, um die Interpolation zu berechnen.
List<Photon> Photonen = null; do { photonKugelRadius += kugelWachstumsrate; kugelWachstumsrate += 0.01f; Photonen = GetFirstNPhotonenFromKugelbereich( position, //Für diesen 3D-Punkt soll der Farbwert bestimmt werden photonKugelRadius, //Suchradius PhotonenSuchAnzahl, // So viel Photonen werden maxmal zurück gegeben (200 in diesen Fall) schnittPunkteigenschaften); } while (Photonen.Count < PhotonenSuchAnzahl && photonKugelRadius < PhotonenSuchRadius); float radius = photonKugelRadius; //Bilde gewichtete Summe (Jedes Summenglied liegt zwischen 0 und 1) photonFarbe = new Vektor(0, 0, 0); foreach (Photon P in Photonen) { float weight = (radius - Math.Min(radius, (position - P.Position).Betrag())) / radius; // Weight by Photon-Point Distance photonFarbe += P.Farbe * weight; if (photonFarbe.x > 1 || photonFarbe.y > 1 || photonFarbe.z > 1) break; } photonFarbe = photonFarbe / (radius * radius) * 15000; // Teile durch die Fläche des Kreises, damit Bild nicht Heller wird, wenn Kreis größer wird.
-
Ich glaube ich habe es mir am Anfang etwas zu einfach gemacht. Im Pixel Shader wo ich das Photonenbild über die Szene lege, habe ich nun versucht innerhalb einer 20x20 pixel box per Bruteforce nach einem photon zu suchen und wenn vorhanden die Stelle aufzuhellen je nach Entfernung des gefundenen Photons. Als Ergebnis hatte ich dann 3 FPS, und das Ergebnis: http://image-upload.de/file/Rs71k6/5d7ab868f9.png
Eventuell versuche ich das Photonen Bild zu verkleinern um die Suche zu beschleunigen, oder ich Interpoliere direkt das Photonen Volumen. Leider ist das Interpolieren im Pixel Shader ein krampf...
-
In der CPU kann man einfach im KD-Baum die Nearest Neighbor Search-Funktion benutzen. Ich denke mal, dass man sowas auch in der Grafikkarte machen kann. Sollten dort Objektreferenzen nicht gehen/erlaubt sein, dann kann man ja über eine Integer-Index-Verweise arbeiten. Ein rekursiv definierte Datenstruktur kann man ja als Array speichern und Rekursive verweise sind dann Indexverweise auf das Array.
Sollten KD-Bäume zu hart sein, dann kannst du auch Oktrees nehmen. Die kommen ohne Prioitätslisten, Quicksort und Medianbestimmung aus.