vec3 trace(const ray& theray, const world* world, const vec3& light_dir) { range r(0, std::numeric_limits<float>::max()); surface_hit hit; hit.t = std::numeric_limits<float>::max(); ray object_ray = transform_ray(theray, world->object_matrix, world->object_normal_matrix); bool have_hit = world->root->intersect(object_ray, r, &hit); if(!have_hit) return world->background; vec4 n1(hit.normal.x, hit.normal.y, hit.normal.z, 0.0), n2; vec4 p1(hit.point.x, hit.point.y, hit.point.z, 1.0), p2; n2 = mat4_mult_vec4(world->object_normal_inverse, n1); p2 = mat4_mult_vec4(world->object_inverse, p1); vec3 normal = vec3(n2.x, n2.y, n2.z); vec3 point = vec3(p2.x, p2.y, p2.z); float brightness; float shadowed = false; if(cast_shadows) { struct ray shadowray; shadowray.o = vec3_add(point, vec3_scale(normal, .0001)); shadowray.d = light_dir; surface_hit shadow_hit; shadow_hit.t = std::numeric_limits<float>::max(); ray object_ray = transform_ray(shadowray, world->object_matrix, world->object_normal_matrix); shadowed = world->root->intersect(object_ray, range(0, std::numeric_limits<float>::max()), &shadow_hit); } if(shadowed) { brightness = .1; } else { brightness = vec3_dot(normal, light_dir); if(brightness < 0) brightness = 0; if(brightness > 1) brightness = 1; } return vec3_scale(hit.color, brightness); }
float Sphere::intersectT(Ray ray) { ray = transform_ray(ray); Vector pos = ray.position; Vector dir = ray.direction; float a = Vector::dot(dir, dir); float b = 2 * (Vector::dot(dir, pos - center)); float c = Vector::dot(pos - center, pos - center) - radius * radius; float discriminant = b * b - 4 * a * c; if (discriminant >= 0) { float t1 = (-b - sqrt(discriminant)) / (2 * a); float t2 = (-b + sqrt(discriminant)) / (2 * a); if (t1 >= ray.t_min && t1 <= ray.t_max) { return t1; } else if (t2 >= ray.t_min && t2 <= ray.t_max) { return t2; } else { return -1; } } return -1; }
void trace_image(int width, int height, float aspect, unsigned char *image, const world* world, const vec3& light_dir) { #pragma omp parallel for schedule(dynamic) for(int yloop = 0; yloop < height; yloop++) { unsigned char *row = image + (height - yloop - 1) * (((width * 3) + 3) & ~3); for(int xloop = 0; xloop < width; xloop++) { // printf("%d, %d\n", xloop, yloop); int cols = 0; vec3 color(0, 0, 0); for(int qky = 0; qky < world->ysub; qky++) { for(int qkx = 0; qkx < world->xsub; qkx++) { float u = ((xloop + qkx / (float)world->xsub) + .5) / width; float v = ((yloop + qky / (float)world->ysub) + .5) / height; ray eye_ray; eye_ray.d = make_eye_ray(u, v, aspect, world->cam.fov); eye_ray.o = vec3(0, 0, 0); ray world_ray = transform_ray(eye_ray, world->camera_matrix, world->camera_normal_matrix); vec3 sample = trace(world_ray, world, light_dir); color = vec3_add(color, sample); ++cols; } } vec3 final_color = vec3_divide(color, cols); unsigned char *pixel = row + xloop * 3; pixel[0] = final_color.x * 255; pixel[1] = final_color.y * 255; pixel[2] = final_color.z * 255; } } }
/* * Intersect with the ray, but do so in object space. * * First, transform ray into object space. Use the methods you have * implemented for this. * Then, intersect the object with the transformed ray. * Finally, make sure you transform the intersection back into world space. * * isect is guaranteed to be a valid pointer. * The method shall return true if an intersection was found and false otherwise. * * isect must be filled properly if an intersection was found. */ bool Object:: intersect(Ray const& ray, Intersection* isect) const { cg_assert(isect); if (RaytracingContext::get_active()->params.transform_objects) { // TODO: transform ray, intersect object, transform intersection // information back Ray transformedRay = transform_ray(ray, Object::transform_world_to_object); if (geo->intersect(transformedRay, isect)) { *isect = transform_intersection(*isect, Object::transform_object_to_world, Object::transform_object_to_world_normal); isect->t = glm::distance(ray.origin, isect->position); return true; } else return false; } return geo->intersect(ray, isect); }
void get_nearest_cylinder(t_vector ray, t_object *cylinder, t_surface *surface, t_scene *scene) { t_double2 distance; t_surface *tmp; t_vector ray_s; ray_s = transform_ray(ray, cylinder); if (intersect_cylinder(ray_s, cylinder, &distance)) { tmp = cut_object(ray, cylinder, distance, scene); if (tmp->object != NULL && (surface->distance == -1 || surface->distance > tmp->distance)) { surface->object = tmp->object; surface->distance = tmp->distance; surface->normal = tmp->normal; // surface->color = tmp->object->color; surface->color = cylindrical_mapping(scene, surface, ray_s, cylinder); free(tmp); } } }
roots intersection_with_ray(sphere s, ray r) { // We need r in sphere-coordinates ray r_sphere_coordinates; matrix s_transform_inverse = inverse_of_matrix(s.transform); r_sphere_coordinates.point = transform_point(s_transform_inverse, r.point); r_sphere_coordinates.direction = transform_ray(s_transform_inverse, r.direction); vector point_minus_center = subtract_vectors(r_sphere_coordinates.point, s.center); float polynomials[3]; polynomials[2] = square_of_magnitude_of_vector(r_sphere_coordinates.direction); polynomials[1] = 2 * dot_product(point_minus_center, r_sphere_coordinates.direction); polynomials[0] = square_of_magnitude_of_vector(point_minus_center) - s.radius * s.radius; roots quad_roots; quad_roots = quadratic(polynomials[2], polynomials[1], polynomials[0]); return quad_roots; }