/* @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); }
static void localColor(color local_color, const color light_color, double diffuse, double specular, const object_fill *fill) { color ambi = { 0.1, 0.1, 0.1 }; color diff, spec, lightCo, surface; /* Local Color = ambient * surface + * light * ( kd * surface * diffuse + ks * specular) */ COPY_COLOR(diff, fill->fill_color); multiply_vector(diff, fill->Kd, diff); multiply_vector(diff, diffuse, diff); COPY_COLOR(lightCo, light_color); multiply_vectors(diff, lightCo, diff); COPY_COLOR(spec, light_color); multiply_vector(spec, fill->Ks, spec); multiply_vector(spec, specular, spec); COPY_COLOR(surface, fill->fill_color); multiply_vectors(ambi,surface, ambi); add_vector(diff, ambi, diff); add_vector(diff, spec, diff); add_vector(local_color, diff, local_color); }
/* @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; }
/* @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); }
/* 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); } }
//function to scale aroud the world coordinate axes void scale(IFS_DATA* ifs_data,float scale_x,float scale_y,float scale_z) { int i,j; Matrix trans_matrix=return_scale_Matrix(scale_x,scale_y,scale_z); object_x*=scale_x; object_y*=scale_y; object_z*=scale_z; //print(trans_matrix); for (i=0; i<ifs_data->numVertices; ++i) { vector v; v.A[0]=ifs_data->vertices[i].x; v.A[1]=ifs_data->vertices[i].y; v.A[2]=ifs_data->vertices[i].z; v.A[3]=1.0; //v=create_scale_Matrix(&v,scale_x,scale_y,scale_z); v=multiply_vector(&trans_matrix,&v); ifs_data->vertices[i].x=v.A[0]; ifs_data->vertices[i].y=v.A[1]; ifs_data->vertices[i].z=v.A[2]; } }
value value::multiply(const value& that) const { if (that.is(m_type)) { switch (m_type) { case type::number: return multiply_number(*m_value_number, *that.m_value_number); case type::vector: return multiply_vector(*m_value_vector, *that.m_value_vector); default: break; } } throw error( error::type::type, U"Cannot multiply " + type_description(that.m_type) + U" with " + type_description(m_type) ); }
/* * Returns a pointer to the intersection between a cone and a ray. * * eye: Position from which the ray is thrown. * dir_vec: Direction towards which the ray is thrown. Must be normalized. * object_ptr: Pointer to the Object struct that represents the cone. * length: Output parameter for the number of intersections found. */ void* get_cone_intersection(Vector eye, Vector dir_vec, void* object_ptr, int *length) { Cone* cone_ptr = (Cone*) ((Object*)object_ptr)->figure; long double termQD, termQE; Vector varD, varE, anchor_to_anchor; anchor_to_anchor = subtract_vectors(eye, cone_ptr->anchor); termQD = do_dot_product(cone_ptr->direction, dir_vec); termQE = do_dot_product(cone_ptr->direction, anchor_to_anchor); varD = subtract_vectors(multiply_vector(termQD, cone_ptr->direction), dir_vec); varE = get_ray_position(cone_ptr->anchor, subtract_vectors(multiply_vector(termQE, cone_ptr->direction), eye), 1); long double a = pow(varD.x, 2) + pow(varD.y, 2) + pow(varD.z, 2) - pow(cone_ptr->radius, 2) * pow(termQD, 2); long double b = 2 * (do_dot_product(varE, varD) - pow(cone_ptr->radius, 2) * termQD * termQE); long double c = pow(varE.x, 2) + pow(varE.y, 2) + pow(varE.z, 2) - pow(cone_ptr->radius, 2) * pow(termQE, 2); return get_cyl_cone_intersection(a, b, c, eye, dir_vec, object_ptr, length); }
//function to rotate along the world coordinate system void rotate_along(IFS_DATA* ifs_data,int axes) { Matrix k; switch(axes) { case 1: k=return_rotate_x(theta); break; case 2: k=return_rotate_y(theta); break; case 3: k=return_rotate_z(theta); break; } vector temp; temp.A[0]=object_x; temp.A[1]=object_y; temp.A[2]=object_z; temp.A[3]=1.0; temp=multiply_vector(&k,&temp); object_x=temp.A[0]; object_y=temp.A[1]; object_z=temp.A[2]; int i,j; for (i=0; i<ifs_data->numVertices; ++i) { vector v; v.A[0]=ifs_data->vertices[i].x; v.A[1]=ifs_data->vertices[i].y; v.A[2]=ifs_data->vertices[i].z; v.A[3]=1.0; switch(axes) { case 1: v=rotate_x(&v,angle_x); break; case 2: v=rotate_y(&v,angle_y); break; case 3: v=rotate_z(&v,angle_z); break; } ifs_data->vertices[i].x=v.A[0]; ifs_data->vertices[i].y=v.A[1]; ifs_data->vertices[i].z=v.A[2]; } }
/* * Returns the normal vector of a cone on a given position. The vector is * already normalized. * * posn: Position at which the intersection occured * cone_ptr: Pointer to a cone figure. */ Vector get_cone_normal_vector(Vector posn, void* cone_ptr) { Cone cone = *((Cone*) cone_ptr); Vector border, normal_vec; border = subtract_vectors(posn, cone.anchor); long double distance = normalize_vector(&border); if(do_dot_product(border, cone.direction) < 0) distance *= -1; normal_vec = multiply_vector(1.0/ fabsl(distance), subtract_vectors(posn, get_ray_position(cone.anchor, cone.direction, distance * sqrt(2)))); normalize_vector(&normal_vec); return normal_vec; }
//function to rotate the camera around camera coordinate system Rotate_Camera_around_own_axis(float theta,int axes) { vector v; v.A[0]=c_x; v.A[1]=c_y; v.A[2]=c_z; v.A[3]=1.0; vector v1; v1.A[0]=u_x;//-e_x; v1.A[1]=u_y;//-e_y; v1.A[2]=u_z;//-e_z; v1.A[3]=1.0; Matrix m; switch(axes) { case 1: m=return_rotate_x(theta); break; case 2: m=return_rotate_y(theta); break; case 3: m=return_rotate_z(theta); break; } v=multiply_vector(&m,&v); // printf("vector v again is \n"); // print_vector(v); v1=multiply_vector(&m,&v1); // printf("vector v1 again is \n"); // print_vector(v1); look_ortho(data,e_x,e_y,e_z,v.A[0],v.A[1],v.A[2],v1.A[0],v1.A[1],v1.A[2]); }
// my implementation of arbitrary axis void rotate_arbit_axis(IFS_DATA *ifs_data,float x1,float y1,float z1,float x2,float y2,float z2,float theta) { Matrix trans_matrix; int A[4][4]={{1.0,0.0,0.0,0.0},{0.0,1.0,0.0,0.0},{0.0,0.0,1.0,0.0},{0.0,0.0,0.0,1.0}}; int i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) trans_matrix.A[i][j]=A[i][j]; Matrix T=return_translate(-x1,-y1,-z1); trans_matrix=T; float u=sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) +(z2-z1)*(z2-z1)); float x=(x2-x1)/u; float y=(y2-y1)/u; float z=(z2-z1)/u; //printf("%f %f %f \n\n\n",x,y,z); Matrix R; float B[4][4]={{x*x*(1-cos(theta))+cos(theta),x*(1-cos(theta))*y+z*sin(theta),z*x*(1-cos(theta))-y*sin(theta),0.0} ,{x*(1-cos(theta))*y-z*sin(theta),y*y*(1-cos(theta))+cos(theta),z*y*(1-cos(theta))+x*sin(theta),0.0} ,{z*(1-cos(theta))*x+y*sin(theta),z*(1-cos(theta))*y-x*sin(theta),z*z*(1-cos(theta))+cos(theta),0.0} ,{0.0,0.0,0.0,1.0}}; for(i=0;i<4;i++) for(j=0;j<4;j++) R.A[i][j]=B[i][j]; trans_matrix=multiply(R,trans_matrix); T=return_translate(x1,y1,z1); trans_matrix=multiply(T,trans_matrix); for (i=0; i<ifs_data->numVertices; ++i) { vector v; v.A[0]=ifs_data->vertices[i].x; v.A[1]=ifs_data->vertices[i].y; v.A[2]=ifs_data->vertices[i].z; v.A[3]=1.0; v=multiply_vector(&trans_matrix,&v); //for(=0;i<4;i++) ifs_data->vertices[i].x=v.A[0]; ifs_data->vertices[i].y=v.A[1]; ifs_data->vertices[i].z=v.A[2]; } }
void Reflection::reciprocalAxes(vec *aStar, vec *bStar, vec *cStar) { double volume = unitCellVolume(); vec avec, bvec, cvec; realSpaceAxes(&avec, &bvec, &cvec); double alpha, beta, gamma; anglesAsRadians(&alpha, &beta, &gamma); double sinAlpha = sin(alpha); double sinBeta = sin(beta); double sinGamma = sin(gamma); *aStar = cross_product_for_vectors(bvec, cvec); double scalar = sinAlpha / volume; multiply_vector(aStar, scalar); *bStar = cross_product_for_vectors(avec, cvec); scalar = sinBeta / volume; multiply_vector(bStar, scalar); *cStar = cross_product_for_vectors(avec, bvec); scalar = sinGamma / volume; multiply_vector(cStar, scalar); }
void draw_vector_balls(SDL_Renderer* r, SDL_Texture* t, struct vector3d ball[], int size, int width, int height) { SDL_Rect dest; dest.w = 20; dest.h = 20; int i; for (i = 0; i < size; i++) { struct vector3d z_translate = {0,0,2}; struct vector3d screen_translate = {width / 2 , height / 2, 0}; struct vector3d world = {ball[i].x, ball[i].y, ball[i].z}; add_vector(&world, &z_translate); multiply_vector(&world, 100); add_vector(&world, &screen_translate); float inv = 400 - world.z; float interp = inv / 342; dest.w = 30 * interp; dest.h = 30 * interp; /* if (i == 0) { dest.w = 30; dest.h = 30; printf("z = %.1f\n", world.z); } else { dest.w = 20; dest.h = 20; } */ dest.x = world.x; dest.y = world.y; SDL_RenderCopy(r, t, NULL, &dest); //draw screen pixel_buffer } }
/* @param t distance */ static intersection ray_hit_object(const point3 e, const point3 d, double t0, double t1, const rectangular_node rectangulars, rectangular_node *hit_rectangular, const sphere_node spheres, sphere_node *hit_sphere) { /* set these to not hit */ *hit_rectangular = NULL; *hit_sphere = NULL; point3 biased_e; multiply_vector(d, t0, biased_e); add_vector(biased_e, e, biased_e); double nearest = t1; intersection result, tmpresult; for (rectangular_node rec = rectangulars; rec; rec = rec->next) { if (rayRectangularIntersection(biased_e, d, &(rec->element), &tmpresult, &t1) && (t1 < nearest)) { /* hit is closest so far */ *hit_rectangular = rec; nearest = t1; result = tmpresult; } } /* check the spheres */ for (sphere_node sphere = spheres; sphere; sphere = sphere->next) { if (raySphereIntersection(biased_e, d, &(sphere->element), &tmpresult, &t1) && (t1 < nearest)) { *hit_sphere = sphere; *hit_rectangular = NULL; nearest = t1; result = tmpresult; } } return result; }
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); } }
//function to scale the object around its own center void scale_constant(IFS_DATA* ifs_data,float scale_x,float scale_y,float scale_z) { int i,j; Matrix trans_matrix; Matrix T=return_translate(-1*object_x,-1*object_y,-1*object_z); Matrix scale=return_scale_Matrix(scale_x,scale_y,scale_z); trans_matrix=multiply(scale,T); T=return_translate(object_x,object_y,object_z); trans_matrix=multiply(trans_matrix,T); //print(trans_matrix); for (i=0; i<ifs_data->numVertices; ++i) { vector v; v.A[0]=ifs_data->vertices[i].x; v.A[1]=ifs_data->vertices[i].y; v.A[2]=ifs_data->vertices[i].z; v.A[3]=1.0; //v=create_scale_Matrix(&v,scale_x,scale_y,scale_z); v=multiply_vector(&trans_matrix,&v); ifs_data->vertices[i].x=v.A[0]; ifs_data->vertices[i].y=v.A[1]; ifs_data->vertices[i].z=v.A[2]; } }
/* @param r direction of reflected ray * @param d direction of primary ray into intersection * @param n surface normal at intersection */ static void reflection(point3 r, const point3 d, const point3 n) { /* r = d - 2(d . n)n */ multiply_vector(n, -2.0 * dot_product(d, n), r); add_vector(r, d, r); }
void look_ortho(IFS_DATA *ifs_data,float eye1_x,float eye1_y,float eye1_z,float center1_x,float center1_y,float center1_z,float up1_x,float up1_y,float up1_z) { vector w, v, up,u; Matrix m; w.A[0] = -1*(center1_x - eye1_x); w.A[1] = -1*(center1_y - eye1_y); w.A[2] = -1*(center1_z - eye1_z); w.A[3]=1.0; // printf("printing w\n"); // print_vector(w); up.A[0] = up1_x; up.A[1] = up1_y; up.A[2] = up1_z; up.A[3]=1.0; // printf("printing up\n"); // print_vector(up); w=normalize(w); float dot=up.A[0]*w.A[0]+up.A[1]*w.A[1]+up.A[2]*w.A[2]; v.A[0]=up.A[0]-dot*w.A[0]; v.A[1]=up.A[1]-dot*w.A[1]; v.A[2]=up.A[2]-dot*w.A[2]; v.A[3]=1.0; v=normalize(v); /* Side = forward x up */ u=cross_product(v, w); //print_vector(side); // side=normalize(side); /* Recompute up as: up = side x forward */ // up=cross_product(side, f); //print_vector(up); m.A[0][0] = u.A[0]; m.A[1][0] = u.A[1]; m.A[2][0] = u.A[2]; m.A[3][0] = 0.0; m.A[0][1] = v.A[0]; m.A[1][1] = v.A[1]; m.A[2][1] = v.A[2]; m.A[3][1] = 0.0; m.A[0][2] = w.A[0]; m.A[1][2] = w.A[1]; m.A[2][2] = w.A[2]; m.A[3][2] = 0.0; m.A[0][3] = 0.0; m.A[1][3] = 0.0; m.A[2][3] = 0.0; m.A[3][3] = 1.0; Matrix T=return_translate(-eye1_x,-eye1_y,-eye1_z); // print(T); Matrix trans_matrix=multiply(m,T); vector o; o.A[0]=object_x; o.A[1]=object_y; o.A[2]=object_z; o.A[3]=1.0; o=multiply_vector(&trans_matrix,&o); object_x=o.A[0]; object_y=o.A[1]; object_z=o.A[2]; //print_vector(o); // print(trans_matrix); int i,j; for (i=0; i<ifs_data->numVertices; ++i) { vector v; v.A[0]=ifs_data->vertices[i].x; v.A[1]=ifs_data->vertices[i].y; v.A[2]=ifs_data->vertices[i].z; v.A[3]=1.0; v=multiply_vector(&trans_matrix,&v); //for(=0;i<4;i++) ifs_data->vertices[i].x=v.A[0]; ifs_data->vertices[i].y=v.A[1]; ifs_data->vertices[i].z=v.A[2]; } // glMultMatrixf(&m[0][0]); //glTranslated(-eyex, -eyey, -eyez); }
/* * Adds the effect of the given light over the given intersection. * * light: Light that is being applied. * inter: Intersection over which the light is being applied. * normal_vec: Normal vector of the intersection point. It is passed by as a * parameter for optimization purposes. * rev_dir_vec: Reverse vector of the direction of the ray that comes from the * eye. It is passed by as a parameter for optimization purposes. * all_lights_color: Accumulated amount of light sources effect. The effect of * the given light is added to this total. * all_lights_color: Accumulated amount of the specular light effect. The * specular effect of the given light is added to this total. * conf: Configuration of the scene. */ void apply_light_source(Light light, Intersection inter, Vector normal_vec, Vector rev_dir_vec, Color *all_lights_color, long double *all_spec_light, SceneConfig conf) { Vector light_vec; long double light_distance, illum_cos, att_factor, spec_cos; Color light_filter; Intersection* shadow_inter; int shadow_i, shadow_inter_length; Object shadow_obj; // Find the vector that points from the intersection point to the light // source, and normalize it light_vec = subtract_vectors(light.anchor, inter.posn); light_distance = normalize_vector(&light_vec); // We check for any object making a shadow from that light light_filter = (Color){ .red = 1.0, .green = 1.0, .blue = 1.0 };; shadow_inter = get_intersections(inter.posn, light_vec, &shadow_inter_length, conf); // If the intersection is beyond the light source, we ignore it if(shadow_inter) { // Object(s) is/are actually behind the light for(shadow_i = 0; shadow_i < shadow_inter_length && !is_color_empty(light_filter); shadow_i++) { if(shadow_inter[shadow_i].distance < light_distance) { shadow_obj = shadow_inter[shadow_i].obj; if(shadow_obj.translucency_material) { light_filter = multiply_color(shadow_obj.translucency_material, multiply_colors(light_filter, shadow_obj.color)); } else { light_filter = get_empty_color(); } } } if(!is_color_empty(light_filter)) { free(shadow_inter); shadow_inter = NULL; } } // If there aren't any shadows if(!shadow_inter) { illum_cos = do_dot_product(normal_vec, light_vec); // We only take it into account if the angle is lower than 90 degrees if(illum_cos > 0) { Vector light_mirror_vec = subtract_vectors(multiply_vector(2 * illum_cos, normal_vec), light_vec); // Attenuation factor, reduces the light energy depending on the distance att_factor = get_attenuation_factor(light, light_distance); spec_cos = do_dot_product(rev_dir_vec, light_mirror_vec); // We add the light source effect light_filter = multiply_color(illum_cos * inter.obj.light_material * att_factor, light_filter); *all_lights_color = add_colors(*all_lights_color, multiply_colors(light_filter, light.color)); // The specular light, is the white stain on the objects if(spec_cos > 0) { *all_spec_light += pow(spec_cos * inter.obj.specular_material * att_factor, inter.obj.specular_pow); } } } else free(shadow_inter); } /* * Gets the color of the intersection by calculating light intensity, * (which includes specular light, shadows, transparency, etc) * * light: Light for which the attenuation factor is calculated. * distance: Distance between the light and an illuminated spot. * mirror_level: Current level of reflection. * conf: Configuration of the scene. */ Color get_intersection_color(Vector eye, Vector dir_vec, Intersection *inter_list, int inter_length, int mirror_level, int transparency_level, SceneConfig conf) { Intersection inter; int light_index; long double spec_light_factor, mirror_factor, transparency_factor; Vector normal_vec, rev_dir_vec, reflection_vec; Light light; Color all_lights_color, color_found, reflection_color, transparency_color, final_color; inter = inter_list[transparency_level]; // Light intensity all_lights_color = (Color){ .red = 0.0, .green = 0.0, .blue = 0.0 }; // Specular light intensity spec_light_factor = 0.0; normal_vec = get_normal_vector(&inter); // Pick up the normal vector that is pointing to the eye if(do_dot_product(normal_vec, dir_vec) > 0) normal_vec = multiply_vector(-1, normal_vec); // Initialize reverse direction vector for mirrors and specular light rev_dir_vec = multiply_vector(-1, dir_vec); for(light_index = 0; light_index < conf.lights_length; light_index++) { light = conf.lights[light_index]; apply_light_source(light, inter, normal_vec, rev_dir_vec, &all_lights_color, &spec_light_factor, conf); } // We add the environmental light of the scene all_lights_color = add_colors(all_lights_color, multiply_color(inter.obj.light_ambiental, conf.environment_light)); if(spec_light_factor > 1.0) spec_light_factor = 1.0; color_found = multiply_colors(all_lights_color, inter.obj.color); // Specular light gives a color between enlightened color and the light color. color_found.red += (1 - color_found.red) * spec_light_factor; color_found.green += (1 - color_found.green) * spec_light_factor; color_found.blue += (1 - color_found.blue) * spec_light_factor; // Get transparency color transparency_factor = inter.obj.transparency_material; if (transparency_level < conf.max_transparency_level && transparency_factor > 0.0) { if(transparency_level + 1 < inter_length) { transparency_color = get_intersection_color(eye,dir_vec,inter_list,inter_length,0,transparency_level+1, conf); } else { transparency_color = conf.background; } } else { transparency_factor = 0.0; transparency_color = get_empty_color(); } // Get reflection color mirror_factor = inter.obj.mirror_material; if (mirror_level < conf.max_mirror_level && mirror_factor > 0.0) { reflection_vec = subtract_vectors(multiply_vector(2 * do_dot_product(normal_vec, rev_dir_vec), normal_vec), rev_dir_vec); reflection_color = get_color(inter.posn, reflection_vec, mirror_level + 1, conf); } else { mirror_factor = 0; reflection_color = get_empty_color(); } // Calculate final color transparency_color = multiply_color(transparency_factor, transparency_color); reflection_color = multiply_color((1.0-transparency_factor) * mirror_factor, reflection_color); color_found = multiply_color((1.0-transparency_factor) * (1.0-mirror_factor), color_found); final_color = add_colors(transparency_color, add_colors(reflection_color, color_found)); return final_color; } /* * Returns the color that is seen from the position 'eye' when looking at the * tridimensional scene towards the direction 'dir_vec'. * * eye: Position from which the scene is seen. * dir_vec: Direction at which the eye is looking. This vector must be normalized. * mirror_level: Current level of reflection. * conf: Configuration of the scene. */ Color get_color(Vector eye, Vector dir_vec, int mirror_level, SceneConfig conf) { Intersection *inter_list; Color color; // Get intersections on the given direction. Intersections are ordered from the nearest to the farthest. int inter_list_length; inter_list = get_intersections(eye, dir_vec, &inter_list_length, conf); // If we don't find an intersection we return the background, otherwise we check for the intersections's color. if (!inter_list) return conf.background; color = get_intersection_color(eye, dir_vec, inter_list, inter_list_length, mirror_level, 0, conf); free(inter_list); return 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; } } } }
int main (int argc, char* args[]) { //SDL Window setup if (init(SCREEN_WIDTH, SCREEN_HEIGHT) == 1) { return 0; } int i = 0; int j = 0; int offset = 0; struct vector2d translation = {-SCREEN_WIDTH / 2, -SCREEN_HEIGHT / 2}; //set up icons used to represent player lives for (i = 0; i < LIVES; i++) { init_player(&lives[i]); lives[i].lives = 1; //shrink lives for (j = 0; j < P_VERTS; j++) { divide_vector(&lives[i].obj_vert[j], 2); } //convert screen space vector into world space struct vector2d top_left = {20 + offset, 20}; add_vector(&top_left, &translation); lives[i].location = top_left; update_player(&lives[i]); offset += 20; } //set up player and asteroids in world space init_player(&p); init_asteroids(asteroids, ASTEROIDS); int sleep = 0; int quit = 0; SDL_Event event; Uint32 next_game_tick = SDL_GetTicks(); //render loop while(quit == 0) { //check for new events every frame SDL_PumpEvents(); const Uint8 *state = SDL_GetKeyboardState(NULL); if (state[SDL_SCANCODE_ESCAPE]) { quit = 1; } if (state[SDL_SCANCODE_UP]) { struct vector2d thrust = get_direction(&p); multiply_vector(&thrust, .06); apply_force(&p.velocity, thrust); } if (state[SDL_SCANCODE_LEFT]) { rotate_player(&p, -4); } if (state[SDL_SCANCODE_RIGHT]) { rotate_player(&p, 4); } while (SDL_PollEvent(&event)) { switch(event.type) { case SDL_KEYDOWN: switch( event.key.keysym.sym ) { case SDLK_SPACE: if (p.lives > 0) { shoot_bullet(&p); } break; } } } //draw to the pixel buffer clear_pixels(pixels, 0x00000000); draw_player(pixels, &p); draw_player(pixels, &lives[0]); draw_player(pixels, &lives[1]); draw_player(pixels, &lives[2]); draw_asteroids(pixels, asteroids, ASTEROIDS); update_player(&p); bounds_player(&p); bounds_asteroids(asteroids, ASTEROIDS); int res = collision_asteroids(asteroids, ASTEROIDS, &p.location, p.hit_radius); if (res != -1) { p.lives--; p.location.x = 0; p.location.y = 0; p.velocity.x = 0; p.velocity.y = 0; int i = LIVES - 1; for ( i = LIVES; i >= 0; i--) { if(lives[i].lives > 0) { lives[i].lives = 0; break; } } } int i = 0; struct vector2d translation = {-SCREEN_WIDTH / 2, -SCREEN_HEIGHT / 2}; for (i = 0; i < BULLETS; i++) { //only check for collision for bullets that are shown on screen if (p.bullets[i].alive == TRUE) { //convert bullet screen space location to world space to compare //with asteroids world space to detect a collision struct vector2d world = add_vector_new(&p.bullets[i].location, &translation); int index = collision_asteroids(asteroids, ASTEROIDS, &world, 1); //collision occured if (index != -1) { asteroids[index].alive = 0; p.bullets[i].alive = FALSE; if (asteroids[index].size != SMALL) { spawn_asteroids(asteroids, ASTEROIDS, asteroids[index].size, asteroids[index].location); } } } } update_asteroids(asteroids, ASTEROIDS); //draw buffer to the texture representing the screen SDL_UpdateTexture(screen, NULL, pixels, SCREEN_WIDTH * sizeof (Uint32)); //draw to the screen SDL_RenderClear(renderer); SDL_RenderCopy(renderer, screen, NULL, NULL); SDL_RenderPresent(renderer); //time it takes to render 1 frame in milliseconds next_game_tick += 1000 / 60; sleep = next_game_tick - SDL_GetTicks(); if( sleep >= 0 ) { SDL_Delay(sleep); } } //free the screen buffer free(pixels); //Destroy window SDL_DestroyWindow(window); //Quit SDL subsystems SDL_Quit(); return 0; }
/* @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; } 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; }