Radiosity - Die Lichtenergie gerät bei zu geringen Abstand aus dem Ruder



  • Meine Idee wie man das machen könnte war bis jetzt die, dass ich zuerst mit normalen Raytracing und LightSourcesampling das direkte Licht für jeden Punkt, den der Primärstrahl sieht, berechne, um somit zu sehen, wo Schatten/Halbschatten oder keine Schatten sind.

    In den Halbschatten unterteile ich dann genauer.

    Nachteil von den Verfahren: Ich habe nur für den Kamera-Punkt die Patches genau unerteilt, wo ich halt wärend des Schattenberechnes die Kamera stehen habe. Wenn hinter mir Schatten sind, und ich will nach dem Radiosity mich in der Szene frei bewegen können, dann wäre das schlecht.

    Zweite Idee: Ich unterteile die Szene erstmal grob in Patches. Für jedes Patch berechne ich an N zufällig gewählten Punkten die DirectLighting-Berechnung, wie es schon bei Idee 1 gemacht wird nur dass ich hier keine Kamera brauche. Ändert sich die Irradiance über alle N Punkte stark, dann wird das Patch rekursiv erneut so lange unterteil, bis die Änderungsrate zwischen den N Punkten unter ein Schwellwert fällt.

    Was hällst du von den Ideen?


  • Mod

    wenn du "zufall" nimmst, wirst du eine streuung haben und die kann deine entscheidungsfindung beeinflussen, ob du patches teilen solltest.
    Du kannst eher als 4 subpatches ansehen und zu den zufaellig gewaehlten flaechen tracen, wenn die 4 dann variieren, nimmst du die tesselierung wirklich vor. (da ist auch noch streuung, aber die 4 sub-patches haben wenigstens eine relativ gleiche randomization.)

    am ende wirst du wohl 10 versionen ausprobieren muessen bis du weisst, welche, wann gut ist. vermutlich musst du dann 2 oder 3 quellen fuer die entscheidungsfindung nehmen und sie gewichten.



  • Momentan ist mein Algorithmus so:

    Ich suche erst die Patches raus, welche im Halbschatten liegen. Dazu bestimme ich für zufällige Punkte auf dem Patch, wie viel Prozent aller Schattenstrahltests erfolgreich sind. Ist es 0 oder 100%, dann liegt das Objekt nicht im Halbschatten. Ansonsten ja.

    Dann berechen ich die Varianz über die Irradiance von diesen Punkten. Ist sie größer als 1, unterteile ich mehr.

    Bei den Patches unter dem Stuhl sieht man, dass sie etwas kleiner sind, als z.B. an den Wänden.

    https://img1.picload.org/image/rwdcrwwa/ausgabe.png

    Das Bild ist etwas besser dadurch aber den Schatten vom Stuhlbein bekomme ich trotzdem noch nicht hin, da auch Bildstellen für weitere Unterteilungen markiert werden, die eigentlich ok aussehen. Ich habe aber nur eine begrenzte Anzahl an Patches, die ich erzeugen kann. Deswegen bleibt dann nicht genug Speicher übrig, um den Stuhlbeinschatten schön darzustellen.


  • Mod

    wie kommt das limit zustande?



  • Ich muss ja dann für jeden Patch zu jeden anderen Patch die FormFaktor berechne. Wärend er diese Berechnung macht, wächst der Speicher von den Prozess immer weiter an, da es so viele Patche sind. Wenn ich überhaupt keine feinere Unterteilung mache, dann erhalte ich ja schon 10.000 Patche. Untereile ich dann nochmal einige von den Patches auf ein Zentel von ihrer Größe, dann bekomme ich beim FormFaktor-Erstellen eine OutOfMemoryExcepiton.


  • Mod

    das ist natuerlich kein neues Problem, spare matrix

    Ein paar tricks sind:
    -jede Zeile Runlength encoden (da vieles 0 sein sollte), du arbeitest eh zeile fuer zeile ab. (ich empfehle 1 byte mit 4bit fuer wieviele 0 und 4bit fuer wieviele nicht-null folgen).
    -quantifizierung (du suchst pro zeile den maximaln float raus und teilst durch den, legst dann jeden einzelwert als 0-255 oder 0-65525 ab)
    -clustering: du merkst dir beim teilen der patches welche zusammengehoeren, wenn du dann dir formfaktoren errechnest (von anderen patches zu dem zerteilten) und die variieren nicht, legst du nur den wert zum haupt-patch ab.



  • rapso schrieb:

    das ist natuerlich kein neues Problem, spare matrix

    Ein paar tricks sind:
    -jede Zeile Runlength encoden (da vieles 0 sein sollte), du arbeitest eh zeile fuer zeile ab. (ich empfehle 1 byte mit 4bit fuer wieviele 0 und 4bit fuer wieviele nicht-null folgen).
    -quantifizierung (du suchst pro zeile den maximaln float raus und teilst durch den, legst dann jeden einzelwert als 0-255 oder 0-65525 ab)
    -clustering: du merkst dir beim teilen der patches welche zusammengehoeren, wenn du dann dir formfaktoren errechnest (von anderen patches zu dem zerteilten) und die variieren nicht, legst du nur den wert zum haupt-patch ab.

    Also ich speichere die Formfaktoren ja nicht in einer 2D-Matrix sondern jetztes Patch besitzt eine Liste von FormFaktoren:

    class Patch
    {
     public List<ViewFaktor> ViewFaktors { get; private set; }
    }
    
    class ViewFaktor
        {
            public Patch Patch;
            public float FormFaktor;
        }
    

    In dieser Liste werden ja nur die ViewFaktor-Objekte gespeichert, wo der FormFaktor-Wert größer null ist. Ich verstehe jetzt also nicht, inwiefern mir die SpareMatrix-Sache hier weiter helfen kann.

    Ich selbst sehe nur eine sinnvolle Lösung: Ich muss die Patches, welche ich weiter untereile weiter einschränken. Momentan sind es noch immer zu viele. Mich interessieren ja nur die Bereiche, wo es Schattenkanten zu sehen gibt.


  • Mod

    Wieviel speicher kostet eine "verbindung" bei dir genau?



  • C# hat für Datentypen, dass Speicher vom GC verwaltet wird anscheinend kein sizeof-Operator. Wenn ich die Klasse serialisiere, dann erhalte ich 168 Byte. Vermutlich hat er die Patch-Klasse mit serialisiert obwohl sie ein Null-Pointer ist.

    long size = 0;
                object o = new ViewFaktor();
                using (System.IO.Stream s = new System.IO.MemoryStream())
                {
                    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                    formatter.Serialize(s, o);
                    size = s.Length; //->Hier sagt der Debugger 168 
                }
    

    Mein zweiter Weg war über die GC.GetTotalMemmory-Funktion.

    long s1 = GC.GetTotalMemory(false);
                ViewFaktor v = new ViewFaktor();
                string s5 = v.GetType().ToString();
                long s2 = GC.GetTotalMemory(false);
                long s3 = s2 - s1; //-> Hier sagt er 0 Byte
                string s4 = s1.ToString() + s2.ToString() + s3.ToString() + v.ToString() + s5;
    

    Dabei kommt 0 Byte raus.

    Das heißt meine Klasse brauch so zwischen 0 und 168 Byte^^ Das ist so peinlich, dass C# mit dieser simplen Sache überfordert ist.

    Laut meiner Schätzung dürften es 8 Byte sein. Aber zwischen den einzelnen Memberm können noch speicherlöcher sein, so dass die Klasse gut auch doppelt so groß sein kann. Ich weiß es halt nicht genau.

    Mit

    System.Runtime.InteropServices.Marshal.SizeOf(typeof(ViewFaktor));
    

    habe ich es übrigens auch schon versucht und bekomme da nur eine Execption, da das eine Manged-Class- ist.



  • vielleicht kannst du eine million verbindungen allokieren, so wie du es normalerweise machst, und die differenz aus vorher/nachher nehmen, notfalls im taskmanager.

    mit einer matrix solltest du auf etwa 4-5byte pro verbindung kommen (RLE komprimiert).


Anmelden zum Antworten