Reputation: 13
What it does is basically checking for collisions against an array of triangles and drawing an image based on the color of the triangle it hits. I think my problem lies in the collision detection. Code here:
for (int i = 0; i < triangles.size(); i++){
vec3 v0 = triangles[i].v0;
vec3 v1 = triangles[i].v1;
vec3 v2 = triangles[i].v2;
vec3 e1 = v1 - v0;
vec3 e2 = v2 - v0;
vec3 b = start - v0;
mat3 A(-dir, e1, e2);
vec3 x = glm::inverse(A) * b;
if (x.x > 0 && x.y > 0 && (x.x + x.y < 1) && (x.z - start.z>= 0)){
return true;
}
}
...where "dir" is the direction of the ray coming from the camera, calculated as "x - SCREEN_WIDTH / 2, y - SCREEN_HEIGHT / 2, focalLength". SCREEN_WIDTH, SCREEN_HEIGHT and focalLength are constants. Start is the position of the camera, set to 0,0,0.
What I'm not sure about is what x really is and what I should check for before returning true. "x.x > 0 && x.y > 0 && (x.x + x.y < 1)" is supposed to check if the ray hits not only on the same plane but actually inside the triangle, and the last part ("x.z - start.z>= 0", the one I'm least sure about), if the collision happened in front of the camera.
I get images, but no matter how much I try it's never right. It's supposed to be a classic TestModel of a room with different colored walls and two shapes in it. The closest I think I've been is getting four of five walls right, with the far one missing and a part of one of the shapes on the other side of it.
Upvotes: 1
Views: 171
Reputation: 339776
I'm not familiar with the matrix formulation for triangle intersection - it sounds quite expensive.
My own code is below, where my e1
and e2
are equivalent to yours - i.e. they represent the edge vectors from v0
to v1
and v2
respectively:
// NB: triangles are assumed to be in world space
vector3 pvec = vector3::cross(ray.direction(), e2);
double det = e1.dot(pvec);
if (::fabs(det) < math::epsilon) return 0;
double invDet = 1.0 / det;
vector3 tvec(p0, ray.origin());
double u = tvec.dot(pvec) * invDet;
if (u < 0 || u > 1) return 0;
vector3 qvec = vector3::cross(tvec, e1);
double v = ray.direction().dot(qvec) * invDet;
if (v < 0 || u + v > 1) return 0;
double t = e2.dot(qvec) * invDet;
if (t > math::epsilon) { // avoid self intersection
// hit found at distance "t"
}
I suspect the problem is in your calculation of the ray vector, which should be normalised.
Upvotes: 1