2016-04-19 5 views
1

Ich versuche eine omni-direktionale Lichtquelle (ua k.a., Punktlichtquelle) in meinem Raytracing-Programm in C++ zu implementieren. Ich bekomme nicht die erwarteten Ergebnisse, aber ich kann das Problem nicht lösen. Vielleicht kann jemand sehen, was ich falsch mache. Ich habe die zwei Funktionen, die für Raytracing und das Licht verantwortlich sind, aufgenommen. Die ClosestIntersection Funktion findet die nächste Kreuzung und ein Dreieck. Das wird später in der DirectLight Funktion verwendet. Ich würde wirklich jede Hilfe zu schätzen wissen.Omnidirektionales Licht im Raytracing-Programm erzeugt falschen Render C++

#include <iostream> 
#include <glm/glm.hpp> 
#include <SDL.h> 
#include "SDLauxiliary.h" 
#include "TestModel.h" 
#include "math.h" 

using namespace std; 
using glm::vec3; 
using glm::mat3; 

// ---------------------------------------------------------------------------- 
// GLOBAL VARIABLES 

const int SCREEN_WIDTH = 500; 
const int SCREEN_HEIGHT = 500; 
SDL_Surface* screen; 
int t; 
vector<Triangle> triangles; 
float focalLength = 900; 
vec3 cameraPos(0, 0, -4.5); 

vec3 lightPos(0.5, 0.5, 0); 
vec3 lightColor = 14.f * vec3(1,1,1); 

// Translate camera 
float translation = 0.1;  // use this to set translation increment 

// Rotate camera 
float yaw; 
vec3 trueCameraPos; 

const float PI = 3.1415927; 

// ---------------------------------------------------------------------------- 
// CLASSES 

class Intersection; 

// ---------------------------------------------------------------------------- 
// FUNCTIONS 
void Update(); 
void Draw(); 
bool ClosestIntersection(vec3 start, vec3 dir, const vector<Triangle>& triangles, 
    Intersection& closestIntersection); 
vec3 DirectLight(const Intersection& i); 
// ---------------------------------------------------------------------------- 
// STRUCTURES 
struct Intersection 
{ 
    vec3 position; 
    float distance; 
    int triangleIndex; 
}; 

float m = std::numeric_limits<float>::max(); 

int main(int argc, char* argv[]) 
{ 
    LoadTestModel(triangles); 

    screen = InitializeSDL(SCREEN_WIDTH, SCREEN_HEIGHT); 
    t = SDL_GetTicks(); // Set start value for timer. 

    while (NoQuitMessageSDL()) 
    { 
     Update(); 
     Draw(); 
    } 

    SDL_SaveBMP(screen, "screenshot.bmp"); 
    return 0; 
} 

void Update() 
{ 
    // Compute frame time: 
    int t2 = SDL_GetTicks(); 
    float dt = float(t2 - t); 
    t = t2; 
    cout << "Render time: " << dt << " ms." << endl; 
    } 
} 

void Draw() 
{ 
    if (SDL_MUSTLOCK(screen)) 
     SDL_LockSurface(screen); 

    for (int y = 0; y<SCREEN_HEIGHT; ++y) 
    { 
for (int x = 0; x < SCREEN_WIDTH; ++x) 
{ 
    vec3 start = cameraPos; 
    vec3 dir(x - SCREEN_WIDTH/2, y - SCREEN_HEIGHT/2, focalLength); 
    Intersection intersection; 
    if (ClosestIntersection(start, dir, triangles, intersection)) 
    { 
     //vec3 theColor = triangles[intersection.triangleIndex].color; 
     vec3 theColor = DirectLight(intersection); 
     PutPixelSDL(screen, x, y, theColor); 
    } 
    else 
    { 
     vec3 color(0, 0, 0); 
     PutPixelSDL(screen, x, y, color); 
    } 
} 
    } 

    if (SDL_MUSTLOCK(screen)) 
     SDL_UnlockSurface(screen); 

    SDL_UpdateRect(screen, 0, 0, 0, 0); 
} 

