Radiosity - Die Lichtenergie gerät bei zu geringen Abstand aus dem Ruder
-
XMAMan schrieb:
Die Energie schrumpft bei mir bei der Brdf.
im ersten post schriebst du die energie wird groesser. Schumpfen sollte es nirgendwo, sonst waere es falsch.
https://www.siggraph.org/education/materials/HyperGraph/radiosity/images/slide13.jpg
-
rapso schrieb:
Auch 1 ist eine magic number, was ist wenn die patches 100 mal kleiner oder groesser waeren? -> Das ist nicht zielführend.
Die 1 hier repräsentiert einen qualitativen Unterschied, im Gegensatz zu einer willkürlichen Quantität wie 0.01 die wahrscheinlich nur zufällig in einer bestimmten Szene so passt. Ziel war dabei nur, einen möglichst einfache Ansatz zu finden, der Beleuchtung ohne Lichtquellen verhindert. Die Ursache (falscher Geometrieterm) und der richtige Lösungsansatz dazu wurden ja bereits weiter oben diskutiert.
100 mal größerer patches bedeutet eben nicht, dass das Produkt
empfänger.Faktor * empfänger.Patch.SurvaceArea größer als 1 werden kann wenn empfänger.Faktor korrekt berechnet wird. Schließlich ist der Raumwinkel, der durch eine Fläche abgedeckt werden kann, durch 2π begrenzt.
-
camper schrieb:
rapso schrieb:
Auch 1 ist eine magic number, was ist wenn die patches 100 mal kleiner oder groesser waeren? -> Das ist nicht zielführend.
Die 1 hier repräsentiert einen qualitativen Unterschied, im Gegensatz zu einer willkürlichen Quantität wie 0.01 die wahrscheinlich nur zufällig in einer bestimmten Szene so passt. Ziel war dabei nur, einen möglichst einfache Ansatz zu finden, der Beleuchtung ohne Lichtquellen verhindert. Die Ursache und der richtige Lösungsansatz dazu wurden ja bereits weiter oben diskutiert.
was passiert wenn die surfacearea 100 mal groesser skaliert waere? weiterhin 1 beibehalten oder dann min(...,100) ?
-
rapso schrieb:
was passiert wenn die surfacearea 100 mal groesser skaliert waere? weiterhin 1 beibehalten oder dann min(...,100) ?
Hab meine Antwort oben nochmal editiert, bevor ich die Frage gesehen habe. Problem ist, das empfänger.Faktor falsch berechnet wird.
-
camper schrieb:
100 mal größerer patches bedeutet eben nicht, dass das Produkt
empfänger.Faktor * empfänger.Patch.SurvaceArea größer als 1 werden kann wenn empfänger.Faktor korrekt berechnet wird. Schließlich ist der Raumwinkel, der durch eine Fläche abgedeckt werden kann, durch 2π begrenzt.dieser faktor zwischen zwei patches aendert sich nicht. Patch groesse ist nur eine granularitaet. du kannst z.b. eine wand als 1 patch nutzen oder in millionen tesselieren. Raumwinkel spielt da auch ab einer gewissen distanz zwischen patches keine roller (deswegen wird es so approximiert). 1 ist deswegen eine magic number die mal funktionieren kann, an anderer stelle ganz falsche resultate liefert.
-
camper schrieb:
rapso schrieb:
was passiert wenn die surfacearea 100 mal groesser skaliert waere? weiterhin 1 beibehalten oder dann min(...,100) ?
Hab meine Antwort oben nochmal editiert, bevor ich die Frage gesehen habe. Problem ist, das empfänger.Faktor falsch berechnet wird.
Hab ich angenommen, deswegne die 2te antwort
Es kann einiges falsch sein, deswegen mein vorschlag mit einer trivialen testszene, das kann ihm beim bug suchen helfen.
-
ach ja
if (patch.IsLightSource && patch.IsInSpotDirection(otherPatch.CenterOfGravity) == false) continue; //Der andere liegt außerhalb meiens Spotcutoff
var point = this.intersectionFinder.GetIntersectionPoint(ray, patch, 0);
if (point == null || point.IntersectedObject != otherPatch) continue; //Sichtbarkeitstestfloat lambda2 = point.Normale * (-ray.Direction);
if (lambda2 <= 0) continue;1. mach erst den lambda2 test, dann IsInSpot, dann intersection, das kann dir bis 50% rechenzeit sparen.
2. Speicher dir irgendwo als bitmaske die resultate der intersections ab.
3. n->Intersect->m ist wie m->Intersect->n, nochmal 50%
-
rapso schrieb:
XMAMan schrieb:
Die Energie schrumpft bei mir bei der Brdf.
im ersten post schriebst du die energie wird groesser. Schumpfen sollte es nirgendwo, sonst waere es falsch.
https://www.siggraph.org/education/materials/HyperGraph/radiosity/images/slide13.jpgMit schrumpfen wollte ich mich lediglich auf deine Feststellung beziehen, dass die Energie doch endlos wachsen müsste, wenn ich immer nur drauf addiere.
Ohne den Magic-Abstandfaktor von 0.01 Wächst die Gesamtenergie bei der Raumszene. Bei der Cornellbox passiert das nicht.
-
rapso schrieb:
ach ja
if (patch.IsLightSource && patch.IsInSpotDirection(otherPatch.CenterOfGravity) == false) continue; //Der andere liegt außerhalb meiens Spotcutoff
var point = this.intersectionFinder.GetIntersectionPoint(ray, patch, 0);
if (point == null || point.IntersectedObject != otherPatch) continue; //Sichtbarkeitstestfloat lambda2 = point.Normale * (-ray.Direction);
if (lambda2 <= 0) continue;1. mach erst den lambda2 test, dann IsInSpot, dann intersection, das kann dir bis 50% rechenzeit sparen.
2. Speicher dir irgendwo als bitmaske die resultate der intersections ab.
3. n->Intersect->m ist wie m->Intersect->n, nochmal 50%Ich hatte den Lambda2-Test ja ursprünglich auch davor. Dummerweise zeigen die Normalen bei manchen Objekten in die falsche Richtung. Ich müsste also entweder im Blender das jetzt korrigieren oder ich lass das durch mein Raytracer gerade stellen.
Das mit der Bitmaske stell ich mir schwer vor, das das ja eine N*N-Matrix sein muss. Ich arbeite mit mehreren Threads wärend der Formfaktor-Berechnung und kann somit nicht gleichzeitig auf ein Patch schreiben zugreifen.
Hätte ich so eine Matrix, dann wäre das Threadsicher aber sie wäre bei 10.000 Objekten (So viele Patches enthält die Szene) dann ja 10^8 * 4 Byte groß
Die letzten beiden Reihen wurden mit Radiosity berechnet. Dort verwende ich momentan diesen 0.01-Faktor bei SolidAngle.
Dort will ich diesen Faktor weggekommen, da er falsch ist.
-
XMAMan schrieb:
Ich hatte den Lambda2-Test ja ursprünglich auch davor. Dummerweise zeigen die Normalen bei manchen Objekten in die falsche Richtung. Ich müsste also entweder im Blender das jetzt korrigieren oder ich lass das durch mein Raytracer gerade stellen.
bei scenen mit richtigen normalen sind die berechnungen richtig, bei scenen mit falschen sind sie falsch? vielleicht haengt das zusammen.
du kannst die normalen beim laden selbst errechnen (brauchst ja eh nur face normalen, keine per-vertex). vergiss nicht zu normalisieren
Das mit der Bitmaske stell ich mir schwer vor, das das ja eine N*N-Matrix sein muss. Ich arbeite mit mehreren Threads wärend der Formfaktor-Berechnung und kann somit nicht gleichzeitig auf ein Patch schreiben zugreifen.
es arbeitet doch hoffentlich immer nur ein thread auf einem patch, oder? von daher kannst du auch pro patch eine zeile der matrix beschreiben.
Hätte ich so eine Matrix, dann wäre das Threadsicher aber sie wäre bei 10.000 Objekten (So viele Patches enthält die Szene) dann ja 10^8 * 4 Byte groß
10^8 / 8 (du brauchst ja nur ein bit, erstmal). 12MB oder so.
[quote]
Die letzten beiden Reihen wurden mit Radiosity berechnet. Dort verwende ich momentan diesen 0.01-Faktor bei SolidAngle.
Dort will ich diesen Faktor weggekommen, da er falsch ist.
wie schaut es ohne den faktor aus? ist es im ganzen heller, oder nur an kanten?
-
[quote="rapso"]
XMAMan schrieb:
wie schaut es ohne den faktor aus? ist es im ganzen heller, oder nur an kanten?
Es sieht nach 6 Beleuchtungsschritten so auss:
Nach 8 Beleuchtungsschritten fängt dann langsam die ganze Szene an immer heller zu werden (wie so ein glühen), bis es dann ins komplette Weiss übergeht.
Jetzt gerade für das GesamtTestBild verwende ich 20 Schritte.
Kann Blender aber auch wissen, welche seite Außen und welche innen liegt? Ich lasse mir von Blender eine Liste von Dreiecken berechnen und berechne mir die Normale dann selber. Dummerweise erzeugt es mir z.B. beim Tisch immer die Normalen falsch herrum obwohl sie laut Blender-ANzeige nach außen zeigen müssten. Deswegen habe ich dann irgendwann mal gesagt, dass ich dir mir selber zurecht drehe über den Schnittpunkttest.
Auf ein Patch arbeitet immer nur ein Thread schreibend. Wenn also jedes Patch seine eigene ViewBitmask hat, dann würde das schon gehen. Nur nur wenn ich Patch i sage, dass ich Patch j sehen kann, dann müsste ja der Thread, der dann Patch j bearbeitet dann bei i schauen und feststellen, das i bereits j sieht. Je nachdem zu welchen Zeitpunkt j diese Abfrage macht, wird er dann feststellen, dass i j sieht oder nicht. Außerdem weiß ich immer noch nicht, wie diese Bitmaske aussehen soll, so dass schreiben und lesen zugleich möglich ist. Hat jedes Patch ein Fixes Array, wo jedes Bit in dem Array dann auf alle Patches in der Szene verweist?
-
[quote="XMAMan"]
rapso schrieb:
XMAMan schrieb:
wie schaut es ohne den faktor aus? ist es im ganzen heller, oder nur an kanten?
Es sieht nach 6 Beleuchtungsschritten so auss:
Nach 8 Beleuchtungsschritten fängt dann langsam die ganze Szene an immer heller zu werden (wie so ein glühen), bis es dann ins komplette Weiss übergeht.
kann es sein dass da irgendwas anderes schiefgeht. z.b. schaut der fuss vom schrank an der rechten seite ganz weiss aus, das sollte nicht sein.
Kann Blender aber auch wissen, welche seite Außen und welche innen liegt? Ich lasse mir von Blender eine Liste von Dreiecken berechnen und berechne mir die Normale dann selber. Dummerweise erzeugt es mir z.B. beim Tisch immer die Normalen falsch herrum obwohl sie laut Blender-ANzeige nach außen zeigen müssten. Deswegen habe ich dann irgendwann mal gesagt, dass ich dir mir selber zurecht drehe über den Schnittpunkttest.
ich kenne mich mit blender nicht aus, aber es waere wirklich gut nur mit scenen zu testen, bei denen du dir sicher bist, dass die gut sind, um auszuschliessen dass du im code geister jagst, waehrend es nur kaputte geometrie ist.
Auf ein Patch arbeitet immer nur ein Thread schreibend. Wenn also jedes Patch seine eigene ViewBitmask hat, dann würde das schon gehen. Nur nur wenn ich Patch i sage, dass ich Patch j sehen kann, dann müsste ja der Thread, der dann Patch j bearbeitet dann bei i schauen und feststellen, das i bereits j sieht. Je nachdem zu welchen Zeitpunkt j diese Abfrage macht, wird er dann feststellen, dass i j sieht oder nicht. Außerdem weiß ich immer noch nicht, wie diese Bitmaske aussehen soll, so dass schreiben und lesen zugleich möglich ist. Hat jedes Patch ein Fixes Array, wo jedes Bit in dem Array dann auf alle Patches in der Szene verweist?
zum erstellen des arrays:
for(i=1;i<count;i++) for(j=i+1;j<count;j++) { bool hit= lambda0>0&&lambda1>0&&InSpot(..)&&Intersect(..); HitArray[i+j*count]=HitArray[j+i*count]=hit; }
beim evaluieren musst du nur noch if(HitArray...) machen, brauchst kein lambda usw. test, da das ins array eingeflossen ist.
das beispiel oben ist nur byte weise, wenn du bitweise moechtest und threadsafe, sollte jeder thread 8 patches am stueck machen, sodass jeder thread sein eigenes byte beschreibt.
-
Es klingt jetzt vielleicht etwas peinlich aber es lag wirklich nur daran, dass bei mir nicht alle Normalen nach außen gezeigt haben. Ich habe jetzt im Blender die Sache teilweise korrigiert und nun funktioniert mein Algorithmus ganz ohne die Distanz-Abfrage für ein Teil des Bildes. Das ganze Bild bekomme ich aufgrund des Normalenfehler noch nicht hin. Das blöde ist echt, dass die Blenderversion, die ich verwende bei der Normalenberechnung viele Fehler macht. Lasse ich mir die Normalen anzeigen, dann zeigen sie alle nach außen. Schaue ich bei mir im Raytracer die Normalen an, dann zeigen sie Teilweise für manche Flächen wieder in die andere Richtung. Vielleicht liegt mein Fehler ja darin, dass ich mir die Normalen selber über die Dreiecksposition berechne. Ich lass die mir mal mitausgeben und drehe dann die Dreickskoordianten entsprechend im oder gegen den Uhrzeigersinn.
Außerdem habe ich für die viewMatrix ein Zweidimmensionales enum-Array verwendet. Ich bin mir jetzt nicht sicher, ob das für Rapso so ok ist^^
private enum VisibleValue { NotSet, Visible, NotVisible }; private VisibleValue[,] visibleMatrix; this.visibleMatrix = new VisibleValue[patches.Count, patches.Count]; int index1 = this.patches.IndexOf(patch); int index2 = this.patches.IndexOf(otherPatch); if (this.visibleMatrix[index1, index2] == VisibleValue.NotVisible) continue; if (this.visibleMatrix[index1, index2] == VisibleValue.NotSet) { var point = this.intersectionFinder.GetIntersectionPoint(ray, patch, 0); VisibleValue visibleTest = VisibleValue.Visible; if (point == null || point.IntersectedObject != otherPatch) visibleTest = VisibleValue.NotVisible; //Sichtbarkeitstest this.visibleMatrix[index1, index2] = visibleTest; this.visibleMatrix[index2, index1] = visibleTest; if (visibleTest == VisibleValue.NotVisible) continue; }
Damit ist die Berechnung um 35% schneller.
@edit:
Die Ausgabe der Normalen klappt leider auch nicht. Sie zeigen trotzdem in die falsche Richtung. Ich werde es mal mit einer anderen Blenderversion probieren müssen.
-
XMAMan schrieb:
Es klingt jetzt vielleicht etwas peinlich aber es lag wirklich nur daran, dass bei mir nicht alle Normalen nach außen gezeigt haben.
Das ist nicht peinlich, es ist immer gut den grund zu finden bzw zu verstehen, bevor man magic anwendet (esseiden die zeit ist zu knapp).
Ich habe jetzt im Blender die Sache teilweise korrigiert und nun funktioniert mein Algorithmus ganz ohne die Distanz-Abfrage für ein Teil des Bildes. Das ganze Bild bekomme ich aufgrund des Normalenfehler noch nicht hin. Das blöde ist echt, dass die Blenderversion, die ich verwende bei der Normalenberechnung viele Fehler macht. Lasse ich mir die Normalen anzeigen, dann zeigen sie alle nach außen. Schaue ich bei mir im Raytracer die Normalen an, dann zeigen sie Teilweise für manche Flächen wieder in die andere Richtung. Vielleicht liegt mein Fehler ja darin, dass ich mir die Normalen selber über die Dreiecksposition berechne. Ich lass die mir mal mitausgeben und drehe dann die Dreickskoordianten entsprechend im oder gegen den Uhrzeigersinn.
Es muss nicht direkt an blender liegen, manchmal sind nur die expoerter (und manchmal importer :P) fehlerhaft. schau dir die Scene in einem anderen tool als referenz an, damit du weisst ob der bug wirklich in blender ist, oder bei dir.
Außerdem habe ich für die viewMatrix ein Zweidimmensionales enum-Array verwendet. Ich bin mir jetzt nicht sicher, ob das für Rapso so ok ist^^
private enum VisibleValue { NotSet, Visible, NotVisible }; private VisibleValue[,] visibleMatrix; this.visibleMatrix = new VisibleValue[patches.Count, patches.Count]; int index1 = this.patches.IndexOf(patch); int index2 = this.patches.IndexOf(otherPatch); if (this.visibleMatrix[index1, index2] == VisibleValue.NotVisible) continue; if (this.visibleMatrix[index1, index2] == VisibleValue.NotSet) { var point = this.intersectionFinder.GetIntersectionPoint(ray, patch, 0); VisibleValue visibleTest = VisibleValue.Visible; if (point == null || point.IntersectedObject != otherPatch) visibleTest = VisibleValue.NotVisible; //Sichtbarkeitstest this.visibleMatrix[index1, index2] = visibleTest; this.visibleMatrix[index2, index1] = visibleTest; if (visibleTest == VisibleValue.NotVisible) continue; }
Damit ist die Berechnung um 35% schneller.
Mein Punkt war, dass du diese matrix abspeichern kannst. Der test ist vermutlich 99% der laufzeitkosten und solange die geometrie sich nicht aendert, bleibt die matrix gleich, also kannst du sie von der platte laden.
Die Ausgabe der Normalen klappt leider auch nicht. Sie zeigen trotzdem in die falsche Richtung. Ich werde es mal mit einer anderen Blenderversion probieren müssen.
ist das ein bekannter blender bug? eventuell liegt es ja nicht an blender.
-
Ich muss mich doch nochmal zu dem Thema zu Wort melden^^
Das Problem lag doch nicht an den Normalen. Ich habe mit Blender hier und da einzelnen Flächen mal so und mal so gedreht mit der Hoffnung, dass nun endlich der Blender-Exporter eine Datei erzeugt, wo alle Normalen nach außen zeigen. Dadurch ist es mir dann durch Zufall gelungen genau die beiden Patches, welche ein ganz geringen Abstand zueinander haben so zu drehen, dass sie voneinander wegzeigen.
Aber...
camper hatte ganz am Anfang der Diskusion noch ein wichtigen Punkt genannt, welchen ich nun nochmal aufgegriffen habe. Er sagte, dass wenn ich zwei große Flächen nah zueinander stelle, dann ist die Formel der Geometryterm-Berechnung von den Patchmittelpunkten zu ungenau. Er hatte recht damit.
Ich habe das jetzt so gemacht, dass wenn das Verhältnis zwischen Patch-Oberfläche zu Patch-Quadratdistanz einen bestimmten (Fehler)Wert überschreitet, dann verwende ich für die FormFaktor-Berechnung eine genauere Lösung. Da ich nicht genau wußte, wie man das Integral auf dem Papier lößt, habe ich es numerisch per Monte CarloIntegration gelößt. Es funktioniert sehr gut und das Bild sieht mit dieser Funktion nun so aus:
https://picload.org/view/rwgwolgw/ausgabe3.png.html
private void AddAllViewFaktorsWithSolidAngle(IPatch patch, Random rand) { foreach (var otherPatch in this.patches) { if (patch == otherPatch) continue; //Keine Beleuchtung mit sich selbst if (otherPatch.IsLightSource) continue; //Lichtquellen dürfen nicht beleuchtet werden float distanceSqrt = (patch.CenterOfGravity - otherPatch.CenterOfGravity).QuadratBetrag(); //if (distanceSqrt <= 0.01f) continue; //Wenn der Abstand zwischen zwei Objekten zu gering ist, dann erhält man ein hohen ViewFaktor (Zahl >> 10), was dann dazu führt, dass mit jeden Beleuchtungsstep die Lichtenergie immer mehr wird Ray ray = new Ray(patch.CenterOfGravity, Vektor.Normiere(otherPatch.CenterOfGravity - patch.CenterOfGravity)); float lambda1 = patch.Normale * ray.Direction; if (lambda1 <= 0) continue; float lambda2 = otherPatch.Normale * (-ray.Direction); if (lambda2 <= 0) continue; if (patch.IsLightSource && patch.IsInSpotDirection(otherPatch.CenterOfGravity) == false) continue; //Der andere liegt außerhalb meiens Spotcutoff int index1 = this.patches.IndexOf(patch); int index2 = this.patches.IndexOf(otherPatch); if (this.visibleMatrix[index1, index2] == VisibleValue.NotVisible) continue; if (this.visibleMatrix[index1, index2] == VisibleValue.NotSet) { var point = this.intersectionFinder.GetIntersectionPoint(ray, patch, 0); VisibleValue visibleTest = VisibleValue.Visible; if (point == null || point.IntersectedObject != otherPatch) visibleTest = VisibleValue.NotVisible; //Sichtbarkeitstest this.visibleMatrix[index1, index2] = visibleTest; this.visibleMatrix[index2, index1] = visibleTest; if (visibleTest == VisibleValue.NotVisible) continue; //float lambda2 = point.Normale * (-ray.Direction); //if (lambda2 <= 0) continue; } float geometryTerm = lambda1 * lambda2 / distanceSqrt; float viewFactor = 1; //Diese Zahl soll später mal mit ein Rasterizer berechnet werden float formFaktorErrorValue = (patch.SurvaceArea + otherPatch.SurvaceArea) / distanceSqrt; float formFaktor; if (formFaktorErrorValue > 10) //Die 10 hängt von der Anzahl der Beleuchtungsschritte und der MaxSurfaceAreaPerPatch ab. Um so mehr Beleuchtungsschritte oder um so größer die MaxSurfaceAreaPerPatch ist, um so kleiner muss diese Zahl hier sein { formFaktor = GetFormfaktor(patch, otherPatch, rand); //Berechnet den Formfaktor genau, wenn eine Näherungslösung zu ungenau wird } else { formFaktor = geometryTerm * viewFactor * patch.SurvaceArea * otherPatch.SurvaceArea; //Das ist nur eine Näherungslösung } patch.AddViewFaktor(new ViewFaktor() { Patch = otherPatch, FormFaktor = formFaktor }); } } //Berechnet numerisch das Doppelintegral, wo über alle alle Punkte aus Patch1 und Patch2 gegangen wird, und jeweils der GeometryTerm für dA1 udn dA2 berechnet wird //Der FormFaktor, welcher hier beschrieben ist: https://de.wikipedia.org/wiki/Radiosity_(Computergrafik) enthält noch zusätzlich den VisibleTerm und / PI (Brdf) //Brdf gehört für mich nicht zu diesen Term, da er sich nicht direkt auf die Strecke zwischen zwei Patches bezieht sondern auf ein Patch (Pfadumknickpunkt) //VisibleTerm lasse ich aus Performancegründen weg private float GetFormfaktor(IPatch patch1, IPatch patch2, Random rand) { int sampleCount = 100; float geometryTermSum = 0; for (int i = 0; i < sampleCount; i++) { var point1 = patch1.GetRandomPointOnSurvace(rand); var point2 = patch2.GetRandomPointOnSurvace(rand); Vektor direction = point2.Position - point1.Position; float sqrtLength = direction.QuadratBetrag(); direction /= (float)Math.Sqrt(sqrtLength); float lambda1 = patch1.Normale * direction; float lambda2 = patch2.Normale * (-direction); float geometryTermEstimation = lambda1 * lambda2 / sqrtLength * patch1.SurvaceArea * patch2.SurvaceArea; geometryTermSum += geometryTermEstimation; } return geometryTermSum / sampleCount; }
Das Problem mit Blender habe ich jetzt noch nicht lösen können. Ich habe gestern die neuste Blenderversion installiert und der Wavefront(obj)-Exporter erzeugt weiterhin falsche Normalen. Das komische ist, dass er es nur für manche Objekte falsch macht. Die Lampen sind ok. Der Tisch oder der Schrank nicht. Dort muss ich die Normalen nach Innen zeigen lassen, damit sie im Export nach außen zeigen.
Ich werde versuchen mithilfe von ein globalen Beleuchtungsalgorithmus mir die 'wahren' Normalenrichtungen bestimmen zu lassen, um somit die fehlerhafte OBJ-Datei zu korrigieren.
-
Haette nicht gedacht, dass deine patches schon zu gross sind, aber da hatte camper ein gutes gespuer.
Wenn du soeinen fehler hast, ist eine andere integration nicht immer die beste loesung, da die patches dann weiterhin zu gross sind, du somit einem "mittelwert" hast, statt eine varianz ueber das ganze patch (du sendest also vielleicht weiterhin nicht die richtige menge energie an andere patches). Es ist deswegen gaengig die patches adaptiv zu tesselieren.
http://www.cs.utah.edu/~schmelze/radiosity/hw2/meshl1_lo.jpg
nicht nur wegen distanz, sondern auch bei varianz:
https://classes.soe.ucsc.edu/cmps161/Winter04/projects/aames/images/screen4.jpg
-
rapso schrieb:
Wenn du soeinen fehler hast, ist eine andere integration nicht immer die beste loesung, da die patches dann weiterhin zu gross sind, du somit einem "mittelwert" hast, statt eine varianz ueber das ganze patch (du sendest also vielleicht weiterhin nicht die richtige menge energie an andere patches).
Dieser Mittelwert konvergiert doch aber gegen den perfekten FormFaktor-Wert. Ich verwende hier jetzt zwar nur 100 Samples, aber um so höher die Zahl ist, um so mehr müsste es doch passen.
Um das Integral zu berechnen, nutze ich folgende Formel:
⟨FN⟩=1N∑i=0N−1f(Xi)pdf(Xi).
Jedes Sample berechnet den GeometryTerm zwischen den Differentialflächen dA1 und dA2. Die Wahrscheinlichkeitsdichte (Pdf A), dass ich einen von diesen Punkten generiere ist 1 / SurfaceArea. Wenn ich dann den GeometryTerm mit der PdfA diffidiere, dann ist dass das gleich wie die Multiplikation mit Patch-SurfaceArea.
Die Formel sieht jetzt erstmal genau so aus wie die Näherungsformel oben, aber es sind zweich verschiedene Sachen.
Hier wird ein bisschen auf das Thema eingegangen, wenn du es näher wissen willst:
http://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing
Die Idee mit den adaptivren anpassen der Patchgröße habe ich woanders auch schon gesehen. Die Sache ist, ich will jetzt nicht mit Radiosity versuchen gegen mein Pathtracer oder andere Distributet Raytracing-Algorithmen anzukommen. Dafür ist Radiosity einfach zu schlecht. Mir ging es eher darum die Basis-Variante zu machen und zu akzeptieren, dass ich mir der begrenzten Patch-Größe eben auch nur so Mindcraft-Mäßige Bilder erzeugen kann. Ich find das so ok.
Bildfehler aufgrund von falschen Formfaktoren sind nicht ok. Pixeliges außsehen aufgrund der Patches ist ok.
-
XMAMan schrieb:
rapso schrieb:
Wenn du soeinen fehler hast, ist eine andere integration nicht immer die beste loesung, da die patches dann weiterhin zu gross sind, du somit einem "mittelwert" hast, statt eine varianz ueber das ganze patch (du sendest also vielleicht weiterhin nicht die richtige menge energie an andere patches).
Dieser Mittelwert konvergiert doch aber gegen den perfekten FormFaktor-Wert. Ich verwende hier jetzt zwar nur 100 Samples, aber um so höher die Zahl ist, um so mehr müsste es doch passen.
es konvergiert gegen den durchschnittswert, nicht gegen den perfekten wert, denn diesen einen wert gibt es eventuell nicht. Wenn z.b. 50% vom Patch direktes licht bekommt, 50% im schatten wird, wird das patch "grau".
Was erstmal "ok" klingt, du musst aber beachten, dass das patch wieder benutzt wird um fuer andere patches die energie einzuschaetzen, wenn also in einem bereich wo 100% reflektiert werden sollte nur 50% der energie weitergetragen wird, im schattenbereich wo 0% reflektiert werden sollte auch 50% weitergetragen wird, bekommst du eine falsche ausleuchtung.Die tesselierung wird also nicht (nur) dem eigentlichen patch "zuliebe", sondern all den verbundenen patches "zuliebe" gemacht.
Die Sache ist, ich will jetzt nicht mit Radiosity versuchen gegen mein Pathtracer oder andere Distributet Raytracing-Algorithmen anzukommen. Dafür ist Radiosity einfach zu schlecht. Mir ging es eher darum die Basis-Variante zu machen und zu akzeptieren, dass ich mir der begrenzten Patch-Größe eben auch nur so Mindcraft-Mäßige Bilder erzeugen kann. Ich find das so ok.
Bildfehler aufgrund von falschen Formfaktoren sind nicht ok. Pixeliges außsehen aufgrund der Patches ist ok.
Radiosity wird, bzw wurde oft verwendet um daraus das eigentlich nuetzliche zu errechnen. Du kannst z.B. eine lightmap erstellen (indem du die patches direkt einzeichnest, oder eine art "final gathering" per texel in die radiosity patche traced). Das kannst du abspeichern und hast relativ echt beleuchtete echtzeit szenen.
Du kennst sicher:
http://i39.tinypic.com/11sgq39.jpg
https://image.slidesharecdn.com/henrikgdc09-compat-100210170437-phpapp01/95/the-unique-lighting-of-mirrors-edge-41-728.jpg?cb=1265822373
http://imgur.com/oN5kPe3oder:
https://zigguratvertigodotcom.files.wordpress.com/2015/11/giunity.png
-
Hättest du ein Paper / Internetlink den ich durcharbeiten kann, um das Radiosity so umzubauen, dass ich damit härtere Schattenkanten hinbekomme? Also dieses Unterteilen der Patches im Abhängigkeit vom Irradiance-Gradienten?
-
Hab kein speziellen paper dazu im kopf, koennte nur das auflisten was google ausspuckt.
ich denke die offensichtlichen methoden sind:
1. wie du es schon gemacht hast, ueber die min-distanz zu gehen, sodass die kantenlaenge * faktor < minDistanz ist. (natuerlich mit einem min-limit, damit bei sich beruehrenden/schneidenden patches es nicht zuweit geht.
2. alternativ koenntest du in der mitte und an den raendern der patches paar samples nehmen und wenn dort die energie zu sehr variiert, unterteilst du das patch.
3. oder evaluierst wie kontrastreich benachbarte patches sind nach einem gather step und unterteilst die, die sehr variieren