2014-11-04 30 views
6

Sto scrivendo un ray tracer. Finora ho diffuso, illuminazione Blinn e riflessioni. Qualcosa è andato storto con le mie rifrazioni e non ho idea di cosa. Spero che qualcuno possa darmi una mano. enter image description hereRay tracing - bug di rifrazione

Ho una grande sfera rossa diffusa + Blinn e una piccola rifrangente con indice di rifrazione n = 1.5.

Il piccolo è davvero rovinato.

codice rilevante:

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; 
} 

Il codice è tutto il luogo, dal momento che questo è un lavoro e io non sono autorizzato a includere le intestazioni supplementari e devo inviarlo in in un file cpp, così Ho dovuto separare ogni classe in una dichiarazione, dichiarazione e implementazione in quel file. Mi fa vomitare ma ho cercato di mantenerlo il più pulito possibile. C'è un sacco di codice quindi ho incluso solo quello che pensavo fosse più relativo. ReflectiveSurface è la classe genitore di RefractiveSurface. N è la superficie normale, V è il vettore di direzione del raggio normale, n è l'indice di rifrazione. La struttura dell'incidenza contiene un punto, un vettore normale e un vettore di direzione.

Formule per il ravvicinamento Fersnel e la rifrazione vettore rispettivamente: enter image description here

Si può vedere nel codice che uso un valore epsilon * direzione del raggio per evitare acne ombra causata dal galleggiante imprecisione. Qualcosa di simile sembra accadere alla piccola sfera, però. un'altra immagine: enter image description here

enter image description here

Come si può vedere, la sfera non appare trasparente, ma lo fa ereditano il colore della sfera diffusa. Di solito ha anche alcuni pixel bianchi.

Senza rifrazione:

enter image description here

+0

Che tipo di numeri sono coinvolti? È possibile che i tuoi valori stiano diventando troppo piccoli per essere rappresentati con precisione da 'float' e stanno andando a zero. Puoi/hai provato a usare 'double' invece? –

+0

Sembra essere nell'intervallo 20-100 per i due valori di colore nelle prime iterazioni quando arriva in modalità debug alla fine della funzione getColor, e verrà quindi diviso per la distanza^2 dalla telecamera e saturato. – PEC

+0

Lo stiamo pensando tutti. MORTE NERA –

risposta

1

La risposta si è rivelata piuttosto semplice, ma mi ci sono voluti 3 giorni per fissare il codice per catturare l'errore. Ho una classe Surface, ne ricavo due classi: RoughSurface (diffuse + blinn) e RelfectiveSurface. Quindi, RefractiveSurace è derivato da RefleciveSurface. Il costruttore di ReflectiveSurface prende l'indice di rifrazione (n) e il valore di estinzione (k) come parametri, ma non li memorizza.(F0) viene calcolato da loro durante la costruzione, quindi vengono persi. RefractiveSurface, d'altra parte, utilizza (n) nel calcolo dell'angolo di rifrazione.

Old costruttore:

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

nuovo costruttore:

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

Come potete vedere, ho dimenticato di salvare il valore (n) per RefractiveSurface nel costruttore.

piccola sfera rossa dietro il grande sfera di vetro illuminato dai due lati della macchina fotografica:

enter image description here

Sembra impressionante in movimento D

Grazie per il vostro tempo, ragazzi!. Devo finire questo compito, poi riscriverò il tutto e ottimizzerò l'inferno.

1

RefractiveSurface::refractionDir batte il normale N di (non-const) di riferimento, e potrebbe capovolgerlo. Questo sembra pericoloso. Non è chiaro che il chiamante voglia capovolgere I.normal, poiché viene utilizzato nei calcoli di colore più in basso.

Inoltre, refracted_color non è sempre inizializzato (a meno che il costruttore di colori non lo renda nero).

Provare (temporaneamente) a semplificare e vedere se i raggi rifratti colpiscono dove ci si aspetta. Rimuovi il calcolo di Fresnel e il componente di riflessione e imposta semplicemente refracted_color sul risultato della traccia del raggio rifratto. Ciò aiuterà a determinare se l'errore si trova nel calcolo di Fresnel o nella geometria di piegare il raggio.

Un suggerimento per il debug: Colora i pixel che non colpiscono nulla con qualcosa di diverso dal nero. Questo rende facile distinguere le mancate dalle ombre (acne superficiale).