bool ClosestIntersection(vec3 s, vec3 d, 
    const vector<Triangle>& triangles, Intersection& closestIntersection) 
{ 
    closestIntersection.distance = m; 
    for (size_t i = 0; i < triangles.size(); i++) 
    { 
     vec3 v0 = triangles[i].v0; 
     vec3 v1 = triangles[i].v1; 
     vec3 v2 = triangles[i].v2; 
     vec3 u = v1 - v0; 
     vec3 v = v2 - v0; 
     vec3 b = s - v0; 
     vec3 x; 

     // Determinant of A = [-d u v] 
     float det = -d.x * ((u.y * v.z) - (v.y * u.z)) - 
      u.x * ((-d.y * v.z) - (v.y * -d.z)) + 
      v.x * ((-d.y * u.z) - (u.y * -d.z)); 

     // Cramer'r Rule for t = x.x 
     x.x = (b.x * ((u.y * v.z) - (v.y * u.z)) - 
      u.x * ((b.y * v.z) - (v.y * b.z)) + 
      v.x * ((b.y * u.z) - (u.y * b.z)))/det; 

     if (x.x >= 0) 
     { 
      // Cramer'r Rule for u = x.y 
      x.y = (-d.x * ((b.y * v.z) - (v.y * b.z)) - 
       b.x * ((-d.y * v.z) - (v.y * -d.z)) + 
       v.x * ((-d.y * b.z) - (b.y * -d.z)))/det; 

      // Cramer'r Rule for v = x.z 
      x.z = (-d.x * ((u.y * b.z) - (b.y * u.z)) - 
       u.x * ((-d.y * b.z) - (b.y * -d.z)) + 
       b.x * ((-d.y * u.z) - (u.y * -d.z)))/det; 

      if (x.y >= 0 && x.z >= 0 && x.y + x.z <= 1 && x.x < closestIntersection.distance) 
      { 
       closestIntersection.position = x; 
       closestIntersection.distance = x.x; 
       closestIntersection.triangleIndex = i; 
      } 
     } 

    } 
    //end of for loop 

    if (closestIntersection.distance != m) 
    { 
     return true; 
    } 
    else 
    { 
     return false; 
    } 

} 

vec3 DirectLight(const Intersection& i) 
{ 
    vec3 n = triangles[i.triangleIndex].normal; 
    vec3 r = lightPos - i.position; 
    float R2 = r.x * r.x + r.y * r.y + r.z * r.z; 
    vec3 D = (lightColor * fmaxf((glm::dot(glm::normalize(r), n)), 0))/(4 * PI * R2); 
    return D; 
} 
+0

Nur aus Neugier, warum haben Sie die [vorherige Version] (http://stackoverflow.com/questions/36703812/omni-light-in-raytracing-doesnt-work-c) dieser Frage gelöscht? –

+0

Weil ich den ganzen Code posten wollte und sich die Leute normalerweise beschweren, wenn ich die Frage ändere. Also dachte ich, ich würde einen neuen Artikel posten :) – DoubleOseven

Antwort

1

Wenn ich den Code in ClosestIntersection richtig zu verstehen, ist hier, was es für jedes Dreieck zu tun:

  • u Lassen, v die Vektoren von einem Eckpunkt des Dreiecks zu den anderen zwei Ecken . Sei d (die Umkehrung) der Richtung des Strahls, den wir betrachten.
  • Und b sei der Vektor von diesem Eckpunkt des Dreiecks zur Kamera.
  • Finden Sie p, q, r, so dass b = pd + qu + rv (p, q, r sind, was Ihr Code x.x, x.y, x.z) nennt.
  • Nun trifft der Strahl auf das Dreieck, wenn p> 0, q> = 0, r> = 0, q + r < = 1 und die Entfernung zum Schnittpunkt p ist.

So machen die Bedingungen auf q, r Sinn; Die Idee ist, dass b-qu-rv der Vektor von der Kamera zum relevanten Punkt im Dreieck ist und es in Richtung d ist. Ihre Entfernungen sind nicht wirklich Entfernungen, aber entlang eines einzelnen Strahls sind sie die gleichen multiple der tatsächlichen Entfernung, was bedeutet, dass dies gut funktioniert, um festzustellen, welches Dreieck Sie getroffen haben, und das ist alles, was Sie für sie verwenden. So weit, ist es gut.

