/* Function that returns whether a ray intersects a capped cylinder and fills out a variable for the distance from the ray's origin to the intersection if there is one and also fills out the "type" of the intersection -- 1 for a cylinder body intersection, 2 for a top cap intersection, and 3 for a bottom cap intersection */ bool intersect_capped_cylinder(const ray3f& ray, float r, float h, float& t, int& type) { bool valid_intersect = false; t = ray.tmax; vec3f intersect = zero3f; /* Check whether the ray intersects the cylinder body, ensuring that the intersection is not between the end caps. Note: most of this code is from the previous function, written by Jon Denning */ if(intersect_cylinder(ray, r, h, t)) { valid_intersect = true; type = BODY; } /* Now check the circles on top/bottom of cylinder http://orca.st.usm.edu/~jchen/courses/graphics/lectures/Raytracing.pdf proved helpful for this section of the code */ /* Using the notes on ray-plane intersection... */ /* Intersect the top end cap, first; intersect the plane at {0, 0, h} */ vec3f n = vec3f(0, 0, 1); // Normal vec3f c = vec3f(0, 0, h); // Center float t_cap; if (dot(ray.d, n) != 0) { t_cap = dot((c-ray.e), n)/dot(ray.d, n); if (t_cap >= ray.tmin && t_cap <= ray.tmax) { intersect = ray.eval(t_cap); if((intersect.x * intersect.x + intersect.y * intersect.y) <= r*r) { if(t_cap < t) { t = t_cap; valid_intersect = true; type = CAP_TOP; } } } } /* Intersect the bottom end cap; intersect the plane at {0, 0, 0} */ n = vec3f(0, 0, -1); c = vec3f(0, 0, 0); if (dot(ray.d, n) != 0) { t_cap = dot((c-ray.e), n)/dot(ray.d, n); if (t_cap >= ray.tmin && t_cap <= ray.tmax) { intersect = ray.eval(t_cap); if((intersect.x * intersect.x + intersect.y * intersect.y) <= r*r) { if(t_cap < t) { t = t_cap; valid_intersect = true; type = CAP_BOT; } } } } if(valid_intersect) return true; else return false; }
// intersect quad inline bool intersect_quad(const ray3f& ray, float radius, float& t, vec3f& p) { if(ray.d.z == 0) return false; t = - ray.e.z / ray.d.z; p = ray.eval(t); if(radius < p.x or -radius > p.x or radius < p.y or -radius > p.y) return false; if (t < ray.tmin or t > ray.tmax) return false; return true; }
bool intersect_quad(const ray3f& ray, float w, float h, float& t, float& ba, float& bb) { // TODO: BUG: handle infinite intersections if(ray.d.z == 0) return false; t = - ray.e.z / ray.d.z; if(t < ray.tmin or t > ray.tmax) return false; auto p = ray.eval(t); if(w/2 < p.x or -w/2 > p.x or h/2 < p.y or -h/2 > p.y) return false; ba = p.x/w+0.5; bb = p.y/h+0.5; return true; }
// http://geomalgorithms.com/a05-_intersect-1.html // // intersect2D_2Segments(): find the 2D intersection of 2 finite segments // // Input: two finite segments S1 and S2 // // Output: *I0 = intersect point (when it exists) // // *I1 = endpoint of intersect segment [I0,I1] (when it exists) // // Return: 0=disjoint (no intersect) // // 1=intersect in unique point I0 // // 2=overlap in segment from I0 to I1 // int // intersect2D_2Segments( Segment S1, Segment S2, Point* I0, Point* I1 ) // { // Vector u = S1.P1 - S1.P0; // Vector v = S2.P1 - S2.P0; // Vector w = S1.P0 - S2.P0; // float D = perp(u,v); // // // test if they are parallel (includes either being a point) // if (fabs(D) < SMALL_NUM) { // S1 and S2 are parallel // if (perp(u,w) != 0 || perp(v,w) != 0) { // return 0; // they are NOT collinear // } // // they are collinear or degenerate // // check if they are degenerate points // float du = dot(u,u); // float dv = dot(v,v); // if (du==0 && dv==0) { // both segments are points // if (S1.P0 != S2.P0) // they are distinct points // return 0; // *I0 = S1.P0; // they are the same point // return 1; // } // if (du==0) { // S1 is a single point // if (inSegment(S1.P0, S2) == 0) // but is not in S2 // return 0; // *I0 = S1.P0; // return 1; // } // if (dv==0) { // S2 a single point // if (inSegment(S2.P0, S1) == 0) // but is not in S1 // return 0; // *I0 = S2.P0; // return 1; // } // // they are collinear segments - get overlap (or not) // float t0, t1; // endpoints of S1 in eqn for S2 // Vector w2 = S1.P1 - S2.P0; // if (v.x != 0) { // t0 = w.x / v.x; // t1 = w2.x / v.x; // } // else { // t0 = w.y / v.y; // t1 = w2.y / v.y; // } // if (t0 > t1) { // must have t0 smaller than t1 // float t=t0; t0=t1; t1=t; // swap if not // } // if (t0 > 1 || t1 < 0) { // return 0; // NO overlap // } // t0 = t0<0? 0 : t0; // clip to min 0 // t1 = t1>1? 1 : t1; // clip to max 1 // if (t0 == t1) { // intersect is a point // *I0 = S2.P0 + t0 * v; // return 1; // } // // // they overlap in a valid subsegment // *I0 = S2.P0 + t0 * v; // *I1 = S2.P0 + t1 * v; // return 2; // } // // // the segments are skew and may intersect in a point // // get the intersect parameter for S1 // float sI = perp(v,w) / D; // if (sI < 0 || sI > 1) // no intersect with S1 // return 0; // // // get the intersect parameter for S2 // float tI = perp(u,w) / D; // if (tI < 0 || tI > 1) // no intersect with S2 // return 0; // // *I0 = S1.P0 + sI * u; // compute S1 intersect point // return 1; // } // //=================================================================== // http://geomalgorithms.com/a07-_distance.html#dist3D_Segment_to_Segment bool intersect_line_approximate(const ray3f& ray, const vec3f& v0, const vec3f& v1, float r0, float r1, float& t, float& s) { auto r = ray3f::segment(v0, v1); if(abs(dot(ray.d,r.d)) == 1) return false; auto a = dot(ray.d,ray.d); auto b = dot(ray.d,r.d); auto c = dot(r.d,r.d); auto d = dot(ray.d,ray.e-r.e); auto e = dot(r.d,ray.e-r.e); t = (b*e-c*d)/(a*c-b*b); s = (a*e-b*d)/(a*c-b*b); t = clamp(t, ray.tmin, ray.tmax); s = clamp(s, r.tmin, r.tmax); auto ss = s / length(v1-v0); auto rr = r0*(1-ss)+r1*ss; if(dist(ray.eval(t), r.eval(s)) > rr) return false; s = ss; return true; }
// http://geomalgorithms.com/a02-_lines.html // distance( Point P, Segment P0:P1 ) // { // v = P1 - P0 // w = P - P0 // // if ( (c1 = w·v) <= 0 ) // before P0 // return d(P, P0) // if ( (c2 = v·v) <= c1 ) // after P1 // return d(P, P1) // // b = c1 / c2 // Pb = P0 + bv // return d(P, Pb) // } bool intersect_point_approximate(const ray3f& ray, const vec3f& p, float r, float& t) { t = - dot(ray.e - p, ray.d); t = clamp(t, ray.tmin, ray.tmax); return length(p-ray.eval(t)) <= r; }