//-*-c-*- #ifndef __INTERSECT_H__ #define __INTERSECT_H__ #include #include "linalg.h" #include "matrix.h" #include "rotate.h" #define EPSILON 0.0f /* Test the intersection between a ray starting from `origin` traveling in the direction `direction` and a triangle defined by the vertices `v0`, `v1`, and `v2`. If the ray intersects the triangle, set `distance` to the distance between `origin` and the intersection and return true, else return false. `direction` must be normalized. */ __device__ bool intersect_triangle(const float3 &origin, const float3 &direction, const float3 &v0, const float3 &v1, const float3 &v2, float &distance) { Matrix m = make_matrix(v1-v0, v2-v0, -direction); float determinant = det(m); if (determinant == 0.0f) return false; float3 b = origin-v0; float u1 = ((m.a11*m.a22 - m.a12*m.a21)*b.x + (m.a02*m.a21 - m.a01*m.a22)*b.y + (m.a01*m.a12 - m.a02*m.a11)*b.z)/determinant; if (u1 < -EPSILON || u1 > 1.0f) return false; float u2 = ((m.a12*m.a20 - m.a10*m.a22)*b.x + (m.a00*m.a22 - m.a02*m.a20)*b.y + (m.a02*m.a10 - m.a00*m.a12)*b.z)/determinant; if (u2 < -EPSILON || u2 > 1.0f) return false; float u3 = ((m.a10*m.a21 - m.a11*m.a20)*b.x + (m.a01*m.a20 - m.a00*m.a21)*b.y + (m.a00*m.a11 - m.a01*m.a10)*b.z)/determinant; if (u3 <= 0.0f || (1.0f-u1-u2) < -EPSILON) return false; distance = u3; return true; } /* Return the 32 bit color associated with the intersection between a ray starting from `origin` traveling in the direction `direction` and the plane defined by the points `v0`, `v1`, and `v2` using the cosine of the angle between the ray and the plane normal to determine the brightness. `direction` must be normalized. */ __device__ unsigned int get_color(const float3 &direction, const float3 &v0, const float3& v1, const float3 &v2, const unsigned int base_color=0xFFFFFFFF) { float scale = dot(normalize(cross(v1-v0,v2-v1)),-direction); unsigned int r = 0xFF & (base_color >> 16); unsigned int g = 0xFF & (base_color >> 8); unsigned int b = 0xFF & base_color; if (scale < 0.0f) scale = dot(-normalize(cross(v1-v0,v2-v1)),-direction); r = floorf(r*scale); g = floorf(g*scale); b = floorf(b*scale); return r << 16 | g << 8 | b; } /* Test the intersection between a ray starting from `origin` traveling in the direction `direction` and the axis-aligned box defined by the opposite vertices `lower_bound` and `upper_bound`. If the ray intersects the box return True, else return False. */ __device__ bool intersect_box(const float3 &origin, const float3 &direction, const float3 &lower_bound, const float3 &upper_bound, float& distance_to_box) { float kmin, kmax, kymin, kymax, kzmin, kzmax; float divx = 1.0f/direction.x; if (divx >= 0.0f) { kmin = (lower_bound.x - origin.x)*divx; kmax = (upper_bound.x - origin.x)*divx; } else { kmin = (upper_bound.x - origin.x)*divx; kmax = (lower_bound.x - origin.x)*divx; } if (kmax < 0.0f) return false; float divy = 1.0f/direction.y; if (divy >= 0.0f) { kymin = (lower_bound.y - origin.y)*divy; kymax = (upper_bound.y - origin.y)*divy; } else { kymin = (upper_bound.y - origin.y)*divy; kymax = (lower_bound.y - origin.y)*divy; } if (kymax < 0.0f) return false; if (kymin > kmin) kmin = kymin; if (kymax < kmax) kmax = kymax; if (kmin > kmax) return false; float divz = 1.0f/direction.z; if (divz >= 0.0f) { kzmin = (lower_bound.z - origin.z)*divz; kzmax = (upper_bound.z - origin.z)*divz; } else { kzmin = (upper_bound.z - origin.z)*divz; kzmax = (lower_bound.z - origin.z)*divz; } if (kzmax < 0.0f) return false; if (kzmin > kmin) kmin = kzmin; if (kzmax < kmax) kmax = kzmax; if (kmin > kmax) return false; distance_to_box = kmin; return true; } #endif