I'm working on adding triangles to my raytracer, it currently does planes and spheres including shading, shadows, and ambient occlusion. I've developed the code below to determine a ray's intersection point with an arbitrary triangle. Although the raw intersection is correct, the shading is wrong and a triangle will appear in-front of all other objects even when behind them. I think it's because the ray parameter 't' is getting calculated wrong, but I can't seem to figure out where. Any help is appreciated.
The attached image is of a leaning-back triangle intersecting a vertical plane, as can('t) be seen, the part of the triangle behind the plane is still visible. I can provide other renders or the file I use to generate the scene if desired.
The constructor for the Triangle and the hit function are copied below
Triangle::Triangle(const Point3D& a, const Point3D& b, const Point3D& c)
:GeometricObject(),
t1(a), t2(b), t3(c) {
// t1, t2, and t3 are the verticies of the triangle
// Subtract points to get two sides of the triangle
Vector3D v1 = t2 - t1;
Vector3D v2 = t3 - t2;
// ^ is cross product operator
// use cross product to get the normal for the triangle
n = v1 ^ v2;
n.normalize();
// * is dot-product when used on vectors or anything
// based on a vector (Normal, Ray)
d = t1 * n;
}
bool
Triangle::hit(const Ray& ray, double& tmin, ShadeRec& sr) const{
// t = ray * n /
// (p0 * n) + d
float vd = ray * n;
// Origin in vector form
Vector3D p0(-Vector3D(ray.o));
// Ray is parallel to triangle's plane
if (vd == 0) return false;
// Triangle's normal faces away from ray origin
if (vd > 0) return false;
float v0 = (p0 * n) + d;
float t = vd / v0;
// Intersection occurs before ray origin
if (t < 0) return false;
// ray-triangle intersection point
Vector3D p(ray.o + t * ray);
// Can be optimized, not for ease of debugging
Vector3D v1 = t1 - p;
Vector3D v2 = t2 - p;
Vector3D v3 = t3 - p;
Vector3D n1; // store the normal for the side
float d1;
// Check if the point is within the triangle
// by checking which side of each edge it's on
// Side 1
n1 = v2 ^ v1;
n1.normalize();
d1 = p0 * n1;
if (((p * n1) + d1) < 0) return false;
// kEpsilon is a very small positive value
// used to avoid shading errors due to
// floating point precision
if (t > kEpsilon) {
tmin = t;
sr.normal = n;
sr.localHitPoint = ray.o + t * ray;
return true;
}else {
return false;
}
}
Last edited by Bjartr; December 24th, 2008 at 08:24 PM.
* The Best Reasons to Target Windows 8
Learn some of the best reasons why you should seriously consider bringing your Android mobile development expertise to bear on the Windows 8 platform.