visual studio - Omni-directional light in raytracing program gives wrong render c++ -
i trying implement omni-directional light source (a.k.a., point light source) in raytracing program in c++. not getting expected results, can't figure out problem. maybe can see doing wrong. have included 2 functions responsible raytracing , light. closestintersection
function finds closest intersection , triangle. used later in directlight
function. appreciate help.
#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 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 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); (int y = 0; y<screen_height; ++y) { (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; (size_t = 0; < 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 = [-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 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 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 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 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; }
if i'm understanding code in closestintersection
correctly, here's it's doing each triangle:
- let u,v vectors 1 vertex of triangle other 2 vertices. let d (the reverse of) direction of ray we're considering.
- and let b vector vertex of triangle camera.
- find p,q,r b = pd+qu+rv (p,q,r code calls x.x, x.y, x.z).
- now ray meets triangle if p>0, q>=0, r>=0, q+r<=1 , distance intersection point p.
so, conditions on q,r make sense; idea b-qu-rv vector camera relevant point in triangle , it's in direction d. distances aren't distances, along single ray they're the same multiple of actual distance, means works fine determining triangle you've hit, , that's use them for. far, good.
but closestintersection.position = x;
, surely that's wrong, because x
isn't in same coordinate system camera location, triangle vertices, etc. it's in funny "how of d, how of u, how of v" coordinate system isn't same 1 triangle next. (which why getting discontinuities @ triangle boundaries within single face, think.)
try setting v0+x.y*(v1-v0)+x.z*(v2-v0) instead (i think right; it's meant actual point ray crosses triangle, in same coordinates other points) , see does.
Comments
Post a Comment