Intersection Model::intersect(Ray r) { Intersection xsect; xsect.init(); Vector3 e = invMat.transform_point(r.e); Vector3 d = normalize(invMat.transform_vector(r.d)); Mesh::MeshTriangleList m; m = kdtree->Test(e, d); real_t min_dis = 9999999.9; // Convert each triangle into a "Triangle" Class object, and pass // it to that class's intersection test. Yay DRY. for (size_t i = 0; i < m.size(); i++) { MeshTriangle tri = m[i]; Triangle t; for (size_t j = 0; j < 3; j++) { Triangle::Vertex& tv = t.vertices[j]; const MeshVertex& mv = mesh->vertices[tri.vertices[j]]; tv.position = mv.position; tv.normal = mv.normal; tv.tex_coord = mv.tex_coord; tv.material = material; } t.position = position; t.orientation = orientation; t.scale = scale; t.invMat = invMat; t.normMat = normMat; Intersection ti = t.intersect(r); if (ti.exists && ti.squared_dist < min_dis) { min_dis = ti.squared_dist; xsect = ti; } } return xsect; }
Intersection Triangle::intersect(Ray r) { Intersection xsect; xsect.init(); real_t min_dis = 999999.9; Vector3 e = invMat.transform_point(r.e); Vector3 d = normalize(invMat.transform_vector(r.d)); Vector3 abc = vertices[0].position - vertices[1].position; Vector3 def = vertices[0].position - vertices[2].position; Vector3 fed = Vector3(def.z, def.y, def.x); Vector3 ghi = d; Vector3 ihg = Vector3(ghi.z, ghi.y, ghi.x); Vector3 jkl = vertices[0].position - e; Vector3 det_1 = Vector3(def.y * ghi.z - ghi.y * def.z, ghi.x * def.z - def.x * ghi.z, def.x * ghi.y - def.y * ghi.x); Vector3 det_2 = Vector3(abc.x * jkl.y - jkl.x * abc.y, jkl.x * abc.z - abc.x * jkl.z, abc.y * jkl.z - jkl.y * abc.z); // barycentric weighting factors real_t M = dot(abc, det_1); real_t beta = dot(jkl, det_1) / M; real_t gamma = dot(ihg, det_2) / M; real_t theta = -1 * dot(fed, det_2) / M; if (beta < 0 || beta > 1 - gamma || gamma < 0 || gamma > 1 || theta < epsilon) return xsect; Matrix4 inv; make_transformation_matrix(&inv, position, orientation, scale); Vector3 local_pos = e + theta * d; Vector3 world_pos = inv.transform_point(local_pos); real_t dist = squared_distance(r.e, world_pos); if (dist >= min_dis * min_dis) { return xsect; } xsect.squared_dist = dist; xsect.position = world_pos; Vector3 local_norm = normalize(vertices[0].normal + vertices[1].normal + vertices[2].normal); xsect.normal = normalize(normMat * local_norm); xsect.exists = true; real_t material_mult[3] = {1 - beta - gamma, beta, gamma}; xsect.mat.black_out(); Vector2 texel = Vector2::Zero(); // Use the weighting factors to interpolate values at this point for (int i = 0; i < 3; ++i) { xsect.mat.ambient += vertices[i].material->ambient * material_mult[i]; xsect.mat.diffuse += vertices[i].material->diffuse * material_mult[i]; xsect.mat.specular += vertices[i].material->specular * material_mult[i]; xsect.mat.refractive_index += vertices[i].material->refractive_index * material_mult[i]; texel += vertices[i].tex_coord * material_mult[i]; } texel.x -= floor(texel.x); texel.y -= floor(texel.y); int w, h; for (int i = 0; i < 3; ++i) { vertices[i].material->get_texture_size(&w, &h); xsect.texel += vertices[i].material->get_texture_pixel((int)(texel.x * w), (int)(texel.y * h)) * material_mult[i]; } return xsect; }