hit_test intersect(ray r, object obj) { v3 ro = r.origin; v3 rd = r.direction; double t; hit_test ht_out; switch (obj.tag) { case SPHERE: { v3 sc = obj.o.s.center; double sr = obj.o.s.radius; v3 A = v3_sub(ro, sc); double B = v3_dot(A, rd); double C = v3_dot(A, A) - sr*sr; double D = B*B - C; t = -B - sqrt(D); if (D > 0 && t > 0) { v3 ray_pos = ray_position(r, t); ht_out.miss = HIT; ht_out.t = t; ht_out.hit_point = ray_pos; ht_out.surf = \ (*(obj.o.s.surface_color))(obj.o.s.center, ray_pos); ht_out.shine = obj.o.s.shine; ht_out.surf_norm = v3_norm(v3_sub(ray_pos, obj.o.s.center)); } else { ht_out.miss = MISS; } break; } case POSTER: { v3 n = v3_expr(0, 0, -1); double d = obj.o.p.upper_left.z; t = -(v3_dot(ro, n) + d) / v3_dot(rd, n); v3 ray_pos = ray_position(r, t); if (t > 0 && is_on_poster(ray_pos, obj.o.p)) { ht_out.miss = HIT; ht_out.t = t; ht_out.hit_point = ray_pos; ht_out.surf = \ (*(obj.o.p.surface_color))(obj.o.p.upper_left, ray_pos); ht_out.shine = obj.o.p.shine; ht_out.surf_norm = n; } else { ht_out.miss = MISS; } break; } default: fprintf(stderr, "error in intersect: unrecognized tag\n"); exit(1); } return ht_out; }
hit_test intersect_cylinder (ray r, cylinder c) { hit_test result; v3 rp = v3_expr(r.direction.x,0,r.direction.z); double mp = v3_mag(rp); v3 np = v3_norm(rp); double xbar = r.origin.x - c.center.x; double zbar = r.origin.z - c.center.z; double a = pow(np.x,2) + pow(np.z,2); double b = 2 * ( (xbar*np.x) + (zbar*np.z) ); double c1 = pow(xbar,2) + pow(zbar,2) - pow(c.radius,2); double d = pow(b,2) - (4*a*c1); result.miss = MISS; if(d >= 0) { double t_front = (-b - sqrt(d)) / (2*a); double t_back = (-b + sqrt(d)) / (2*a); v3 p_front = ray_position(r, t_front/mp); v3 p_back = ray_position(r, t_back/mp); if( (t_front < t_back) && (t_front > 0) && (p_front.y >= c.center.y) && (on_cylinder(p_front, c))) { result.miss = HIT; result.t = (t_front/mp); result.hit_point = p_front; result.surf = c.surface_color(c.center, p_front); result.shine = c.shine; v3 c2 = v3_expr(c.center.x, p_front.y, c.center.z); result.surf_norm = v3_norm(v3_sub(p_front,c2)); } else if( (t_back > 0) && (p_back.y >= c.center.y) && (on_cylinder(p_back, c)) ) { result.miss = HIT; result.t = (t_back/mp); result.hit_point = p_back; result.surf = c.surface_color(c.center, p_back); result.shine = c.shine; v3 c3 = v3_expr(c.center.x, p_back.y, c.center.z); result.surf_norm = v3_norm(v3_sub(c3,p_back)); } } return result; }
hit_test intersect_poster (ray r, poster p) { hit_test result = {0}; v3 ro = r.origin; v3 rd = r.direction; v3 n = v3_expr(0, 0, -1); double d = p.upper_left.z; double t = -(v3_dot(ro, n) + d) / v3_dot(rd, n); result.miss = MISS; v3 intersection = ray_position(r, t); if (t>0 && within_poster(intersection, p)) { result.miss = HIT; result.t = t; result.hit_point = intersection; result.surf = p.surface_color(p.upper_left, intersection); result.shine = p.shine; result.surf_norm = n; } return result; }