/* @param t t distance * @return 1 means hit, otherwise 0 */ static int raySphereIntersection(const point3 ray_e, const point3 ray_d, const sphere *sph, intersection *ip, double *t1) { point3 l; subtract_vector(sph->center, ray_e, l); double s = dot_product(l, ray_d); double l2 = dot_product(l, l); double r2 = sph->radius * sph->radius; if (s < 0 && l2 > r2) return 0; float m2 = l2 - s * s; if (m2 > r2) return 0; float q = sqrt(r2 - m2); *t1 = (l2 > r2) ? (s - q) : (s + q); /* p = e + t1 * d */ multiply_vector(ray_d, *t1, ip->point); add_vector(ray_e, ip->point, ip->point); subtract_vector(ip->point, sph->center, ip->normal); normalize(ip->normal); if (dot_product(ip->normal, ray_d) > 0.0) multiply_vector(ip->normal, -1, ip->normal); return 1; }
void spacing_simulator_step(spacing_simulator *ss) { linked_list* vertices = ss->vg->vertices; linked_list* edges = ss->vg->edges; for(node* i = vertices->first; i != NULL;i = i->next){ visual_vertex* v1 = (visual_vertex*)i->element; v1->sim_data.speed = subtract_vector(make_vector_2d(400, 300), v1->position); v1->sim_data.speed = multiply_vector(normalize(v1->sim_data.speed), ss->origin_point_force); //debug_vector2d(v1->position, "POSITION"); //debug_vector2d(v1->sim_data.speed, "SPEED"); //debug("VVVVVVVVVV\n"); } for(node* i = vertices->first; i != NULL;i = i->next){ visual_vertex* v1 = (visual_vertex*)i->element; for(node* j = i->next;j != NULL;j = j->next){ visual_vertex* v2 = (visual_vertex*)j->element; vector_2d speed1 = subtract_vector(v1->position, v2->position); vector_2d speed2 = subtract_vector(v2->position, v1->position); float distance = calculate_distance(v1->position, v2->position); float force_factor = 100-distance; force_factor = (force_factor > 0 ? force_factor : 0)*2; speed1 = normalize(speed1); speed2 = normalize(speed2); speed1 = multiply_vector(speed1, force_factor); speed2 = multiply_vector(speed2, force_factor); v1->sim_data.speed = add_vector(v1->sim_data.speed, speed1); v2->sim_data.speed = add_vector(v2->sim_data.speed, speed2); //debug_vector2d(speed1, "SPEED1"); //debug_vector2d(speed2, "SPEED2"); } } for(node* i = edges->first;i != NULL;i = i->next){ visual_edge* e = (visual_edge*)i->element; vector_2d pos1 = e->v1->position; vector_2d pos2 = e->v2->position; float distance = calculate_distance(pos1, pos2); vector_2d direction1 = normalize(subtract_vector(pos2, pos1)); vector_2d direction2 = normalize(subtract_vector(pos1, pos2)); vector_2d speed1 = multiply_vector(direction1, distance*distance/500); vector_2d speed2 = multiply_vector(direction2, distance*distance/500); e->v1->sim_data.speed = add_vector(e->v1->sim_data.speed, speed1); e->v2->sim_data.speed = add_vector(e->v2->sim_data.speed, speed2); } for(node* i = vertices->first; i != NULL;i = i->next){ visual_vertex* v1 = (visual_vertex*)i->element; v1->sim_data.speed = multiply_vector(v1->sim_data.speed, ss->friction_factor); v1->position = add_vector(v1->position, v1->sim_data.speed); } }
/* @param d direction of ray * @param w basic vectors */ static void rayConstruction(point3 d, const point3 u, const point3 v, const point3 w, unsigned int i, unsigned int j, const viewpoint *view, unsigned int width, unsigned int height) { double xmin = -0.0175; double ymin = -0.0175; double xmax = 0.0175; double ymax = 0.0175; double focal = 0.05; point3 u_tmp, v_tmp, w_tmp, s; double w_s = focal; double u_s = xmin + ((xmax - xmin) * (float) i / (width - 1)); double v_s = ymax + ((ymin - ymax) * (float) j / (height - 1)); /* s = e + u_s * u + v_s * v + w_s * w */ multiply_vector(u, u_s, u_tmp); multiply_vector(v, v_s, v_tmp); multiply_vector(w, w_s, w_tmp); add_vector(view->vrp, u_tmp, s); add_vector(s, v_tmp, s); add_vector(s, w_tmp, s); /* p(t) = e + td = e + t(s - e) */ subtract_vector(s, view->vrp, d); normalize(d); }
/* @param d direction of the ray into intersection * @param l direction of intersection to light * @param n surface normal */ static void compute_specular_diffuse(double *diffuse, double *specular, const point3 d, const point3 l, const point3 n, double phong_pow) { point3 d_copy, l_copy, middle, r; /* Calculate vector to eye V */ COPY_POINT3(d_copy, d); multiply_vector(d_copy, -1, d_copy); normalize(d_copy); /* Calculate vector to light L */ COPY_POINT3(l_copy, l); multiply_vector(l_copy, -1, l_copy); normalize(l_copy); /* Calculate reflection direction R */ double tmp = dot_product(n, l_copy); multiply_vector(n, tmp, middle); multiply_vector(middle, 2, middle); subtract_vector(middle, l_copy, r); normalize(r); /* diffuse = max(0, dot_product(n, -l)) */ *diffuse = MAX(0, dot_product(n, l_copy)); /* specular = (dot_product(r, -d))^p */ *specular = pow(MAX(0, dot_product(r, d_copy)), phong_pow); }
/* reference: https://www.opengl.org/sdk/docs/man/html/refract.xhtml */ static void refraction(point3 t, const point3 I, const point3 N, double n1, double n2) { double eta = n1 / n2; double dot_NI = dot_product(N,I); double k = 1.0 - eta * eta * (1.0 - dot_NI * dot_NI); if (k < 0.0 || n2 <= 0.0) t[0] = t[1] = t[2] = 0.0; else { point3 tmp; multiply_vector(I, eta, t); multiply_vector(N, eta * dot_NI + sqrt(k), tmp); subtract_vector(t, tmp, t); } }
/* @return 1 means hit, otherwise 0; */ static int rayRectangularIntersection(const point3 ray_e, const point3 ray_d, rectangular *rec, intersection *ip, double *t1) { point3 e01, e03, p; subtract_vector(rec->vertices[1], rec->vertices[0], e01); subtract_vector(rec->vertices[3], rec->vertices[0], e03); cross_product(ray_d, e03, p); double det = dot_product(e01, p); /* Reject rays orthagonal to the normal vector. * I.e. rays parallell to the plane. */ if (det < 1e-4) return 0; double inv_det = 1.0 / det; point3 s; subtract_vector(ray_e, rec->vertices[0], s); double alpha = inv_det * dot_product(s, p); if ((alpha > 1.0) || (alpha < 0.0)) return 0; point3 q; cross_product(s, e01, q); double beta = inv_det * dot_product(ray_d, q); if ((beta > 1.0) || (beta < 0.0)) return 0; *t1 = inv_det * dot_product(e03, q); if (alpha + beta > 1.0f) { /* for the second triangle */ point3 e23, e21; subtract_vector(rec->vertices[3], rec->vertices[2], e23); subtract_vector(rec->vertices[1], rec->vertices[2], e21); cross_product(ray_d, e21, p); det = dot_product(e23, p); if (det < 1e-4) return 0; inv_det = 1.0 / det; subtract_vector(ray_e, rec->vertices[2], s); alpha = inv_det * dot_product(s, p); if (alpha < 0.0) return 0; cross_product(s, e23, q); beta = inv_det * dot_product(ray_d, q); if ((beta < 0.0) || (beta + alpha > 1.0)) return 0; *t1 = inv_det * dot_product(e21, q); } if (*t1 < 1e-4) return 0; COPY_POINT3(ip->normal, rec->normal); if (dot_product(ip->normal, ray_d)>0.0) multiply_vector(ip->normal, -1, ip->normal); multiply_vector(ray_d, *t1, ip->point); add_vector(ray_e, ip->point, ip->point); return 1; }
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; } } } }
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; }