2014-11-04 9 views
6

Ich schreibe einen Ray Tracer. Bisher habe ich diffuse, Blinn-Beleuchtung und Reflexionen. Irgendetwas ist mit meinen Brechungen falsch gelaufen und ich habe keine Ahnung was. Ich hoffe, dass mir jemand helfen kann. enter image description hereRay Tracing - Refraktion Bug

Ich habe eine große rote diffuse + Blinn Kugel und eine kleine refraktive mit einem Brechungsindex n = 1,5.

Der Kleine ist einfach nur vermasselt.

Relevante Code:

ReflectiveSurface::ReflectiveSurface(const Color& _n, const Color& _k) : 
F0(Color(((_n - 1)*(_n - 1) + _k * _k)/((_n + 1)*(_n + 1) + _k * _k))) {} 

Color ReflectiveSurface::F(const Point& N, const Point& V) const { 
    float cosa = fabs(N * V); 
    return F0 + (F0 * (-1) + 1) * pow(1 - cosa, 5); 
} 

Color ReflectiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const { 
    Point reflectedDir = reflect(incidence.normal, incidence.direction); 
    Ray ray = Ray(incidence.point + reflectedDir * epsilon, reflectedDir); 
    return F(incidence.normal, incidence.direction) * scene.rayTrace(ray, traceDepth + 1); 
} 

Point ReflectiveSurface::reflect(const Point& N, const Point& V) const { 
    return V - N * (2 * (N * V)); 
} 

bool RefractiveSurface::refractionDir(Point& T, Point& N, const Point& V) const { 
    float cosa = -(N * V), cn = n; 
    if (cosa < 0) { cosa = -cosa; N = N * (-1); cn = 1/n; } 
    float disc = 1 - (1 - cosa * cosa)/cn/cn; 
    if (disc < 0) return false; 
    T = V/cn + N * (cosa/cn - sqrt(disc)); 
    return true; 
} 

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) : ReflectiveSurface(Color(1, 1, 1) * _n, _k) {} 

Surface* RefractiveSurface::copy() { return new RefractiveSurface(*this); } 

Color RefractiveSurface::getColor(const Incidence& incidence, const Scene& scene, int traceDepth) const { 
    Incidence I = Incidence(incidence); 
    Color reflectedColor, refractedColor; 
    Point direction = reflect(I.normal, I.direction); 
    Ray reflectedRay = Ray(I.point + direction * epsilon, direction); 
    if (refractionDir(direction, I.normal, I.direction)) { 
     Ray refractedRay = Ray(I.point + direction * epsilon, direction); 
     Color colorF = F(I.normal, I.direction); 
     reflectedColor = colorF * scene.rayTrace(reflectedRay, traceDepth + 1); 
     refractedColor = (Color(1, 1, 1) - colorF) * scene.rayTrace(refractedRay, traceDepth + 1); 
    } 
    else { 
     reflectedColor = scene.rayTrace(reflectedRay, traceDepth + 1); 
    } 
    return reflectedColor + refractedColor; 
} 

Der Code ist ganz über den Platz, da dies eine Hausaufgabe und ich bin nicht zusätzliche Header enthalten darf, und ich habe es in einer CPP-Datei senden in, so Ich musste jede Klasse in Vorwärtsdeklaration, Deklaration und Implementierung in dieser einen Datei trennen. Es bringt mich zum Erbrechen, aber ich habe versucht, es so sauber wie möglich zu halten. Es gibt Tonnen von Code, also habe ich nur das aufgenommen, was ich für am meisten verwandt hielt. ReflectiveSurface ist die Elternklasse von RefractiveSurface. N ist die Flächennormale, V ist der Strahlrichtungsvektor diese Normale, n ist der Brechungsindex. Die Inzidenzstruktur enthält einen Punkt-, einen Normal- und einen Richtungsvektor.

Formeln für die Fersnel Annäherung und der Brechungsvektor jeweils: enter image description here

Sie können im Code sehen, dass ich ein Epsilon * Strahlrichtung Wert verwenden Schatten Akne durch Schwimmer Unschärfen zu vermeiden. Ähnliches scheint jedoch der kleinen Sphäre zu passieren. Ein weiterer Screenshot: enter image description here

enter image description here

Wie Sie sehen können, wird die Kugel nicht transparent erscheinen, aber es die diffusen Kugel der Farbe nicht erben. Es hat normalerweise auch einige weiße Pixel.

ohne Brechung:

enter image description here

+0

Um welche Art von Zahlen handelt es sich? Es ist möglich, dass Ihre Werte zu klein werden, um durch "float" genau dargestellt zu werden und auf Null gehen. Können/haben Sie versucht, stattdessen 'double' zu ​​verwenden? –

+0

Scheint für die zwei Farbwerte in den ersten paar Iterationen im Bereich von 20-100 zu sein, wenn es am Ende der getColor-Funktion im Debug-Modus ankommt, und das dann durch die Entfernung^2 von der Kamera und geteilt wird gesättigt. – PEC

+0

Wir denken es alle. TODESSTERN –

Antwort

1

Die Antwort stellte sich als ziemlich einfach heraus, aber ich brauchte drei Tage, um den Code zu betrachten, um den Fehler zu finden. Ich habe eine Surface Klasse, von der ich zwei Klassen ableite: RoughSurface (diffus + blinn) und RelfectiveSurface. Dann wird RefractiveSurace von RefleciveSurface abgeleitet. Der Konstruktor von ReflectiveSurface nimmt den Brechungsindex (n) und den Extinktionswert (k) als Parameter, speichert sie aber nicht.(F0) wird während der Konstruktion aus ihnen berechnet und dann sind sie verloren. RefractiveSurface hingegen verwendet (n) in der Berechnung des Refraktionswinkels.

Alte Baumeister:

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) : 
    ReflectiveSurface(Color(1, 1, 1) * _n, _k) {} 

New Constructor:

RefractiveSurface::RefractiveSurface(float _n, const Color& _k) : 
    ReflectiveSurface(Color(1, 1, 1) * _n, _k), n(_n) {} 

Wie Sie sehen können, habe ich vergessen, den Wert (n) für RefractiveSurface im Konstruktor zu speichern.

Kleine rote Kugel hinter großen Glaskugel von den beiden Seiten der Kamera leuchtet:

enter image description here

Es sieht in Bewegung genial D

Vielen Dank für Ihre Zeit, Jungs!. Ich muss diese Hausaufgaben machen, dann werde ich das Ganze umschreiben und das Ganze optimieren.

1

RefractiveSurface::refractionDir nimmt die normale N durch (nicht const) Referenz, und es kann es invertieren. Dies scheint gefährlich zu sein. Es ist nicht klar, dass der Aufrufer möchte, dass I.normal umgedreht wird, da er in Farbberechnungen weiter unten verwendet wird.

Außerdem wird refracted_color nicht immer initialisiert (außer der Farbkonstruktor macht es schwarz).

Versuchen (vorübergehend) zu vereinfachen und nur sehen, ob die gebrochenen Strahlen treffen, wo Sie erwarten. Entfernen Sie die Fresnel-Berechnung und die Reflexionskomponente und setzen Sie einfach refracted_color auf das Ergebnis der Kurve des gebrochenen Strahls. Das wird helfen zu bestimmen, ob der Fehler in der Fresnel-Berechnung oder in der Geometrie der Biegung des Strahls liegt.

Ein Debugging-Tipp: Färben Sie die Pixel, die nichts mit etwas anderem als Schwarz berühren. Das macht es leicht, die Verfehlungen von den Schatten (Oberflächenakne) zu unterscheiden.