double inter_triangle(t_object *obj, t_ray *ray) { t_triangle *tri; t_vec w; t_vec tmp; double d; double a; double b; double t; tri = &obj->prim.triangle; normalize(&ray->dir); if (!(d = -dot_product(&ray->dir, &tri->normal))) // si le triangle est parallele au rayon, on return 0 return (0); w.x = ray->ori.x - tri->v1.x; w.y = ray->ori.y - tri->v1.y; w.z = ray->ori.z - tri->v1.z; mul_vec(&tmp, &w, &tri->v3); a = -dot_product(&tmp, &ray->dir) / d; mul_vec(&tmp, &tri->v2, &w); b = -dot_product(&tmp, &ray->dir) / d; mul_vec(&tmp, &tri->v2, &tri->v3); t = dot_product(&tmp, &w) / d; if (a > 0 && b > 0 && a + b <= 1) return (t); return (0); }
float CylinderObject::hit_test(const Ray &ray, Vector &normal, const Point *max_pos, bool *inside) { Ray inv_ray; inv_ray.origin = mul_point(inv_trans, ray.origin); inv_ray.direction = mul_vec(inv_trans, ray.direction); inv_ray.direction.normalize(); Vector c_normal; bool c_inside; double t = FLT_MAX; // check collision with cylinder body double c_t = hit_cylinder(inv_ray, c_normal, c_inside); if(c_t > FLT_EPSILON && c_t < t) { t = c_t; normal = c_normal; if(inside) *inside = c_inside; } // check collision with bottom disk c_t = hit_disk(inv_ray, c_normal, Vector(0, -1, 0), Point(0, bottom, 0)); if(c_t > FLT_EPSILON && c_t < t) { t = c_t; normal = c_normal; if(inside) *inside = false; } // check collision with top disk c_t = hit_disk(inv_ray, c_normal, Vector(0, 1, 0), Point(0, top, 0)); if(c_t > FLT_EPSILON && c_t < t) { t = c_t; normal = c_normal; if(inside) *inside = false; } double max_t; if(max_pos) max_t = (max_pos->x - ray.origin.x) / ray.direction.x; else max_t = FLT_MAX; if(t < max_t) { normal = mul_vec(inv_trans, normal); normal.normalize(); return t; } else return -1.0; }
float SphereObject::hit_test(const Ray &ray, Vector &normal, const Point *max_pos, bool *inside) { Ray inv_ray; inv_ray.origin = mul_point(inv_trans, ray.origin); inv_ray.direction = mul_vec(inv_trans, ray.direction); inv_ray.direction.normalize(); Vector e = (inv_ray.origin - pos); double a = Vector::dot(inv_ray.direction, inv_ray.direction); double b = 2.0f * Vector::dot(inv_ray.direction, e); double c = Vector::dot(e, e) - std::pow(radius, 2); double delta = std::pow(b, 2) - 4*a*c; if(delta < FLT_EPSILON) return -1.0f; // Resolving the equation. delta = std::sqrt(delta); // Test both solutions. double t1 = (-b - delta) / (2.0f * a); double t2 = (-b + delta) / (2.0f * a); // Calculate the maximum t. double max_t; if(max_pos) max_t = (max_pos->x - inv_ray.origin.x) / inv_ray.direction.x; else max_t = FLT_MAX; // t1 is always smaller than t2 because it uses -b -discriminant. if(t1 > FLT_EPSILON && t1 < max_t) { if(inside) *inside = false; Point intersection = inv_ray.origin + t1 * inv_ray.direction; normal = (intersection - pos).normalize(); normal = mul_vec(inv_trans, normal); normal.normalize(); return t1; } else if(t2 > FLT_EPSILON && t2 < max_t) { if(inside) *inside = true; Point intersection = inv_ray.origin + t2* inv_ray.direction; normal = (intersection - pos).normalize(); normal = mul_vec(inv_trans, normal); normal.normalize(); return t2; } else return -1.0f; }
int ft_interconew(t_vec rayorg, t_vec raydir, t_obj *obj) { t_cylinder cone; cone.a = ft_dotw(raydir, raydir) - obj->radius * (raydir.w * raydir.w); cone.b = ft_dotw(mul_vec(sub_vec(rayorg, obj->pos), 2.0), raydir) \ - obj->radius * (raydir.w * raydir.w); cone.c = ft_dotw(obj->pos, obj->pos) + ft_dotw(rayorg, rayorg) - (2.0 * \ ft_dotw(rayorg, obj->pos)) - obj->radius * (raydir.w * raydir.w); cone.delt = pow(cone.b, 2) - (4.0 * cone.a * cone.c); if (cone.delt >= 0) { cone.a1 = ((-1.0 * cone.b) - sqrt(cone.delt)) / (2.0 * cone.a); cone.b1 = ((-1.0 * cone.b) + sqrt(cone.delt)) / (2.0 * cone.a); if (cone.b1 > cone.a1) cone.ret = cone.a1; else cone.ret = cone.b1; if (cone.a1 <= 0 && cone.b1 <= 0) return (0); } else return (0); return (cone.ret); }
t_vec raytracer(t_rayparams *params) { t_raytracer *ray; ray = init_ray(params->over.l); first_loop(ray, params->dir, params->o); if (!ray->ret) return (ray->color); *(params->distance) = ray->ret2; if (ray->ret->light == TRUE) return (set_vec(1, 1, 1)); ray->pi = add_vec(params->o, mul_vec(params->dir, ray->ret2)); ray->tmp = params->over.l; while (ray->tmp) { if (ray->tmp->light == TRUE) { set_nray(ray, params->over.l, params->dir, params->o); shade(ray, params->dir); } ray->tmp = ray->tmp->next; } reflexion(ray, params); refraction(ray, params); return (ray->color); }
void specular(t_raytracer *ray, t_vec dir) { t_specular spc; if (ray->ret->specular > 0) { spc.r_spect = 2.0f * DOT(ray->l, ray->n); spc.r_spec = mul_vec(ray->n, spc.r_spect); spc.r_spec = sub_vec(ray->l, spc.r_spec); spc.dot_spec = DOT(dir, spc.r_spec); if (spc.dot_spec > 0) { spc.spect_diff = powf(spc.dot_spec, 20) * ray->ret->specular * ray->shade; spc.ret_spec = mul_vec(ray->tmp->col, spc.spect_diff); ray->color = add_vec(ray->color, spc.ret_spec); } } }
void set_nray(t_raytracer *ray, t_obj *l, t_vec dir, t_vec o) { ray->shade = 1.0f; if (ray->tmp->type == SPHERE) tmp_type_sphere(ray, l); if (ray->ret->type == SPHERE) { ray->n = sub_vec(ray->pi, ray->ret->pos); ray->n = mul_vec(ray->n, 1.0f / ray->ret->radius); } else if (ray->ret->type == PLAN) ray->n = ray->ret->pos; else ray->n = set_nvec(ray->ret, dir, o, ray->ret2); }
float TorusObject::hit_test(const Ray &ray, Vector &normal, const Point *max_pos, bool *inside) { Ray inv_ray; inv_ray.origin = mul_point(inv_trans, ray.origin); inv_ray.direction = mul_vec(inv_trans, ray.direction); inv_ray.direction.normalize(); double x1 = inv_ray.origin.x; double y1 = inv_ray.origin.y; double z1 = inv_ray.origin.z; double d1 = inv_ray.direction.x; double d2 = inv_ray.direction.y; double d3 = inv_ray.direction.z; double coeffs[5]; // coefficient array double roots[4]; // solution array //define the coefficients double sum_d_sqrd = d1*d1 + d2*d2 + d3*d3; double e = x1*x1 + y1*y1 + z1*z1 - radius*radius - thickness*thickness; double f = x1*d1 + y1*d2 + z1*d3; double four_a_sqrd = 4.0 * radius*radius; coeffs[0] = e*e - four_a_sqrd * (thickness*thickness-y1*y1); // constante term coeffs[1] = 4.0 * f * e + 2.0 * four_a_sqrd * y1 *d2; coeffs[2] = 2.0 * sum_d_sqrd * e + 4.0 * f * f + four_a_sqrd * d2 * d2; coeffs[3] = 4.0 * sum_d_sqrd * f; coeffs[4] = sum_d_sqrd * sum_d_sqrd; // coefficient of t^4 //fin the roots int num_real_roots = solveQuartic(coeffs, roots); bool intersected = false; double t = FLT_MAX; if ( num_real_roots == 0) // ray misses the torus return -1.0; //find the smallest root greater than FLT_EPSILON, if any for( int j = 0; j < num_real_roots; j++) { if(roots[j] > FLT_EPSILON) { intersected = true; if(roots[j] < t) t = roots[j]; } } double max_t; if(max_pos) max_t = (max_pos->x - ray.origin.x) / ray.direction.x; else max_t = FLT_MAX; if( t > max_t || !intersected) return -1.0; Point hit = inv_ray.origin + t*inv_ray.direction; normal = compute_normal(hit); normal = mul_vec(inv_trans, normal); normal.normalize(); return t; }