Radiosity

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Punika
Beiträge: 29
Registriert: 25.02.2002, 15:12
Echter Name: Lutz Hören
Kontaktdaten:

Radiosity

Beitrag von Punika »

Hallo Zusammen,

bin schon seit einiger Zeit dran einen Radiosity Lightmapper zu schreiben. Das ganze verfahren mache ich noch auf die herkömmliche Art, also Progressive Refinement Radiosity über Raytracing (Rays vom Emitter zu möglichen Collectors).

In den Grundzügen funktioniert der auch, aber er läuft zum einen nicht Stabil, ich bekomme kein realistisches Radiosity hin und habe auf manchen Flächen Fehler.

Erstmal eine Frage zur Formel. Da ich meine Scene im Moment mit Patches so unterteile das jedes Patch die gleiche Größe hat, fallen quasi die Werte fast weg. z.B. ist bei mir die Differenz Fläche hauptsächlich bei 1. Das passiert bei mir im Moment nur bei Lichtern nicht. Da diese zusätzlich zu den Geometry Patches extra hinzugefügt werden. Die Sichtbarkeit Fläche wäre bei mir auch noch entweder 0 (fällt weg da vorher getestet wird ob emitter sicht hat zu collector oder nicht) oder eben 1.

Wenn ich nun einem Patch genug Energy gebe um im ersten Pass die Szene zu beleuchten funktioniert das auch tadellos. Doch im nächsten Pass ist viel zu wenig Energy da, da man durch Fij nur noch Werte im Bereich von 0.00001 hat. Wenn ich diese wieder durch eine Konstante in den Bereich bringe wo ich mit Arbeiten kann, wird das sehr unstabil. Entweder wird alles komplett Hell oder es bleibt quasi beim ersten Pass.

Meine Frage ist nun wie ihr die Werte stabil bekommt -> zum sichtbaren 0 - 1 Bereich für die Texturen. Oder ob Radiosity nur stabil läuft mit Patch Subdivision -> Große Patch flächen am Anfang.

Vielen Dank

punika
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Radiosity

Beitrag von eXile »

