glm::vec3 DirectLightingIntegrator::LightPDFEnergy(const Intersection &light_sample_isx, const Intersection &isx, const Ray &light_sample, const glm::vec3 &woW, unsigned int n_light, unsigned int n_brdf) { glm::vec3 ray_color(0, 0, 0); Material* M = isx.object_hit->material; //material of point hit Geometry* L = light_sample_isx.object_hit; //light source float lightPDF = L->RayPDF(light_sample_isx, light_sample); //if light pdf is less than zero, return no light if (lightPDF <= 0.0f) { return glm::vec3(0); } //get BRDFPDF and energy from the material float brdfPDF; float dummy; glm::vec3 M_energy(M->EvaluateScatteredEnergy(isx, woW, light_sample.direction, brdfPDF)); //terminate early if brdf pdf is zero; if (brdfPDF <= 0.0f) return ray_color; glm::vec3 L_energy(L->material->EvaluateScatteredEnergy(light_sample_isx, woW, -light_sample.direction, dummy)); float W = MIS(lightPDF, brdfPDF); //MIS power heuristic weighing function ray_color = ComponentMult(L_energy, M_energy); // multiply the energy of the light with BRDF reflected energy ray_color = ComponentMult(ComponentMult(ray_color, M->base_color), isx.texture_color); ray_color = ray_color*W/lightPDF*glm::abs(glm::dot(isx.normal, light_sample.direction)); // and then do the solid angle PDF and the cosine return ray_color; }
glm::vec3 Integrator::CalculateEnergy(const Intersection &light_sample_isx, const Intersection &isx, const Ray &light_sample, const glm::vec3 &woW) { glm::vec3 ray_color(0, 0, 0); Material* M = isx.object_hit->material; //material of point hit Geometry* L = light_sample_isx.object_hit; //light source float dummy; //Intersection isx_light = L->GetIntersection(light_sample); ray_color = ComponentMult(L->material->EvaluateScatteredEnergy(light_sample_isx, woW, -light_sample.direction, dummy), M->EvaluateScatteredEnergy(isx, woW, light_sample.direction, dummy)); // multiply the energy of the light with BRDF reflected energy ray_color = ray_color/L->RayPDF(light_sample_isx, light_sample)*glm::abs(glm::dot(isx.normal, light_sample.direction)); // and then do the solid angle PDF and the cosine ray_color = glm::clamp(ray_color, 0.0f, 1.0f); return ray_color; }
glm::vec3 DirectLightingIntegrator::BxDFPDFEnergy(const Intersection &isx, const glm::vec3 &woW, unsigned int n_light, unsigned int n_brdf) { glm::vec3 ray_color(0, 0, 0); glm::vec3 wiW(0, 0, 0);//this will be obtained by sampling BxDf Material* M = isx.object_hit->material; //material of point hit float brdfPDF; float lightPDF; float dummy; float rand1 = unif_distribution(mersenne_generator); float rand2 = unif_distribution(mersenne_generator); glm::vec3 M_energy(M->SampleAndEvaluateScatteredEnergy(isx, woW, wiW, brdfPDF, rand1, rand2)); //use sampled wiW to check if I can hit the light Ray shadow_feeler(isx.point, wiW); Intersection light_isx = intersection_engine->GetIntersection(shadow_feeler); Geometry* L; //this holds the intersected light source //terminate early if brdf pdf is zero; if (brdfPDF <= 0.0f) return ray_color; if (light_isx.object_hit == NULL)//if ray didnt hit anything return ray_color; if (light_isx.object_hit->material->is_light_source) { L = light_isx.object_hit; lightPDF = L->RayPDF(light_isx, shadow_feeler); if (lightPDF <= 0) { return ray_color; } glm::vec3 L_energy(L->material->EvaluateScatteredEnergy(light_isx, woW, -shadow_feeler.direction, dummy)); float W = MIS(brdfPDF, lightPDF); ray_color = ComponentMult(L_energy, M_energy); ray_color = ComponentMult(ComponentMult(ray_color, M->base_color), isx.texture_color); ray_color = ray_color*W/brdfPDF*glm::abs(glm::dot(isx.normal, shadow_feeler.direction)); return ray_color; } else { return ray_color; } }
static unsigned int ray_color(const point3 e, double t, const point3 d, idx_stack *stk, const rectangular_node rectangulars, const sphere_node spheres, const light_node lights, color object_color, int bounces_left) { rectangular_node hit_rec = NULL, light_hit_rec = NULL; sphere_node hit_sphere = NULL, light_hit_sphere = NULL; double diffuse, specular; point3 l, _l, r, rr; object_fill fill; color reflection_part; color refraction_part; /* might be a reflection ray, so check how many times we've bounced */ if (bounces_left == 0) { SET_COLOR(object_color, 0.0, 0.0, 0.0); return 0; } /* check for intersection with a sphere or a rectangular */ intersection ip= ray_hit_object(e, d, t, MAX_DISTANCE, rectangulars, &hit_rec, spheres, &hit_sphere); if (!hit_rec && !hit_sphere) return 0; /* pick the fill of the object that was hit */ fill = hit_rec ? hit_rec->element.rectangular_fill : hit_sphere->element.sphere_fill; void *hit_obj = hit_rec ? (void *) hit_rec : (void *) hit_sphere; /* assume it is a shadow */ SET_COLOR(object_color, 0.0, 0.0, 0.0); for (light_node light = lights; light; light = light->next) { /* calculate the intersection vector pointing at the light */ subtract_vector(ip.point, light->element.position, l); multiply_vector(l, -1, _l); normalize(_l); /* check for intersection with an object. use ignore_me * because we don't care about this normal */ ray_hit_object(ip.point, _l, MIN_DISTANCE, length(l), rectangulars, &light_hit_rec, spheres, &light_hit_sphere); /* the light was not block by itself(lit object) */ if (light_hit_rec || light_hit_sphere) continue; compute_specular_diffuse(&diffuse, &specular, d, l, ip.normal, fill.phong_power); localColor(object_color, light->element.light_color, diffuse, specular, &fill); } reflection(r, d, ip.normal); double idx = idx_stack_top(stk).idx, idx_pass = fill.index_of_refraction; if (idx_stack_top(stk).obj == hit_obj) { idx_stack_pop(stk); idx_pass = idx_stack_top(stk).idx; } else { idx_stack_element e = { .obj = hit_obj, .idx = fill.index_of_refraction }; idx_stack_push(stk, e); } refraction(rr, d, ip.normal, idx, idx_pass); double R = (fill.T > 0.1) ? fresnel(d, rr, ip.normal, idx, idx_pass) : 1.0; /* totalColor = localColor + mix((1-fill.Kd) * fill.R * reflection, T * refraction, R) */ if (fill.R > 0) { /* if we hit something, add the color */ int old_top = stk->top; if (ray_color(ip.point, MIN_DISTANCE, r, stk, rectangulars, spheres, lights, reflection_part, bounces_left - 1)) { multiply_vector(reflection_part, R * (1.0 - fill.Kd) * fill.R, reflection_part); add_vector(object_color, reflection_part, object_color); } stk->top = old_top; } /* calculate refraction ray */ if ((length(rr) > 0.0) && (fill.T > 0.0) && (fill.index_of_refraction > 0.0)) { normalize(rr); if (ray_color(ip.point, MIN_DISTANCE, rr, stk,rectangulars, spheres, lights, refraction_part, bounces_left - 1)) { multiply_vector(refraction_part, (1 - R) * fill.T, refraction_part); add_vector(object_color, refraction_part, object_color); } } protect_color_overflow(object_color); return 1; } /* @param background_color this is not ambient light */ void raytracing(void* args) { arg *data = (arg*) args; point3 u, v, w, d; color object_color = { 0.0, 0.0, 0.0 }; const viewpoint *view = (*data).View; color back = { 0.0 , 0.1 , 0.1 }; uint8_t *pixels = data->pixels; int start_j,end_j; /* Separate to count the pixels */ if(pthread_equal(pthread_self(),THREAD[0])) { start_j = 0; end_j = 128; } else if(pthread_equal(pthread_self(),THREAD[1])) { start_j = 128; end_j = 256; } else if(pthread_equal(pthread_self(),THREAD[2])) { start_j = 256; end_j = 384; } else if(pthread_equal(pthread_self(),THREAD[3])) { start_j = 384; end_j = 512; } /* calculate u, v, w */ calculateBasisVectors(u, v, w, view); idx_stack stk; int factor = sqrt(SAMPLES); #pragma omp parallel for num_threads(64) \ private(stk), private(d), \ private(object_color) for (int j = start_j ; j < end_j; j++) { for (int i = 0 ; i < (*data).row; i++) { double r = 0, g = 0, b = 0; /* MSAA */ for (int s = 0; s < SAMPLES; s++) { idx_stack_init(&stk); rayConstruction(d, u, v, w, i * factor + s / factor, j * factor + s % factor, view, (*data).row * factor, (*data).col * factor); if (ray_color(view->vrp, 0.0, d, &stk,(*data).rectangulars, (*data).spheres, (*data).lights, object_color, MAX_REFLECTION_BOUNCES)) { r += object_color[0]; g += object_color[1]; b += object_color[2]; } else { r += back[0]; g += back[1]; b += back[2]; } pixels[((i + (j * (*data).row)) * 3) + 0] = r * 255 / SAMPLES; pixels[((i + (j * (*data).row)) * 3) + 1] = g * 255 / SAMPLES; pixels[((i + (j * (*data).row)) * 3) + 2] = b * 255 / SAMPLES; } } } }
void ray_trace(void) { vec3 forward_vector, right_vector, up_vector; int i, j; float image_plane_width, image_plane_height; vec3 color; char buf[128]; struct timeval t0, t1; float time_taken; fprintf(stderr, "Ray tracing ..."); gettimeofday(&t0, NULL); num_rays_shot = num_shadow_rays_shot = num_triangles_tested = num_bboxes_tested = 0; // Compute camera coordinate system from camera position // and look-at point up_vector = v3_create(0, 0, 1); forward_vector = v3_normalize(v3_subtract(scene_camera_lookat, scene_camera_position)); right_vector = v3_normalize(v3_crossprod(forward_vector, up_vector)); up_vector = v3_crossprod(right_vector, forward_vector); // Compute size of image plane from the chosen field-of-view // and image aspect ratio. This is the size of the plane at distance // of one unit from the camera position. image_plane_height = 2.0 * tan(0.5*VFOV/180*M_PI); image_plane_width = image_plane_height * (1.0 * framebuffer_width / framebuffer_height); vec3 d, e, u, v, w, ud, vd; float l, r, b, t, nx, ny; // direction d, origin e // ONB u, v, w // image plane edges l, r, b, t // window size nx, ny e = scene_camera_position; u = right_vector, v = up_vector, w = v3_negate(forward_vector); l = -0.5 * image_plane_width, r = 0.5 * image_plane_width; b = 0.5 * image_plane_height, t = -0.5 * image_plane_height; nx = framebuffer_width, ny = framebuffer_height; // Loop over all pixels in the framebuffer for (j = 0; j < ny; j++) { for (i = 0; i < nx; i++) { ud = v3_multiply(u, (l + (r - l) * ((i + 0.5) / nx))); vd = v3_multiply(v, (b + (t - b) * ((j + 0.5) / ny))); d = v3_add(v3_add(ud, vd), v3_negate(w)); color = ray_color(0, e, d); put_pixel(i, j, color.x, color.y, color.z); } sprintf(buf, "Ray-tracing ::: %.0f%% done", 100.0*j/framebuffer_height); glutSetWindowTitle(buf); } // Done! gettimeofday(&t1, NULL); glutSetWindowTitle("Ray-tracing ::: done"); // Output some statistics time_taken = 1.0 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1000000.0; fprintf(stderr, " done in %.1f seconds\n", time_taken); fprintf(stderr, "... %lld total rays shot, of which %d camera rays and " "%lld shadow rays\n", num_rays_shot, do_antialiasing ? 4*framebuffer_width*framebuffer_height : framebuffer_width*framebuffer_height, num_shadow_rays_shot); fprintf(stderr, "... %lld triangles intersection tested " "(avg %.1f tri/ray)\n", num_triangles_tested, 1.0*num_triangles_tested/num_rays_shot); fprintf(stderr, "... %lld bboxes intersection tested (avg %.1f bbox/ray)\n", num_bboxes_tested, 1.0*num_bboxes_tested/num_rays_shot); }
// Returns final color uint8_t raytrace(vec3 pos, vec3 dir, hit* info) { // Finish early if there's no direction if (dir.x == 0.0f && dir.y == 0.0f && dir.z == 0.0f) { goto nohit; } vec3 start = pos; int x = (int) pos.x; int y = (int) pos.y; int z = (int) pos.z; int x_dir = dir.x >= 0.0f ? 1 : -1; int y_dir = dir.y >= 0.0f ? 1 : -1; int z_dir = dir.z >= 0.0f ? 1 : -1; float dx_off = x_dir > 0 ? 1.0f : 0.0f; float dy_off = y_dir > 0 ? 1.0f : 0.0f; float dz_off = z_dir > 0 ? 1.0f : 0.0f; int x_face = x_dir > 0 ? FACE_LEFT : FACE_RIGHT; int y_face = y_dir > 0 ? FACE_BOTTOM : FACE_TOP; int z_face = z_dir > 0 ? FACE_BACK : FACE_FRONT; int face = FACE_TOP; // Assumption is made that the camera is never outside the world while (IN_WORLD(x, y, z)) { // Determine if block is solid if (get_block(x, y, z) != BLOCK_AIR) { float dx = start.x - pos.x; float dy = start.y - pos.y; float dz = start.z - pos.z; float dist = dx*dx + dy*dy + dz*dz; vec3 relPos = pos; relPos.x -= x; relPos.y -= y; relPos.z -= z; // If hit info is requested, no color computation is done if (info != NULL) { int nx, ny, nz; face_normal(face, &nx, &ny, &nz); info->hit = true; info->x = x; info->y = y; info->z = z; info->nx = nx; info->ny = ny; info->nz = nz; info->dist = dist; return 0; } int tex = tex_index(relPos, face); return ray_color(x, y, z, pos, tex, face); } // Remaining distance inside this block given ray direction float dx = x - pos.x + dx_off; float dy = y - pos.y + dy_off; float dz = z - pos.z + dz_off; // Calculate distance for each dimension float t1 = dx / dir.x; float t2 = dy / dir.y; float t3 = dz / dir.z; // Find closest hit if (t1 <= t2 && t1 <= t3) { pos.x += dx; pos.y += t1 * dir.y; pos.z += t1 * dir.z; x += x_dir; face = x_face; } if (t2 <= t1 && t2 <= t3) { pos.x += t2 * dir.x; pos.y += dy; pos.z += t2 * dir.z; y += y_dir; face = y_face; } if (t3 <= t1 && t3 <= t2) { pos.x += t3 * dir.x; pos.y += t3 * dir.y; pos.z += dz; z += z_dir; face = z_face; } } nohit: if (info != NULL) { info->hit = false; } // Sky color return skyColor; }
void ray_trace(void) { vec3 forward_vector, right_vector, up_vector; int i, j; float image_plane_width, image_plane_height; vec3 color; char buf[128]; struct timeval t0, t1; float time_taken; fprintf(stderr, "Ray tracing ..."); gettimeofday(&t0, NULL); num_rays_shot = num_shadow_rays_shot = num_triangles_tested = num_bboxes_tested = 0; // Compute camera coordinate system from camera position // and look-at point up_vector = v3_create(0, 0, 1); forward_vector = v3_normalize(v3_subtract(scene_camera_lookat, scene_camera_position)); right_vector = v3_normalize(v3_crossprod(forward_vector, up_vector)); up_vector = v3_crossprod(right_vector, forward_vector); // Compute size of image plane from the chosen field-of-view // and image aspect ratio. This is the size of the plane at distance // of one unit from the camera position. image_plane_height = 2.0 * tan(0.5*VFOV/180*M_PI); image_plane_width = image_plane_height * (1.0 * framebuffer_width / framebuffer_height); // vector points to the middle of the monitor vec3 plane_center = v3_add(scene_camera_position, forward_vector); // vector points to the left side of the monitor vec3 le_unnormalized = v3_multiply(right_vector, -(image_plane_width / 2.0)); // vector points to the up side of the monitor vec3 up_unnormalized = v3_multiply(up_vector, image_plane_height / 2.0); // vector points to the coordinates 0,0 (left up) of the monitor vec3 left_up = v3_add(plane_center, v3_add(le_unnormalized, up_unnormalized)); // vector points to right, and has length equal to width of a pixel vec3 pixel2pixel_x = v3_multiply(right_vector, (image_plane_width / framebuffer_width)); // vector points to down, and has length equal to height of a pixel vec3 pixel2pixel_y = v3_multiply(up_vector, -(image_plane_height / framebuffer_height)); // ANTI-ALIASING LOOP if (do_antialiasing) { // loop over all pixels in the framebuffer for (j = 0; j < framebuffer_height; j++) { for (i = 0; i < framebuffer_width; i++) { // for each pixel, shoot four rays vec3 ray_direction_00 = v3_add(v3_add(left_up, v3_multiply(pixel2pixel_y, j + 0.25)), v3_multiply(pixel2pixel_x, i + 0.25)); vec3 ray_direction_01 = v3_add(v3_add(left_up, v3_multiply(pixel2pixel_y, j + 0.75)), v3_multiply(pixel2pixel_x, i + 0.25)); vec3 ray_direction_10 = v3_add(v3_add(left_up, v3_multiply(pixel2pixel_y, j + 0.25)), v3_multiply(pixel2pixel_x, i + 0.75)); vec3 ray_direction_11 = v3_add(v3_add(left_up, v3_multiply(pixel2pixel_y, j + 0.75)), v3_multiply(pixel2pixel_x, i + 0.75)); // for each ray fired, get the difference ray_direction_00 = v3_subtract(ray_direction_00, scene_camera_position); ray_direction_01 = v3_subtract(ray_direction_01, scene_camera_position); ray_direction_10 = v3_subtract(ray_direction_10, scene_camera_position); ray_direction_11 = v3_subtract(ray_direction_11, scene_camera_position); // add the colors of the four rays, then divide by four color = ray_color(0, scene_camera_position, ray_direction_00); color = v3_add(color, ray_color(0, scene_camera_position, ray_direction_01)); color = v3_add(color, ray_color(0, scene_camera_position, ray_direction_10)); color = v3_add(color, ray_color(0, scene_camera_position, ray_direction_11)); color = v3_multiply(color, 0.25); // output pixel color put_pixel(i, j, color.x, color.y, color.z); } sprintf(buf, "Ray-tracing (AA enabled) ::: %.0f%% done", 100.0*j/framebuffer_height); glutSetWindowTitle(buf); } } // NON-ANTI-ALIASING LOOP else { // loop over all pixels in the framebuffer for (j = 0; j < framebuffer_height; j++) { for (i = 0; i < framebuffer_width; i++) { // select the currently relevant pixel vec3 ray_direction = v3_add(v3_add(left_up, v3_multiply(pixel2pixel_y, j + 0.5)), v3_multiply(pixel2pixel_x, i + 0.5)); // get diference between the two points ray_direction = v3_subtract(ray_direction, scene_camera_position); // set color color = ray_color(0, scene_camera_position, ray_direction); // output pixel color put_pixel(i, j, color.x, color.y, color.z); } sprintf(buf, "Ray-tracing ::: %.0f%% done", 100.0*j/framebuffer_height); glutSetWindowTitle(buf); } } // set a detailed title, useful for testing if (use_bvh && do_antialiasing) glutSetWindowTitle("Ray-tracing is done. AA=yes, BVH=yes"); else if (use_bvh && !do_antialiasing) glutSetWindowTitle("Ray-tracing is done. AA=no, BVH=yes"); else if (!use_bvh && do_antialiasing) glutSetWindowTitle("Ray-tracing is done. AA=yes, BVH=no"); else glutSetWindowTitle("Ray-tracing is done. AA=no, BVH=no"); // Done! gettimeofday(&t1, NULL); // Output some statistics time_taken = 1.0 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1000000.0; fprintf(stderr, " done in %.1f seconds\n", time_taken); fprintf(stderr, "... %d total rays shot, of which %d camera rays and %d shadow rays\n", num_rays_shot, do_antialiasing ? 4*framebuffer_width*framebuffer_height : framebuffer_width*framebuffer_height, num_shadow_rays_shot); fprintf(stderr, "... %d triangles intersection tested (avg %.1f tri/ray)\n", num_triangles_tested, 1.0*num_triangles_tested/num_rays_shot); fprintf(stderr, "... %d bboxes intersection tested (avg %.1f bbox/ray)\n", num_bboxes_tested, 1.0*num_bboxes_tested/num_rays_shot); }
void ray_trace(void) { vec3 forward_vector, right_vector, up_vector; int i, j; float image_plane_width, image_plane_height; vec3 color; char buf[128]; struct timeval t0, t1; float time_taken; fprintf(stderr, "Ray tracing ..."); gettimeofday(&t0, NULL); num_rays_shot = num_shadow_rays_shot = num_triangles_tested = num_bboxes_tested = 0; // Compute camera coordinate system from camera position // and look-at point up_vector = v3_create(0, 0, 1); forward_vector = v3_normalize(v3_subtract(scene_camera_lookat, scene_camera_position)); right_vector = v3_normalize(v3_crossprod(forward_vector, up_vector)); up_vector = v3_crossprod(right_vector, forward_vector); // Compute size of image plane from the chosen field-of-view // and image aspect ratio. This is the size of the plane at distance // of one unit from the camera position. image_plane_height = 2.0 * tan(0.5*VFOV/180*M_PI); image_plane_width = image_plane_height * (1.0 * framebuffer_width / framebuffer_height); printf("imageplane: (%f, %f)\n", image_plane_width, image_plane_height); // the borders of the image plane in camera coordinates float left = -(image_plane_width / 2), right = image_plane_width / 2, bottom = (image_plane_height / 2), top = -image_plane_height / 2; // rays are expressed as a location vector and direction vector vec3 ray_origin = scene_camera_position; float u, v, w; // Loop over all pixels in the framebuffer for (j = 0; j < framebuffer_height; j++) { for (i = 0; i < framebuffer_width; i++) { vec3 directions[4]; int directions_i = 0; float offsets[2]; int offsets_n; // if anti-aliasing is activated, shoot 4 rays through each pixel // slightly offset from the center if (do_antialiasing) { offsets_n = 2; offsets[0] = 0.25; offsets[1] = 0.75; } // without anti-aliasing, just send a single ray through the // pixel-center else { offsets_n = 1; offsets[0] = 0.5; } // calculate the [u, v, w] components of the pixel's location // relative to the camera for (int u_offset = 0; u_offset < offsets_n; ++u_offset) { for (int v_offset = 0; v_offset < offsets_n; ++v_offset) { w = 1; u = left + (right - left) * (i + offsets[u_offset]) / framebuffer_width; v = bottom + (top - bottom) * (j + offsets[v_offset]) / framebuffer_height; // the direction of the ray is a a linear combination of the camera // basisvectors directions[directions_i] = v3_add3(v3_multiply(forward_vector, w), v3_multiply(right_vector, u), v3_multiply(up_vector, v)); directions_i += 1; } } // Output average pixel color color = v3_create(0.0, 0.0, 0.0); int num_directions = do_antialiasing ? 2 * offsets_n : 1; for (int dir = 0; dir < num_directions; ++dir) { color = v3_add(color, ray_color(0, ray_origin, directions[dir]) ); } color = v3_multiply(color, 1.0 / num_directions); put_pixel(i, j, color.x, color.y, color.z); } sprintf(buf, "Ray-tracing ::: %.0f%% done", 100.0*j/framebuffer_height); glutSetWindowTitle(buf); } // Done! gettimeofday(&t1, NULL); glutSetWindowTitle("Ray-tracing ::: done"); // Output some statistics time_taken = 1.0 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1000000.0; fprintf(stderr, " done in %.1f seconds\n", time_taken); fprintf(stderr, "... %d total rays shot, of which %d camera rays and %d shadow rays\n", num_rays_shot, do_antialiasing ? 4*framebuffer_width*framebuffer_height : framebuffer_width*framebuffer_height, num_shadow_rays_shot); fprintf(stderr, "... %d triangles intersection tested (avg %.1f tri/ray)\n", num_triangles_tested, 1.0*num_triangles_tested/num_rays_shot); fprintf(stderr, "... %d bboxes intersection tested (avg %.1f bbox/ray)\n", num_bboxes_tested, 1.0*num_bboxes_tested/num_rays_shot); }
void ray_trace(void) { vec3 forward_vector, right_vector, up_vector; int i, j; float image_plane_width, image_plane_height; vec3 color; char buf[128]; struct timeval t0, t1; float time_taken; fprintf(stderr, "Ray tracing ..."); gettimeofday(&t0, NULL); num_rays_shot = num_shadow_rays_shot = num_triangles_tested = num_bboxes_tested = 0; // Compute camera coordinate system from camera position // and look-at point up_vector = v3_create(0, 0, 1); forward_vector = v3_normalize(v3_subtract(scene_camera_lookat, scene_camera_position)); right_vector = v3_normalize(v3_crossprod(forward_vector, up_vector)); up_vector = v3_crossprod(right_vector, forward_vector); // Compute size of image plane from the chosen field-of-view // and image aspect ratio. This is the size of the plane at distance // of one unit from the camera position. image_plane_height = 2.0 * tan(0.5*VFOV/180*M_PI); image_plane_width = image_plane_height * (1.0 * framebuffer_width / framebuffer_height); float bottom, left, Us, Vs; left = -image_plane_width * 0.5; bottom = image_plane_height * 0.5; fprintf(stderr, "%d %d\r\n", framebuffer_height, framebuffer_width); // Loop over all pixels in the framebuffer for (j = 0; j < framebuffer_height; j++) { for (i = 0; i < framebuffer_width; i++) { if(!do_antialiasing){ /* With the formula "b + (t−b) * ((j+ 0.5) / ny)" the vector is calculated. * (t-b) equals the negative image_plane_height */ Us = bottom + (-image_plane_height*(j+0.5)/framebuffer_height); /* using the formula: "l + (r−l) * ((i+ 0.5) / nx)" to calculate the vector * (r-l) equals the image_plane_width. */ Vs = left + (image_plane_width*(i+0.5)/framebuffer_width); /* /* Calculate the vector through the pixel (for "Ray through pixel") * Using the formula "Us * U + Vs * v + n * w" */ vec3 UV = v3_add(v3_multiply(up_vector, Us), v3_multiply(right_vector, Vs)); vec3 ray = v3_add(forward_vector, UV); /* Fills the color */ color = ray_color(0, scene_camera_position, ray); } else { float Us1 = bottom + (-image_plane_height*(j+0.25)/framebuffer_height); float Us2 = bottom + (-image_plane_height*(j+0.75)/framebuffer_height); float Vs1 = left + (image_plane_width*(i+0.25)/framebuffer_width); float Vs2 = left + (image_plane_width*(i+0.75)/framebuffer_width); vec3 UV1 = v3_add(v3_multiply(up_vector, Us1), v3_multiply(right_vector, Vs1)); vec3 UV2 = v3_add(v3_multiply(up_vector, Us2), v3_multiply(right_vector, Vs1)); vec3 UV3 = v3_add(v3_multiply(up_vector, Us1), v3_multiply(right_vector, Vs2)); vec3 UV4 = v3_add(v3_multiply(up_vector, Us2), v3_multiply(right_vector, Vs2)); vec3 color1 = ray_color(0, scene_camera_position, v3_add(forward_vector, UV1)); vec3 color2 = ray_color(0, scene_camera_position, v3_add(forward_vector, UV2)); vec3 color3 = ray_color(0, scene_camera_position, v3_add(forward_vector, UV3)); vec3 color4 = ray_color(0, scene_camera_position, v3_add(forward_vector, UV4)); color = v3_multiply( v3_add(v3_add(color1, color2), v3_add(color3, color4)), 0.25 ); } /* Output pixel color */ put_pixel(i, j, color.x, color.y, color.z); } sprintf(buf, "Ray-tracing ::: %.0f%% done", 100.0*j/framebuffer_height); glutSetWindowTitle(buf); } // Done! gettimeofday(&t1, NULL); glutSetWindowTitle("Ray-tracing ::: done"); // Output some statistics time_taken = 1.0 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1000000.0; fprintf(stderr, " done in %.1f seconds\n", time_taken); fprintf(stderr, "... %lld total rays shot, of which %d camera rays and " "%lld shadow rays\n", num_rays_shot, do_antialiasing ? 4*framebuffer_width*framebuffer_height : framebuffer_width*framebuffer_height, num_shadow_rays_shot); fprintf(stderr, "... %lld triangles intersection tested " "(avg %.1f tri/ray)\n", num_triangles_tested, 1.0*num_triangles_tested/num_rays_shot); fprintf(stderr, "... %lld bboxes intersection tested (avg %.1f bbox/ray)\n", num_bboxes_tested, 1.0*num_bboxes_tested/num_rays_shot); }
static unsigned int ray_color(const point3 e, double t, const point3 d, idx_stack *stk, const rectangular_node rectangulars, const sphere_node spheres, const light_node lights, color object_color, int bounces_left) { rectangular_node hit_rec = NULL, light_hit_rec = NULL; sphere_node hit_sphere = NULL, light_hit_sphere = NULL; double diffuse, specular; point3 l, _l, r, rr; object_fill fill; color reflection_part; color refraction_part; /* might be a reflection ray, so check how many times we've bounced */ if (bounces_left == 0) { SET_COLOR(object_color, 0.0, 0.0, 0.0); return 0; } /* check for intersection with a sphere or a rectangular */ intersection ip= ray_hit_object(e, d, t, MAX_DISTANCE, rectangulars, &hit_rec, spheres, &hit_sphere); if (!hit_rec && !hit_sphere) return 0; /* pick the fill of the object that was hit */ fill = hit_rec ? hit_rec->element.rectangular_fill : hit_sphere->element.sphere_fill; void *hit_obj = hit_rec ? (void *) hit_rec : (void *) hit_sphere; /* assume it is a shadow */ SET_COLOR(object_color, 0.0, 0.0, 0.0); for (light_node light = lights; light; light = light->next) { /* calculate the intersection vector pointing at the light */ subtract_vector(ip.point, light->element.position, l); multiply_vector(l, -1, _l); normalize(_l); /* check for intersection with an object. use ignore_me * because we don't care about this normal */ ray_hit_object(ip.point, _l, MIN_DISTANCE, length(l), rectangulars, &light_hit_rec, spheres, &light_hit_sphere); /* the light was not block by itself(lit object) */ if (light_hit_rec || light_hit_sphere) continue; compute_specular_diffuse(&diffuse, &specular, d, l, ip.normal, fill.phong_power); localColor(object_color, light->element.light_color, diffuse, specular, &fill); } reflection(r, d, ip.normal); double idx = idx_stack_top(stk).idx, idx_pass = fill.index_of_refraction; if (idx_stack_top(stk).obj == hit_obj) { idx_stack_pop(stk); idx_pass = idx_stack_top(stk).idx; } else { idx_stack_element e = { .obj = hit_obj, .idx = fill.index_of_refraction }; idx_stack_push(stk, e); } refraction(rr, d, ip.normal, idx, idx_pass); double R = (fill.T > 0.1) ? fresnel(d, rr, ip.normal, idx, idx_pass) : 1.0; /* totalColor = localColor + mix((1-fill.Kd) * fill.R * reflection, T * refraction, R) */ if (fill.R > 0) { /* if we hit something, add the color */ int old_top = stk->top; if (ray_color(ip.point, MIN_DISTANCE, r, stk, rectangulars, spheres, lights, reflection_part, bounces_left - 1)) { multiply_vector(reflection_part, R * (1.0 - fill.Kd) * fill.R, reflection_part); add_vector(object_color, reflection_part, object_color); } stk->top = old_top; } /* calculate refraction ray */ if ((length(rr) > 0.0) && (fill.T > 0.0) && (fill.index_of_refraction > 0.0)) { normalize(rr); if (ray_color(ip.point, MIN_DISTANCE, rr, stk,rectangulars, spheres, lights, refraction_part, bounces_left - 1)) { multiply_vector(refraction_part, (1 - R) * fill.T, refraction_part); add_vector(object_color, refraction_part, object_color); } } protect_color_overflow(object_color); return 1; } static void *parallel (void* range1) { Thread_range *range = (Thread_range *)range1; point3 d; idx_stack stk; color object_color = { 0.0, 0.0, 0.0 }; for (int j = range->height1; j < range->height2; j++) { for (int i = 0; i < range->ptr->width; i++) { double r = 0, g = 0, b = 0; /* MSAA */ for (int s = 0; s < SAMPLES; s++) { idx_stack_init(&stk); rayConstruction(d, range->ptr->u, range->ptr->v, range->ptr->w, i * range->ptr->factor + s / range->ptr->factor, j * range->ptr->factor + s % range->ptr->factor, range->ptr->view, range->ptr->width * range->ptr->factor, range->ptr->height * range->ptr->factor); if (ray_color(range->ptr->view->vrp, 0.0, d, &(stk), range->ptr->rectangulars, range->ptr->spheres, range->ptr->lights, object_color, MAX_REFLECTION_BOUNCES)) { r += object_color[0]; g += object_color[1]; b += object_color[2]; } else { r += range->ptr->background_color[0]; g += range->ptr->background_color[1]; b += range->ptr->background_color[2]; } range->ptr->pixels[((i + (j * range->ptr->width)) * 3) + 0] = r * 255 / SAMPLES; range->ptr->pixels[((i + (j * range->ptr->width)) * 3) + 1] = g * 255 / SAMPLES; range->ptr->pixels[((i + (j * range->ptr->width)) * 3) + 2] = b * 255 / SAMPLES; } } } return NULL; }