/* * path trace across whole screen image. */ void ri_transport_pathtrace(const ri_display_drv_t *ddrv) { int i; int x, y; int nsamples; /* nsamples per pixel */ int ntotalpixels; int nfinishedpixels; double dcol[3]; /* tempolary color buffer */ float fcol[3]; ri_option_t *opt; /* rendering options */ ri_vector_t radiance; /* Initialize */ opt = ri_render_get()->context->option; pixwidth = opt->camera->horizontal_resolution; pixheight = opt->camera->vertical_resolution; nsamples = opt->pt_nsamples; ntotalpixels = pixwidth * pixheight * nsamples; nfinishedpixels = 0; light = (ri_light_t *)(ri_list_first(ri_render_get()->lightlist)->data); get_camera(&cam_pos, &cam_dir, &c2w); /* for each pixel, trace nsamples rays. */ for (x = 0; x < pixwidth; x++) { for (y = pixheight - 1; y >= 0; y--) { dcol[0] = 0.0; dcol[1] = 0.0; dcol[2] = 0.0; for (i = 0; i < nsamples; i++) { trace_pixel(&radiance, x, y); // add_color(x, y, radiance); dcol[0] += (double)radiance.f[0]; dcol[1] += (double)radiance.f[1]; dcol[2] += (double)radiance.f[2]; } nfinishedpixels += nsamples; #if 0 printf("%f %% finished\r", (float)(nfinishedpixels * 100.0 / ntotalpixels)); fflush(stdout); #endif fcol[0] = (float)(dcol[0] / (double)nsamples); fcol[1] = (float)(dcol[1] / (double)nsamples); fcol[2] = (float)(dcol[2] / (double)nsamples); ddrv->write(x, pixheight - 1 - y, &fcol[0]); } } }
/** * Raytraces some portion of the scene. Should raytrace for about * max_time duration and then return, even if the raytrace is not copmlete. * The results should be placed in the given buffer. * @param buffer The buffer into which to place the color data. It is * 32-bit RGBA (4 bytes per pixel), in row-major order. * @param max_time, If non-null, the maximum suggested time this * function raytrace before returning, in seconds. If null, the raytrace * should run to completion. * @return true if the raytrace is complete, false if there is more * work to be done. */ bool Raytracer::raytrace( unsigned char *buffer, real_t* max_time ) { // TODO Add any modifications to this algorithm, if needed. static long start_time; // used to show how long time ray tracing cost if (0 == current_row) start_time = clock(); static const size_t PRINT_INTERVAL = 64; // the time in milliseconds that we should stop unsigned int end_time = 0; bool is_done = false; if ( max_time ) { // convert duration to milliseconds unsigned int duration = (unsigned int) ( *max_time * 1000 ); end_time = SDL_GetTicks() + duration; } // until time is up, run the raytrace. we render an entire row at once // for simplicity and efficiency. for ( ; !max_time || end_time > SDL_GetTicks(); ++current_row ) { if ( current_row % PRINT_INTERVAL == 0 ) { printf( "Raytracing (row %u)...\n", current_row ); } // we're done if we finish the last row is_done = current_row == height; // break if we finish if ( is_done ) break; for ( size_t x = 0; x < width; ++x ) { // trace a pixel Color3 color = trace_pixel( scene, x, current_row, width, height ); // write the result to the buffer, always use 1.0 as the alpha color.to_array( &buffer[4 * ( current_row * width + x )] ); } } if ( is_done ) { printf( "Done raytracing!\n" ); printf( "Used %d milliseconds.\n", clock()-start_time ); } return is_done; }
// Raytraces some portion of the scene bool Raytracer::raytrace( unsigned char *buffer, real_t* max_time ) { static const size_t PRINT_INTERVAL = 64; unsigned int end_time = 0; bool is_done; if ( max_time ) { // convert duration to milliseconds unsigned int duration = (unsigned int) ( *max_time * 1000 ); end_time = SDL_GetTicks() + duration; } // until time is up, run the raytrace. we render an entire row at once for ( ; !max_time || end_time > SDL_GetTicks(); ++current_row ) { if ( current_row % PRINT_INTERVAL == 0 ) { printf( "Raytracing (row %u)...\n", current_row ); } // we're done if we finish the last row is_done = current_row == height; if ( is_done ) break; for ( size_t x = 0; x < width; ++x ) { // trace a pixel Color3 color = trace_pixel( scene, x, current_row, width, height ); color.to_array( &buffer[4 * ( current_row * width + x )] ); } } if ( is_done ) { printf( "Done raytracing!\n" ); } return is_done; }
/** * Performs a raytrace on the given pixel on the current scene. * The pixel is relative to the bottom-left corner of the image. */ Color3 Raytracer::trace_pixel(int recursions, const Ray& ray, float refractive) { size_t num_geometries = scene->num_geometries(); bool hit_any = false; // if any geometries were hit IsectInfo min_info; // everything we're calculating from intersection Vector3 intersection_point = Vector3::Zero; // run intersection test on every object in scene for (size_t i = 0; i < num_geometries; i++) { IsectInfo info; // intersect returns true if there's a hit, false if not, and sets // values in info struct bool hit = scene->get_geometries()[i]->intersect_ray(ray, info); if (hit && info.time < min_info.time) // min_info.time initializes to inf { min_info = info; intersection_point = ray.eye + (min_info.time * ray.dir); hit_any = true; } } // found a hit if (hit_any) { Color3 direct; Color3 diffuse = Color3::Black; Color3 ambient = scene->ambient_light * min_info.ambient; float angle = dot(ray.dir, min_info.normal); // compute reflected ray Ray incident_ray; incident_ray.dir = ray.dir - 2 * angle * min_info.normal; incident_ray.dir = normalize(incident_ray.dir); incident_ray.eye = intersection_point + eps * incident_ray.dir; // no-refraction case if (min_info.refractive == 0.0) { diffuse = get_diffuse(incident_ray.eye, min_info.normal, min_info.diffuse, eps); direct = min_info.texture * (ambient + diffuse); // return direct light and reflected light if we have recursions left if (recursions >= max_recursion_depth) { return direct; } return direct + min_info.texture * min_info.specular * trace_pixel(recursions + 1, incident_ray, refractive); } // refraction case else { // return black if no more recursions if (recursions >= max_recursion_depth) { return Color3::Black; } float c; Ray transmitted_ray; float refract_ratio = refractive / min_info.refractive; // negative dot product between ray and normal indicates entering object if (angle < 0.0) { refract(ray.dir, min_info.normal, refract_ratio, &transmitted_ray.dir); c = dot(-1.0 * ray.dir, min_info.normal); } else { // exiting object if (refract(ray.dir, (-1.0 * min_info.normal), min_info.refractive, &transmitted_ray.dir)) { c = dot(transmitted_ray.dir, min_info.normal); } // total internal reflection else { return trace_pixel(recursions + 1, incident_ray, refractive); } } // schlick approximation to fresnel equations float R_0 = pow(refract_ratio - 1, 2) / pow(refract_ratio + 1, 2); float R = R_0 + (1 - R_0) * pow(1 - c, 5); transmitted_ray.eye = intersection_point + eps * transmitted_ray.dir; // return reflected and refracted rays return R * trace_pixel(recursions + 1, incident_ray, refractive) + (1.0 - R) * trace_pixel(recursions + 1, transmitted_ray, min_info.refractive); } } // didn't hit anything - return background color else { return scene->background_color; } }
Color3 Raytracer::trace_pixel_end(int recursions, const Ray& ray, float refractive, IsectInfo min_info) { Color3 direct; Color3 diffuse = Color3::Black; Color3 ambient = scene->ambient_light * min_info.ambient; float angle = dot(ray.dir, min_info.normal); // compute reflected ray Vector3 intersection_point = ray.eye + (min_info.time * ray.dir); Ray incident_ray; incident_ray.dir = ray.dir - 2 * angle * min_info.normal; incident_ray.dir = normalize(incident_ray.dir); incident_ray.eye = intersection_point + eps * incident_ray.dir; // no-refraction case if (min_info.refractive == 0.0) { diffuse = get_diffuse(incident_ray.eye, min_info.normal, min_info.diffuse, eps); direct = min_info.texture * (ambient + diffuse); // return direct light and reflected light if we have recursions left if (recursions >= max_recursion_depth) { return direct; } return direct + min_info.texture * min_info.specular * trace_pixel(recursions + 1, incident_ray, refractive); } // refraction case else { // return black if no more recursions if (recursions >= max_recursion_depth) { return Color3::Black; } float c; Ray transmitted_ray; float refract_ratio = refractive / min_info.refractive; // negative dot product between ray and normal indicates entering object if (angle < 0.0) { refract(ray.dir, min_info.normal, refract_ratio, &transmitted_ray.dir); c = dot(-1.0 * ray.dir, min_info.normal); } else { // exiting object if (refract(ray.dir, (-1.0 * min_info.normal), min_info.refractive, &transmitted_ray.dir)) { c = dot(transmitted_ray.dir, min_info.normal); } // total internal reflection else { return trace_pixel(recursions + 1, incident_ray, refractive); } } // schlick approximation to fresnel equations float R_0 = pow(refract_ratio - 1, 2) / pow(refract_ratio + 1, 2); float R = R_0 + (1 - R_0) * pow(1 - c, 5); transmitted_ray.eye = intersection_point + eps * transmitted_ray.dir; // return reflected and refracted rays return R * trace_pixel(recursions + 1, incident_ray, refractive) + (1.0 - R) * trace_pixel(recursions + 1, transmitted_ray, min_info.refractive); } }