Verschwommene Reflexion



  • Hallo,

    ich arbeite an einem Raytracer und glänzende Reflexionen funktionieren schon ganz gut. Jetzt wollte ich einen Schritt weiter gehen und "verschwommene" Reflexionen machen (nicht diffus, immer noch specular). Ich habe mir so etwas vorgestellt:
    http://imgur.com/2rvutTp

    Meine Frage ist nun, was für eine Wahrscheinlichkeitsverteilung muss ich da nun nehmen? Median und Erwartungswert sollten gleich sein und er sollte beschränkbar sein (hier auf -90..90). Gauss schien mir unpassend, weil sich dieser über die ganze Zahlengerade ausdehnt. Wenn ich im Falle einer Übertretung einfach nochmals würfle, dann verschieben sich Median und Erwartungswert (insbesondere bei besonders flachen Winkeln).

    Gruss



  • asfdlol schrieb:

    Gauss schien mir unpassend, weil sich dieser über die ganze Zahlengerade ausdehnt. Wenn ich im Falle einer Übertretung einfach nochmals würfle, dann verschieben sich Median und Erwartungswert (insbesondere bei besonders flachen Winkeln).

    Mach doch einfach irgendwelche Spielereien mit dem Gauss. Etwas wie

    etan2(x)e^{-tan^2(x)}

    https://www.wolframalpha.com/input/?i=plot+exp(-tan(x)^2)+x%3D-pi%2F2..pi%2F2

    Der Link funktioniert leider nicht so ganz. Also muss man das wohl per Copy&Paste machen.

    ...muss natürlich noch normiert und mit irgendetwas wie einer Standardabweichung versehen werden.

    Die Werte jenseits von [-pi/2,pi/2] sollen natürlich 0 sein.



  • wäre die spiegelnde Komponente wie im Phong-Beleuchtungsmodell vielleicht was für dich?
    Genau so wird das nämlich in der Computergraphik auch gemacht, vielleicht bietet sich das für deinen Fall auch an.
    https://de.wikipedia.org/wiki/Phong-Beleuchtungsmodell

    Du hast im Prinzip das Skalarprodukt zwischen zwei Vektoren zur Potenz x, welche angibt, wie stark der Glanzfleck "verschmiert" werden soll: max(0, (R*V)^x)
    Hat den Vorteil dass das Skalarprodukt eine ziemlich billige Operation ist.

    Entweder du verteilst die reflektierenden Strahlen gleich über alle Raumwinkel und skalierst nur deren Energie, oder aber du machst Strahlen gleicher Stärke, welche allerdings nach oben angegebener Formel verteilt sind.



  • Phong schrieb:

    Entweder du verteilst die reflektierenden Strahlen gleich über alle Raumwinkel und skalierst nur deren Energie, oder aber du machst Strahlen gleicher Stärke, welche allerdings nach oben angegebener Formel verteilt sind.

    Ich habe inzwischen beide Methoden einmal implementiert, dabei bin ich nach dem Schema mit der Energie vorgegangen. Ich habe die Strahlen zufällig verteilt nach einer perfekten diffusen Reflexion und dann das Skalarprodukt berechnet und kurz in die entsprechende Formel eingesetzt. Zwar war das einfach zu implementieren, hatte jedoch den Nachteil, dass es nur sehr langsam konvergiert.

    Dann wollte ich die andere Methode umsetzen. Jedoch braucht man, soviel ich weiss, für eine Zufallsverteilung das Integral der Funktion. Jedoch habe ich weder für abs(exp(-tan(x)^2))^ γ noch für cos(x)^ γ die Stammfunktion herausgefunden. Gäbe es ohne diese auch eine Möglichkeit, Zahlen demnach zu verteilen?

    Für das Phong-Modell habe ich eine Alternative zusammengebastelt, die zwar wesentlich schneller konvergiert als die Energie-Methode, aber immer noch nur halb so schnell wie eine Lambertsche Oberfläche (für die ich gemütlich ohne Umwege mit einer Linearkombination generieren kann).

    So sieht die "Notlösung" für die Phong-Verteilung aus:

    Vector3 Specular = Incidence - (2 * Normal.dot(Incidence)) * Normal;
    
    			static std::uniform_real_distribution<RealT> DotDistribution(0, 1);
    			static std::uniform_real_distribution<RealT> CircleDistribution(0, TwoPi);
    
    			RealT RandomDot = Root(DotDistribution(Generator), Gamma);
    			AngleT CircleAngle(ArcCos(RandomDot));
    			Vector3 Axis = Normal.cross(Specular).normalized();
    			Vector3 OnCircle = MakeRotation(CircleAngle, Axis) * Specular; // MakeRotation gibt eine 3x3 Matrix zurück => teuer!
    
    			do
    			{
    				Result.Direction = MakeRotation(AngleT(CircleDistribution(Generator)), Specular) * OnCircle;
    			}
    			while(InteriorAngle(Normal, Result.Direction) > AngleT::RightAngle());
    
    			Result.Origin = IntersectionPoint + Result.Direction * RealTEps;
    

    Und das Resultat für ein Gamma von 250:
    http://i.cubeupload.com/9rclzv.png

    Meine Frage:
    Ich habe ein orthogonales Koordinatensystem, den Einfallswinkel, den idealen Ausfallswinkel und γ gegeben, wie kann ich Strahlen (die diese Verteilung befolgen, natürlich) generieren ohne Rotationsmatrizen zu verwenden?

    Danke euch beiden schonmal und Gruss


Log in to reply