Raytracing-Problem - Schatten werfen

7

Also wurde ich beauftragt, ein Modell der Cornell Box zu erstellen. Ich habe es geschafft, alles zu tun, bis Schatten geworfen wurden. In diesem Fall werden einige Schatten geworfen, wenn es keine geben sollte. Hier sind Bilder davon, wie es jetzt aussieht und ein größeres Bild davon, wie es aussehen sollte:

Geben Sie hier die Bildbeschreibung ein

Ich habe festgestellt, dass die Kastenwände aus irgendeinem Grund auch Schatten werfen.

Ein kurzer Überblick über die Funktionsweise: Wir haben eine Lochkamera, die Strahlen aussendet und den nächsten Kollisionspunkt findet, also alles, was Sie sehen. Diese Punkte sowie die Entfernung von einem Startpunkt (in diesem Fall Kamera) zum Kollisionspunkt werden in einer vordefinierten Datenstruktur gespeichert, die als Schnittpunkt bezeichnet wird. Diese Daten werden dann verwendet, um den Abstand zum Licht zu berechnen und die Beleuchtungsstärken zu ermitteln. Dieselbe Methode, die zum Finden des nächsten Kollisionspunkts verwendet wird, wird verwendet, um das nächste Objekt für Schatten zu finden, wobei auch der ursprüngliche Kollisionspunkt als Start und die Lichtquelle als Richtung des Strahlvektors verwendet werden.

Ich habe das Problem auf Raytracing eingegrenzt. Wenn überprüft wird, ob Objekte vorhanden sind, aus denen Schatten geworfen werden können, beispielsweise aus dem oberen rechten Bereich der hinteren grauen Wand, wird die Cyan-Decke an einem Punkt von derselben Seite des Lichts aufgenommen. Angenommen, die Lichtquelle befindet sich in der Mitte und der ursprüngliche Punkt befindet sich auf unserer rechten Seite des Lichts. Die Methode nimmt irgendwie einen Punkt auf, der sich auf derselben Seite des Lichts befindet, wenn der Vektor direkt durch die Lichtquelle gehen und irgendwo auf unserer linken Seite enden soll.

Hier ist mein Quellcode für die fraglichen Funktionen:

bool ClosestIntersection( vec3 start, vec3 dir, const vector<Triangle>& triangles, Intersection& it ) {

    vec3 least;
    vec3 e1, e2, b, v0;
    mat3 A;

    least[0] = m;

    int index = triangles.size()-1;

    for(int i = 0; i < int(triangles.size()); i++) {

        v0 = triangles[i].v0;
        e1 = triangles[i].v1 - v0;
        e2 = triangles[i].v2 - v0;
        b = start - v0;

        A = mat3( -dir, e1, e2);

        if(!getInverse(A,b)) {continue;}

        vec3 x = A * b;

        if(x[0] <= least[0] && x[1] + x[2] <= 1.f && x[1] >= 0.f && x[2] >= 0.f && x[0] >= 0.00001f) {
            least = x;
            index = i;
        }
    }

    if (least[0] == m) {
        return false;
    }
    else {
        it.position = least[0] * dir + start;
        const vec3 t = it.position-start;
        it.distance = sqrt(t[0]*t[0] + t[1]*t[1] + t[2]*t[2]);
        it.triangleIndex = index;
        return true;
    }
}

vec3 DirectLight( const Intersection& i ){
    const Triangle T = triangles[i.triangleIndex];
    const vec3 r = lightPos - i.position;
    const float dist = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);

    Intersection t;
    t.distance = dist;
    t.position = i.position;
    t.triangleIndex = i.triangleIndex; 

    //ClosestIntersection( i.position, lightPos, triangles, t);

    /*
    if(!ClosestIntersection( lightPos, i.position, triangles, t)) {return vec3(1,0,0);}
    else { return vec3(0,0,0); } */

    if(ClosestIntersection( i.position, lightPos, triangles, t) && (dist-t.distance > 1.f)) {

        return vec3(0,0,0);
    } else {
        const vec3 B = 14.f * T.color * (float(max(dot(r,T.normal),float(0)) / float(4*3.14 * dist* dist)));

        return B; 
    }

}}

Ich habe über zwölf Stunden damit verbracht, dieses Problem zu finden. Selbst mein Dozent kann das Problem nicht herausfinden. Jede Hilfe wäre sehr dankbar!

j.robinson.10203
quelle

Antworten:

3

Sind Sie sicher, dass Sie nicht dieselbe Oberfläche erneut schneiden, wenn Sie nach Lichtverschlüssen suchen? Dies ist ein klassisches Präzisionsproblem. Es gibt viele Möglichkeiten, dies anzugehen:

  • Stellen Sie zunächst eine gute Konditionierung des Schnittpunkts her, indem Sie ein zweites Mal erneut schneiden: Betrachten Sie Ihre erste Trefferentfernung d als ungefähr, erstellen Sie den Punkt E '= Auge + (d-eps) * Strahl und berechnen Sie den Schnittpunkt von hier aus neu. (Variante: Verwenden Sie für die erste Kreuzung einfach den Begrenzungsrahmen).

  • Zweitens können Sie für den Streifwinkel abhängig von Ihrer Formdarstellung, Speicher- und Berechnungsgenauigkeit und Skalierung sowie der Tessellation auch hier gefährliche Ungenauigkeiten aufweisen und müssen dennoch sicherstellen, dass Sie nicht dieselbe Oberfläche erneut schneiden. Wenn es flach oder konvex oder tesseliert ist, können Sie es für den Schattenstrahlentest als nicht schneidbar markieren. Ein einfacherer Trick (näherungsweise) besteht darin, den Beginn des Schattenstrahls durch Epsilon in die normale Richtung zu verschieben.

Fabrice NEYRET
quelle
1

Es gibt einen Trick, mit dem viele das Problem tatsächlich umgehen können *. Die Szene und die Menge der Dinge, die durch Raytracing verfolgt werden sollen, müssen nicht identisch sein. Bei den meisten Raytracern können Objekte nicht am Schattenwurf, an Reflexionen usw. teilnehmen.

In Ihrem Fall könnten Sie einfach die Außenwände von Shadow Casting nehmen und daher würden sie sich nicht selbst beschatten, sodass Sie problemlos Lichter außerhalb der Box platzieren können.

Auf jeden Fall können Sie der Stichprobe eine leichte Verzerrung hinzufügen und die Objekte etwas weiter betrachten, als es Ihr Berechnungsergebnis ergibt. Beim Schattenwerfen werden dadurch alle Arten von Problemen vermieden.

* Ja, Sie haben ein Problem, das Sie beheben sollten. Aber manchmal ist schnell und erledigt alles, was benötigt wird

joojaa
quelle