Woah … Radiosity … das ich davon noch einmal höre! Sehr schön! :D Mein Wissen darüber ist etwas eingerostet, aber ich glaube ich krieg das noch gebacken. Erst einmal damit wir wissen, worüber wir sprechen, die Renderinggleichung auf Radiosity-Form gebracht:
\($$B(\mathbf x) = E(\mathbf x) + r(\mathbf x) \cdot \int_A B(\mathbf x') \, H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \, \mathrm dA$$\)Das heißt also, wir sitzen aufm Punkt \($\mathbf x$\) und integrieren über alle infinitesimal-großen Flächenelemente unserer Szene - das Zentrum dieses Flächenelements ist dabei mit \($\mathbf x'$\) im Integral angegeben. \($\vartheta_i$\) gibt den Winkel zwischen der Normalen der Fläche bei \($\mathbf x$\) und der Verbindungsstrecke zwischen \($\mathbf x$\) und \($\mathbf x'$\) an. Analog gibt \($\vartheta_j$\) den Winkel zwischen der Normalen der Fläche bei \($\mathbf x'$\) und der Verbindungsstrecke zwischen \($\mathbf x$\) und \($\mathbf x'$\) an. \($B(\mathbf x)$\) gibt die Energie vom Punkt \($\mathbf x$\) an (d.h. nach obiger Formel ist das die Summe der von \($\mathbf x$\) emmitierten Energie \($E(\mathbf x)$\) und der auf diesen Punkt eingehenden Energie). \($H(\mathbf x,v\mathbf x')$\) gibt den Sichbarkeitsterm an: 1 wenn der Punkt \($\mathbf x$\) den Punkt \($\mathbf x'$\) sehen kann, oder 0 wenn nicht (binäre Entscheidung - keine Werte dazwischen!). \($r(\mathbf x)$\) gibt den diffusen Reflexiongrad der Oberfläche bei \($\mathbf x$\) an.

Mit ein paar Annahmen (z.B. dass wir Patches haben, auf denen die Energiewerte konstant sind) kann man das in ein Gleichungssystem transformieren (aka die Radiosity-Gleichung):
\($$B_i = E_i + r_i \cdot \sum_{j=1}^n B_j F_{ij} \qquad \text{ für } i = 1 \ldots n$$\)Die \($B_i$\), \($E_i$\) und \($r_i$\) sind eigentlich wie oben, die \($F_{ij}$\) sind die Formfaktoren:
\($$F_{ij} = \frac{1}{A_i} \int_{A_i} \int_{A_j} H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \, \mathrm dA' \mathrm dA$$\)Dabei ist wieder wie oben \($\mathbf x$\) das Zentrum von der infinitesimal-großen Fläche \($A$\) und \($\mathbf x'$\) ist das Zentrum der infinitesimal-großen Fläche \($A'$\). Wie man sieht, gibt also der Formfaktor \($F_{ij}$\) den Anteil der Energie an, welche von \($A_i$\) abgestrahlt wird und bei \($A_j$\) ankommt. Damit ist der Formfaktor auch einheitenlos: Bei dem Integral käme ja in SI-Einheiten die Einheit \($\mathrm m^2$\) (Quadratmeter) raus, aber da wir ja am Anfang durch \($A_i$\) (auch in \($\mathrm m^2$\)) teilen, kürzt sich das alles raus! :) Jetzt zu deinen Fragen:
Punika hat geschrieben:Erstmal eine Frage zur Formel. Da ich meine Scene im Moment mit Patches so unterteile das jedes Patch die gleiche Größe hat, fallen quasi die Werte fast weg. z.B. ist bei mir die Differenz Fläche hauptsächlich bei 1. Das passiert bei mir im Moment nur bei Lichtern nicht. Da diese zusätzlich zu den Geometry Patches extra hinzugefügt werden. Die Sichtbarkeit Fläche wäre bei mir auch noch entweder 0 (fällt weg da vorher getestet wird ob emitter sicht hat zu collector oder nicht) oder eben 1.
OK, ich nehme erstmal an, du meinst mit der Formel die Formel zur Berechnung der Formfaktoren. Ich verstehe erst einmal nicht, was du mit „Differenzfläche“ meinst. Und wenn die Patches doch gleich groß sind, ist doch die Differenz der Flächeninhalte 0? Und viel scherwiegender: In der Formel für die Formfaktoren kommt doch eine Differenzfläche gar nicht vor! Über welche Formel sprechen wir hier nun?
Das Berechnen der Formfaktoren geht z.B. via das Verfahren von Wallace, was auch Raytracing benutzt, so wie du. Bei der häufig genutzten Approximation mittels einer Kreisscheibe mit Flächeninhalt a in Entfernung r gilt für den Formfaktor ungefähr (Halt! Das ist noch nicht die finale Form! Das ist nur für den Formfaktor zwischen genau zwei Kreisscheiben!):
\($$F_{ij} = \frac{a^2 \cdot \cos(\vartheta_i) \cos(\vartheta_j)}{a^2 + r^2}$$\)Aber wir haben ja eigentlich quadratische Patches und außerdem wurde in der obigen Formel viel mit der Sichbarkeit bzgl. der Orientierung der Flächen bei flachen Winkeln rumgehackt. Also eigentlich ist diese Formel ein gigantischer Hack. Aber er sieht gut aus. Also beim Verfahren von Wallace wird jetzt der Zielpatch nicht durch eine Kreisscheibe approximiert, sondern durch ganz viele. Dabei wird immer via Raytracing überprüft, ob die Kreisscheibe sichtbar ist (vom Zentrum des Ursprungspatches aus gesehen). Falls ja, wir das Ergebnis von obiger Formel zum Formfaktor hinzuaddiert, ansonsten halt nicht. Natürlich macht man zuerst ein paar Kollisionstests zwischen den Eckpunkten der Patches, ob überhaupt eine Okklusion stattfindet, und man überhaupt den Zielpatch weiter unterteilen möchte.
Punika hat geschrieben:Wenn ich nun einem Patch genug Energy gebe um im ersten Pass die Szene zu beleuchten funktioniert das auch tadellos. Doch im nächsten Pass ist viel zu wenig Energy da, da man durch Fij nur noch Werte im Bereich von 0.00001 hat. Wenn ich diese wieder durch eine Konstante in den Bereich bringe wo ich mit Arbeiten kann, wird das sehr unstabil. Entweder wird alles komplett Hell oder es bleibt quasi beim ersten Pass.
OK, wenn du dir sicher bist, dass deine Berechnung stimmt (wovon ich bei einem erfolgreichen ersten Pass erst einmal ausgehe, es sei denn, du machst dort irgendetwas anders als in den anderen Passes), wären meine ersten Ideen: Intensität der Lichtquelle rauf, Reflexionsanteile (die r_i oben) rauf oder die gesamte Szene gleichmäßig kleiner Skalieren (das vergrößert die Formfaktoren und ist somit eine Mischung aus den beiden vorherigen Sachen).
Punika hat geschrieben:Meine Frage ist nun wie ihr die Werte stabil bekommt -> zum sichtbaren 0 - 1 Bereich für die Texturen. Oder ob Radiosity nur stabil läuft mit Patch Subdivision -> Große Patch flächen am Anfang.
Das sollte eigentlich ohne weitere Hacks funktionieren. Hierachisches Radiosity macht dabei bzgl. der Korrektheit keinen Unterschied.

PS: Ich bin mit dem LaTeX-Bild-Server oben nicht wirklich zufrieden, da die Referrer gespeichert werden. Ich hatte vor einigen Wochen mal an einem eigenen Tool für phpbb gebastelt - insbesondere mit richtigem Subpixel-Antialiasing, und nicht dem Kack dort oben (ich habe mich dabei von dem 5-Tap-FIR-Filter der FreeType-Library inspirieren lassen) - aber im Augenblick liegt das aus Zeitmangel wieder auf Eis. Aber bald … bestimmt.

Nachtrag: Alles auf MathJax umgestellt.

PPS: Ich mag die von Radiosity erzeugte Beleuchtung sehr gern. Insbesondere in Mirror's Edge sieht man die Ergebniss sehr schön. Allgemein ist glaube ich die Half-Life-2-Engine das einzige Paket, welches einen Radiosity-Berechner eingebaut hat (das schon zu Half-Life-1-Zeiten - eines der großen Erweiterungen im Vergleich zur Quake-Engine).
Zuletzt geändert von eXile am 22.04.2012, 15:38, insgesamt 4-mal geändert.
Benutzeravatar
Krishty
Establishment
Beiträge: 8260
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Radiosity

Beitrag von Krishty »

Außerdem liegt das Ergebnis der Radiosity im linearen Farbraum vor – auch das darf man nicht vergessen, insbesondere bei den Reflexionseigenschaften. Die erwähnten Werte von 0,00001 entsprechen einer empfundenen Helligkeit von fast einem Prozent bzw. zwei Stufen in einer 8-Bit-sRGB-Textur, womit sie langsam wieder in den sichtbaren Bereich kommen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Punika
Beiträge: 29
Registriert: 25.02.2002, 15:12
Echter Name: Lutz Hören
Kontaktdaten:

Re: Radiosity

Beitrag von Punika »

Hallo zusammen

die Fragen oben bezogen sich auf den Form Faktor. Den Form Faktor auf den ich mich beziehe lautet:
Bild

Der kommt aus dem Artikel von Paul Nettle -> Radiosity in English

Da spricht er von einer differenz Fläche dAj.
Ich werde mich heute mal dran geben kurz die Cornell Box zu importieren. Dann kann man leichter die Werte vergleichen.

Vielen Dank

punika
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Radiosity

Beitrag von eXile »

OK, ein klein wenig babylonisches Sprachgewirr: Mit einer „differentiellen Fläche“ ist im Artikel eine infinitesimal-kleine Fläche gemeint.

Wenn man die Fläche vom Ursprungspatch als infinitesimal-klein betrachtet, erhält man:
\($$\begin{align}F_{ij} &= \frac{1}{A_i} \int_{A_i} \int_{A_j} H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \, \mathrm dA' \mathrm dA \\
&= \frac{1}{A_i} \int_{A_j} H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \, \mathrm dA' \cdot \int_{A_i} \mathrm dA \\
&= \int_{A_j} H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \, \mathrm dA'\end{align}$$\)
Wenn man zusätzlich auch noch die Fläche vom Zielpatch als infinitesimal-kleine betrachtet, erhält man weiter:
\($$\begin{align}F_{ij} &= \int_{A_j} H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \, \mathrm dA' \\
&= A_j \cdot H(\mathbf x, \mathbf x') \cdot \frac{\cos(\vartheta_i) \cos(\vartheta_j)}{\|\mathbf x - \mathbf x'\|^2 \cdot \pi} \end{align}$$\)
Diese Formel entspricht der von dir genannten. Die Frage ist aber: Wollen wir überhaupt diese Formel?

Wenn man also wirklich annimmt, unsere Ursprungs- und Zielpatches sind hinreichend klein, kann man die nehmen. Die Konsequenz daraus ist aber klar: Der Term \($H(\mathbf x, \mathbf x')$\) vom Formfaktor kann dann entweder nur Null oder Eins annehmen, d.h. entweder kriegt er vom Zielpatch alles ab oder garnichts. Insbesondere beim ersten Pass würde das bedeuten, dass alle Patches, die die Lichtquelle nicht direkt sehen, schwarz sind, und alle anderen voll beleuchtet, d.h. es gibt keine Penumbra-Region. Ist es das was du möchtest?

Leider wird häufig nämlich mit zweierlei Maß gemessen: Man nimmt an, der Ursprungspatch (also wo wir grad draufsitzen) ist hinreichend klein, aber der Zielpatch (selbst wenn er dieselbe Größe hat) ist es nicht! D.h. man unterteil den Zielpatch weiter in kleinere Subpatches, und bestimmt von den Subpatches die Formfaktoren und sammelt von allen diesen Subpatches die Energie ein. Das würde dann durch die obere der beiden Formel beschrieben werden, und man erhält Penumbra-Regionen. Da sieht man auch, dass die Texel der Lightmap nicht der höchsten Auflösung der Subpatches entsprechen. (Statt Subpatches kann man auch einfach zufällig Strahlen vom Ursprungspatch zum Zielpatch schießen, da muss man aber höllisch auf die Energieerhaltung aufpassen.) Darum setzt man einfach die Patchauflösung hoch und die Texel der Lightmap fassen dann 4, 9, 16, usw. Patches zusammen, womit man auch Penumbraregionen bekommt, und es keine künstliche Trennung zwischen Patches und Subpatches mehr gibt.

Der Teil
Paul Nettle hat geschrieben:Differential areas are calculated by simply dividing the transmitting patch’s area by the receiving patch’s area.
ist mir persönlich absolut schleierhaft. Die von mir oben geposteten Formeln wurden einfach via Integrationsregeln hergeleitet, und da kommt überhaupt gar nichts mit einer Division durch die Flächeninhalte vor. Das sind einfach die Integrationsgrößen. Ich weiß, mich selbst gegen Paul Nettle zu stellen ist nicht wirklich besonders schlau, aber mich bringen seine Ausführungen nicht besonders weiter (oder er vereinfacht an der Stelle zu stark).

Nur so als Frage: Ist denn deine bisherige Radiosity-Lösung energieerhaltend, sprich ist die Summe der Energien von allen Patches konstant?
Zuletzt geändert von eXile am 22.04.2012, 15:40, insgesamt 4-mal geändert.
Punika
Beiträge: 29
Registriert: 25.02.2002, 15:12
Echter Name: Lutz Hören
Kontaktdaten:

Re: Radiosity

Beitrag von Punika »

Zu deiner Frage, Nein ist sie leider nicht. Wenn ich mit anfange habe ich zum Beispiel 12.6 ausgehende Energy. Am Ende mit der von Paul Nettle beschriebenen Formel haben meine Patches aber ca. 22.3 erhalten. Nehme ich aber dAj raus, fange ich auch mit 12.6 an und meine Patches erhalten nur 0.04.

Die Werte sollten ja quasi gleich bleiben. Was ich aber nicht verstanden habe:
1. Warum wir nur 0 oder 1 bekommen wenn die Patches hinreichend klein wären.
2. Die Lösung habe ich nicht so ganz verstanden. Verstehe ich damit das ich wenn ich auch z.B. schon Patches habe die 4x4 groß sind ich quasi, um vernünftige Energy werte zu bekommen, am besten die noch mal zu unterteilen und den Form Faktor von den unterteilten Regionen als Summe dem 4x4 Patch zuweise? -> Und würde das nicht so etwas ähnliches sein wie der sogenannte "differential area" von Herrn Paul Nettle. Da er ja quasi auch einen Faktor über die größe eines Patches mit rein nimmt?

Vielen Dank für die ganze Mühen

punika
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Radiosity

Beitrag von eXile »

Ad 1.
Wenn die Patches hinreichend klein werden, dann bestehen die "sozusagen" nur noch aus einem Punkt. Und die Verbindungslinie zwischen zwei Punkten kann entweder nur verdeckt, oder nicht verdeckt sein. Das sieht man auch an der letzten Zeile der zweiten Formel vom letzten Post: Der Term \($H(x, x')$\) nimmt nur die Werte 0 oder 1 an, d.h. der Formfaktor nimmt Werte die Werte 0 und irgendetwas positives an. Aber man erhält keine Penumbra-Regionen (wenn die Lichtquelle aus nur einem Patch besteht), da ein anderer Patch diesen Lichtpatch entweder sieht oder nicht sieht. Daran schließt sich direkt ad 2. an.

Ad 2.
Sorry, wenn ich mit dem Subpatches oder so unklar war. Vergiss einfach alles mit Subpatches und feineren Unterteilungen. Es gibt nur Patches, sonst nichts. Wenn man die Patches klein genug macht, d.h. die Unterteilung fein genug wählt, ist es plausibel, z.B. 2x2-Patches in der Lightmap als Texel zusammenzufassen. Damit vermeidet man den unter ad 1. genannten Fall, dass wenn es in einem Raum nur ein Patch mit emissiven Anteil gibt, und erhält automatisch durch dieses Zusammenfassen Penumbra-Regionen in der Lightmap. Das ist einfach eine Art von Supersampling bzw. Antialiasing.

Ich habe irgendwie das Gefühl, die hier bisher angesprochenen Formfaktor-Approximationen sind nicht das Gelbe vom Ei, und darum ist die Energieerhaltung auch nicht gegeben. Natürlich könnte man jetzt sagen: „OK, wir schießen einfach die ganze Energie von einem Patch weg, und verteilen die auf die anderen Patches. Dabei zählen wir, wieviel Energie wir überhaupt verteilt haben. Wenn es mehr Energie ist, als der Patch hatte, so haben wir zu viel verschossen, und müssen die übertragene Energie entsprechend skalieren.“ Aber das ist ja auch ein ziemlicher Hack.
Zuletzt geändert von eXile am 20.04.2012, 03:21, insgesamt 2-mal geändert.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Radiosity

Beitrag von kimmi »

Mit welcher Precision arbeitest du? Also Floats oder Double?

Gruß Kimmi
Punika
Beiträge: 29
Registriert: 25.02.2002, 15:12
Echter Name: Lutz Hören
Kontaktdaten:

Re: Radiosity

Beitrag von Punika »

Hi

ich arbeite mit Floats. Ich hatte noch eine Frage. Wie gehe ich mit einem Form Faktor um der im Minus bereich liegt? Dieser fall tritt oft auf.
Wenn ich den absoluten Wert nehme sehen die Resultate eben einigermaßen realistisch aus.

Bild
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Radiosity

Beitrag von eXile »

Punika hat geschrieben:Wie gehe ich mit einem Form Faktor um der im Minus bereich liegt? Dieser fall tritt oft auf.
Das sollte nicht sein. Wenn der Formfaktor negativ ist, so ist entweder der Term \($\cos(\vartheta_i)$\) oder der Term \($\cos(\vartheta_j)$\) negativ. Das kann nur auftreten, wenn der entsprechende Winkel um die Normale außerhalb des Bereichs \($[-90°, 90°]$\) liegt. Dann kann ist aber die Verbindungslinie verdeckt (also \($H(\mathbf x, \mathbf x') = 0$\) und damit ist der ganze Formfaktor 0, also kann er in keinem Fall negativ werden!) und zwar durch das Quell- oder Zielobjekt selbst: Der entsprechende Quell- oder Zielpatch ist falsch herum orientiert. Einfachste Lösung: Statt \($\cos(\vartheta_i)$\) dann \($\max(\cos(\vartheta_i),0)$\) schreiben (für \($\vartheta_j$\) analog).

Bei negativen Formfaktoren ist natürlich die Energieerhaltung auch kaputt.
Zuletzt geändert von eXile am 22.04.2012, 15:41, insgesamt 4-mal geändert.
Punika
Beiträge: 29
Registriert: 25.02.2002, 15:12
Echter Name: Lutz Hören
Kontaktdaten:

Re: Radiosity

Beitrag von Punika »

Der Fehler tritt bei mir genau auf wenn patches genau 90 grad zueinander liegen. Dann kann es passieren das entweder theta_i oder theta_j minimal in den minus bereich gelangen. Habe mich noch nicht damit beschäftigt, könnte mir aber vorstellen das das durch Ungenauigkeiten auftritt.

Beschäftige mich gerade mit Radiosity Normal Mapping. Meine ersten Versuche bringe aber Fehler: bei der Umrechnung Basis Vektoren in Tanent Space und Verschiebung von Lichtquellen. Hab noch nicht ganz verstanden mit welchen Normalen ich rechnen muss für die 3 Basis Vektoren. Die 3 Basis Vektoren mit einer TBN Matrix multiplizieren und mit denen als Normale rechnen ist für mich unlogisch da Sie dann ja im Tangent Space liegen aber ich ja mit meinen Normalen im World Space rechne.

Auf jeden fall vielen Dank für alles

Lutz
Antworten