Aber dann sagst du closestIntersection.position = x; und das ist sicher alles falsch, denn x ist nicht im selben Koordinatensystem wie deine Kamera Position, Dreieck Vertices, etc. Es ist in diesem lustigen "wie viel von d, wie viel von dir , wie viel von v "Koordinatensystem, das von Dreieck zu Dreieck nicht gleich ist. (Das ist der Grund, warum Diskontinuitäten an Dreiecksgrenzen auch innerhalb eines einzigen Gesichts auftreten.)

Versuchen Sie es stattdessen auf v0 + xy * (v1-v0) + xz * (v2-v0) zu setzen (ich denke das ist richtig, es ist der eigentliche Punkt, an dem der Strahl das Dreieck kreuzt, in den gleichen Koordinaten wie alle anderen Punkte) und zu sehen, was es tut.

+0

Vielen Dank für Ihre klare Erklärung! Das war es, was ich nach langer Zeit brauchte, um es zum Laufen zu bringen :) – DoubleOseven

1

Dies ist keine super großartige Antwort, aber ich habe es geschafft, dass Ihr Code ohne die seltsamen Schattierungsdiskontinuitäten funktioniert. Das Problem passiert in ClosestIntersection und vielleicht Gareths Antwort deckt es ab. Ich muss jetzt aufhören, mir das anzuschauen, aber ich wollte dir zeigen, was ich habe, bevor ich gehe, und ich brauche eine Antwort, um einen Code zu schreiben.

// This starts with some vec3 helper functions which make things 
// easier to look at 
float Dot(const vec3& a, const vec3& b) { 
    return a.x * b.x + a.y * b.y + a.z * b.z; 
} 
vec3 Cross(const vec3& a, const vec3& b) { 
    return vec3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); 
} 
float L2(const vec3& v) { return v.x*v.x + v.y*v.y + v.z*v.z; } 
float Abs(const vec3& v) { return std::sqrt(L2(v)); } 

// Here is the replacement version of ClosestIntersection 
bool ClosestIntersection(vec3 cam, vec3 dir, 
    const vector<Triangle>& triangles, Intersection& closestIntersection) 
{ 
    closestIntersection.distance = m; 
    vec3 P0 = cam; 
    vec3 P1 = cam + dir; 
    for (size_t i = 0; i < triangles.size(); ++i) { 
     vec3 v0 = triangles[i].v0; 
     vec3 v1 = triangles[i].v1; 
     vec3 v2 = triangles[i].v2; 
     // Dan Sunday 
     // http://geomalgorithms.com/a06-_intersect-2.html 
     vec3 u = v1 - v0; 
     vec3 v = v2 - v0; 
     // w = P-v0, solve w = su +tv (s, t are parametric scalars) 

     vec3 n = Cross(u, v); 
     float ri = Dot(n, (v0 - P0))/Dot(n, (P1 - P0)); 
     vec3 Pi = P0 + ri * (P1- P0); 
     vec3 w = Pi - v0; 

     // s = w . (n x v)/(u . (n x v)) 
     // t = w . (n x u)/(v . (n x u)) 

     float s = Dot(w, Cross(n, v))/Dot(u, Cross(n, v)); 
     float t = Dot(w, Cross(n, u))/Dot(v, Cross(n, u)); 

     if(s >= 0 && t >= 0 && s+t <= 1) { 
      float dist = Abs(cam - Pi); 
      if(dist < closestIntersection.distance) { 
       closestIntersection.position  = Pi; 
       closestIntersection.distance  = dist; 
       closestIntersection.triangleIndex = int(i); 
      } 
     } 
    } 

    return closestIntersection.distance != m; 
} 

Viel Glück.

+0

Vielen Dank! Ich schätze es, dass du dir die Zeit genommen hast :) – DoubleOseven