def test_determine_diffuse_contribution(self): sphere = data.Sphere(data.Point(0, 0, 0), 1, data.Color(0.5, 0.7, 0.8), data.Finish(0.5, 0.5, 0.5, 0.05)) light = data.Light(data.Point(0, 0, 100), data.Color(1.5, 1.2, 1.3)) inter_point = data.Point(0, 0, 1) inter_list = [ ( data.Sphere(data.Point(0, 0, 102), 1, data.Color(0.5, 0.7, 0.8), data.Finish(0.5, 0.5, 0.5, 0.05)), data.Point(0, 0, 101), ) ] normal = collisions.sphere_normal_at_point(sphere, inter_point) off_pt = cast.find_pt_off_sphere(inter_point, normal) dir_vect = vector_math.normalize_vector(vector_math.vector_from_to(off_pt, light.pt)) ray = data.Ray(off_pt, dir_vect) sphere_list = [] l_dir = vector_math.normalize_vector(vector_math.vector_from_to(off_pt, light.pt)) l_dot_n = vector_math.dot_vector(normal, l_dir) result = cast.determine_diffuse_contribution(sphere, off_pt, light, normal, sphere_list, l_dir, l_dot_n) self.assertEqual( result[0], cast.get_diffuse_contribution(sphere, light, ray, inter_list, normal, dir_vect, off_pt)[0] ) self.assertEqual( result[1], cast.get_diffuse_contribution(sphere, light, ray, inter_list, normal, dir_vect, off_pt)[1] ) self.assertEqual( result[2], cast.get_diffuse_contribution(sphere, light, ray, inter_list, normal, dir_vect, off_pt)[2] )
def test_vectorToFrom_1(self): p1 = data.Point(1,2,3) p2 = data.Point(0,0,0) v1 = vector_math.vector_from_to(p1, p2) v2 = vector_math.vector_from_to(p2, p1) equals1 = data.Vector(-1, -2, -3) equals2 = vector_math.scale_vector(v1, -1) self.assertEqual(v1 == equals1, True) self.assertEqual(v2 == equals2, True) pass
def cast_ray(ray, sphere_list, color, light): """Find the rendered color at the nearest intersection point along ray""" nearest = closest_intersect(ray, sphere_list) if not nearest: # No intersection, return white return Color(1.0, 1.0, 1.0) point, sphere = nearest # Compute initial ambient colors r = sphere.color.r * sphere.finish.ambient * color.r g = sphere.color.g * sphere.finish.ambient * color.g b = sphere.color.b * sphere.finish.ambient * color.b # Calculate diffuse value normal = sphere_normal_at_point(sphere, point) to_light = normalize_vector(vector_from_to(point, light.pt)) l_dot = dot_vector(normal, to_light) diffuse = sphere.finish.diffuse * l_dot if diffuse < 0: diffuse = 0 else: # Check for shadows new_point = translate_point(point, scale_vector(normal, 0.01)) light_ray = Ray(new_point, to_light) shadow_intersect = closest_intersect(light_ray, sphere_list) if (shadow_intersect and length_vector_sq(vector_from_to(new_point, shadow_intersect[0])) < length_vector_sq(vector_from_to(new_point, light.pt))): diffuse = 0 # Add diffuse to existing colors r += sphere.color.r * diffuse * light.color.r g += sphere.color.g * diffuse * light.color.g b += sphere.color.b * diffuse * light.color.b # Compute specular intensity if diffuse > 0: reflection = difference_vector(to_light, scale_vector(normal, 2 * l_dot)) intensity = dot_vector(reflection, normalize_vector(ray.dir)) power = 1. / sphere.finish.roughness if intensity > 0: r += light.color.r * sphere.finish.specular * intensity ** power g += light.color.g * sphere.finish.specular * intensity ** power b += light.color.b * sphere.finish.specular * intensity ** power # Max out colors at 1.0 if r > 1: r = 1 if g > 1: g = 1 if b > 1: b = 1 return Color(r, g, b)
def find_closest(inter,ray): close = vector_math.length_vector(vector_math.vector_from_to(ray.pt,inter[0][1])) sphere = inter[0][0] point = inter[0][1] for (s,p) in inter: distance = vector_math.length_vector(vector_math.vector_from_to(ray.pt,p)) if close > distance: close = distance sphere = s point = p return sphere, point
def cast_ray(ray, sphere_list, amb, light, eye_point): result_color = data.Color(1.0, 1.0, 1.0) # test for closest sphere to the eye collision_tuple = find_closest_collision(ray, sphere_list) if collision_tuple: # some useful variables sphere_hit = collision_tuple[0] sphere_hit_point = collision_tuple[1] # basic color before manipulation result_r = sphere_hit.color.r * sphere_hit.finish.amb * amb.r result_g = sphere_hit.color.g * sphere_hit.finish.amb * amb.g result_b = sphere_hit.color.b * sphere_hit.finish.amb * amb.b # computing light intensity sphere_vector = vector_math.vector_from_to(sphere_hit.center, sphere_hit_point) sphere_normal = vector_math.normalize_vector(sphere_vector) scaled_normal = vector_math.scale_vector(sphere_normal, 0.01) hit_point = vector_math.translate_point(sphere_hit_point, scaled_normal) light_vector = vector_math.vector_from_to(hit_point, light.pt) light_normal = vector_math.normalize_vector(light_vector) light_scale = vector_math.dot_vector(sphere_normal, light_normal) if light_scale > 0: sphere_normal_ray = data.Ray(hit_point, light_normal) possible_obstruction = find_closest_collision(sphere_normal_ray, sphere_list) if possible_obstruction == None or distance(hit_point, possible_obstruction[1]) > distance( hit_point, light.pt ): result_r += sphere_hit.color.r * light_scale * light.color.r * sphere_hit.finish.diff result_g += sphere_hit.color.g * light_scale * light.color.g * sphere_hit.finish.diff result_b += sphere_hit.color.b * light_scale * light.color.b * sphere_hit.finish.diff # computing specular intensity tmp_vector = vector_math.scale_vector(sphere_normal, 2 * light_scale) reflection_vector = vector_math.difference_vector(light_normal, tmp_vector) eye_vector = vector_math.vector_from_to(eye_point, hit_point) eye_normal = vector_math.normalize_vector(eye_vector) spec_scale = vector_math.dot_vector(reflection_vector, eye_normal) if spec_scale > 0: result_r += light.color.r * sphere_hit.finish.spec * spec_scale ** (1 / float(sphere_hit.finish.rough)) result_g += light.color.g * sphere_hit.finish.spec * spec_scale ** (1 / float(sphere_hit.finish.rough)) result_b += light.color.b * sphere_hit.finish.spec * spec_scale ** (1 / float(sphere_hit.finish.rough)) result_color = data.Color(result_r, result_g, result_b) return result_color
def closest_intersect(ray, sphere_list): """Find the nearest intersection point and sphere""" intersections = find_intersection_points(ray, sphere_list) if len(intersections) < 1: # We don't intersect anything return None # Find the nearest intersection point and its sphere nearest = intersections[0] nearest_dist_sq = length_vector_sq(vector_from_to(ray.pt, nearest[0])) for tup in intersections[1:]: dist_sq = length_vector_sq(vector_from_to(ray.pt, tup[0])) if dist_sq < nearest_dist_sq: nearest = tup nearest_dist_sq = dist_sq return nearest
def test_cast_ray_1(self): ray = data.Ray(data.Point(0, 10, 6), data.Vector(0, 0, -2)) sphere_list = [ data.Sphere(data.Point(0, 10, -2), 3, data.Color(0, 0.5, 1.0), data.Finish(0.5, 0.4, 0.5, 0.05)), data.Sphere(data.Point(0, 10, -20), 0.5, data.Color(0, 0.3, 0.2), data.Finish(0.5, 0.4, 0.5, 0.05)), ] ambient_color = data.Color(0.25, 0.5, 0.75) light = data.Light(data.Point(-100.0, 100.0, -100.0), data.Color(1.5, 1.5, 1.5)) eye_position = data.Point(0, 0, -14) cr = cast.cast_ray(ray, sphere_list, ambient_color, light, eye_position) inter_point = collisions.sphere_intersection_point(ray, sphere_list[0]) normal = collisions.sphere_normal_at_point(sphere_list[0], inter_point) off_pt = cast.find_pt_off_sphere(inter_point, normal) l_dir = vector_math.normalize_vector(vector_math.vector_from_to(off_pt, light.pt)) l_dot_n = vector_math.dot_vector(normal, l_dir) diffuse_list = cast.determine_diffuse_contribution( sphere_list[0], off_pt, light, normal, sphere_list, l_dir, l_dot_n ) spec_list = cast.determine_specular_contribution( l_dir, l_dot_n, normal, eye_position, off_pt, light.color, sphere_list[0].finish ) self.assertEqual( cr, data.Color( 0 + diffuse_list[0] + spec_list[0], 0.125 + diffuse_list[1] + spec_list[1], 0.375 + diffuse_list[2] + spec_list[2], ), )
def determine_specular_contribution(l_dir,l_dot_n,normal,eye_position, off_pt,light,sphere_finish,ray, inter_list): reflection_vect = vector_math.difference_vector(l_dir, vector_math.scale_vector(normal, 2 * l_dot_n)) v_dir = vector_math.normalize_vector( vector_math.vector_from_to(eye_position,off_pt)) spec_intensity = vector_math.dot_vector(reflection_vect,v_dir) def compute_spec(color_comp): return (color_comp * sphere_finish.specular * (spec_intensity ** (1 / sphere_finish.roughness))) if spec_intensity > 0: r_comp = compute_spec(light.color.r) g_comp = compute_spec(light.color.g) b_comp = compute_spec(light.color.b) if inter_list == []: return [r_comp,g_comp,b_comp] else: dist_pt_to_light = distance(off_pt,light.pt) nearest_point = find_nearest(inter_list,ray) if distance(off_pt,nearest_point) < dist_pt_to_light: return [0,0,0] else: return [r_comp,g_comp,b_comp] else: return [0,0,0]
def cast_all_rays(min_x, max_x, min_y, max_y, width, height, eye_point, sphere_list, ambient_color, light): f = open("image.ppm", 'w') f.write("P3\n") f.write("%d %d\n" % (width, height)) f.write("255\n") w = max_x - min_x h = max_y - min_y scale_x = w / width scale_y = h / height total = width * height percent = 0 for i in range(height): print int(percent) for j in range(width): position = width * i + j percent = float(position) / total * 100 x = j * scale_x + min_x y = max_y - i * scale_y dir = vector_math.vector_from_to(eye_point, data.Point(x,y,0)) ray = data.Ray(eye_point, dir) b = cast_ray(ray, sphere_list, ambient_color, light, eye_point) print_color(f,b)
def test_vectorToFrom_2(self): p1 = data.Point(4,4,4) p2 = data.Point(1,2,3) v1 = vector_math.vector_from_to(p1, p2) equals = data.Vector(-3, -2, -1) self.assertEqual(v1 == equals, True) pass
def test_get_diffuse_contribution(self): sphere = data.Sphere(data.Point(0, 0, 0), 1, data.Color(0.5, 0.7, 0.8), data.Finish(0.5, 0.5, 0.5, 0.05)) light = data.Light(data.Point(0, 0, 100), data.Color(1.5, 1.2, 1.3)) inter_point = data.Point(0, 0, 1) normal = collisions.sphere_normal_at_point(sphere, inter_point) inter_list = [] off_pt = cast.find_pt_off_sphere(inter_point, normal) dir_vect = vector_math.normalize_vector(vector_math.vector_from_to(off_pt, light.pt)) ray = data.Ray(off_pt, dir_vect) result = cast.get_diffuse_contribution(sphere, light, ray, inter_list, normal, dir_vect, off_pt) self.assertEqual(result[0], (vector_math.dot_vector(normal, dir_vect) * 1.5 * 0.5 * 0.5)) self.assertEqual(result[1], (vector_math.dot_vector(normal, dir_vect) * 1.2 * 0.7 * 0.5)) self.assertEqual(result[2], (vector_math.dot_vector(normal, dir_vect) * 1.3 * 0.8 * 0.5))
def get_diffuse_color(tu, light, s_list): pE = get_pe(tu) N = collisions.sphere_normal_at_point(tu[0], tu[1]) lDir = vector_math.vector_from_to(pE, light.pt) lDir = vector_math.normalize_vector(lDir) lDirection = vector_math.dot_vector(N, lDir) sI = get_specular_intensity(lDir, lDirection, N, pE, light, tu[0]) ray = data.Ray(pE, lDir) if lDirection <= 0 or collides_with_spheres(ray, s_list, pE, light): return data.Color(0,0,0) dif = get_diffuse(lDirection, light, tu[0], tu[0].finish.diffuse) finalColor = data.Color(sI.r + dif.r, sI.g + dif.g, sI.b + dif.b) return finalColor
def comp(sphere_list,inter,light,sphere,int,eye_point): n = collisions.sphere_normal_at_point(sphere,int) scaled_normal = vector_math.scale_vector(n,.01) Pe = vector_math.translate_point(inter[0][1],scaled_normal) vr_light = vector_math.vector_from_to(Pe,light.pt) L_dir = vector_math.normalize_vector(vr_light) dot_product = vector_math.dot_vector(n,L_dir) reflection_vr = vector_math.difference_vector(L_dir,vector_math.scale_vector(n,(2 * dot_product))) V_dir = vector_math.normalize_vector(vector_math.vector_from_to(eye_point,Pe)) intensity = vector_math.dot_vector(reflection_vr,V_dir) ray = data.Ray(Pe,L_dir) inter2 = collisions.find_intersection_points(sphere_list,ray) if dot_product>0 and inter2 == []: diff_r = sphere.color.r*sphere.finish.diffuse*dot_product*light.color.r diff_g = sphere.color.g*sphere.finish.diffuse*dot_product*light.color.g diff_b = sphere.color.b*sphere.finish.diffuse*dot_product*light.color.b spec_r = light.color.r*sphere.finish.specular*math.pow(intensity,(1/sphere.finish.roughness)) spec_g = light.color.g*sphere.finish.specular*math.pow(intensity,(1/sphere.finish.roughness)) spec_b = light.color.b*sphere.finish.specular*math.pow(intensity,(1/sphere.finish.roughness)) return data.Color(diff_r,diff_g,diff_b),data.Color(spec_r,spec_g,spec_b) else : return data.Color(0,0,0), data.Color(0,0,0)
def get_specular_intensity(lDir, lDirection, N, pE, light, sphere): reflection_vector = vector_math.difference_vector(lDir, vector_math.scale_vector(N, lDirection * 2)) vDir = vector_math.vector_from_to(data.Point(0.0,0.0,-14.0), pE) vDir = vector_math.normalize_vector(vDir) intensity = vector_math.dot_vector(reflection_vector, vDir) if intensity > 0: r = light.color.r * sphere.finish.specular * intensity**(1 / sphere.finish.roughness) g = light.color.g * sphere.finish.specular * intensity**(1 / sphere.finish.roughness) b = light.color.b * sphere.finish.specular * intensity**(1 / sphere.finish.roughness) color = data.Color(r,g,b) else: color = data.Color(0,0,0) return color
def cast_all_rays(view, eye_point, sphere_list, amb, light, file): j = view.max_y while j > view.min_y: i = view.min_x while i < view.max_x: screen_point = data.Point(i, j, 0) dir_to_pixel = vector_math.vector_from_to(eye_point, screen_point) ray = data.Ray(eye_point, dir_to_pixel) color = cast_ray(ray, sphere_list, amb, light, eye_point) printed_r = str(color_convert(color.r)) printed_g = str(color_convert(color.g)) printed_b = str(color_convert(color.b)) file.write("{0} {1} {2}\n".format(printed_r, printed_g, printed_b)) i += find_delta(view.min_x, view.max_x, view.width) j -= find_delta(view.min_y, view.max_y, view.height)
def cast_all_rays(min_x, max_x, min_y, max_y, width, height, eye_point, sphere_list,amb,light): image = open('image.ppm','w') print >> image, 'P3' print >> image, width, height print >> image, 255 distx=(max_x-min_x)/float(width) disty=(max_y-min_y)/float(height) for y in range(height): for x in range(width): pix_x = min_x + distx*x pix_y = max_y - disty*y vr = vector_math.vector_from_to(eye_point,data.Point(pix_x,pix_y,0.0)) ray = data.Ray(eye_point,vr) color = cast_ray(ray,sphere_list,amb,light,eye_point) print >> image, int(min(color.r*255,255)),int(min(color.g*255,255)),int(min(color.b*255,255))
def cast_ray(ray,sphere_list,ambient_color,light,eye_position): inter_list = collisions.find_intersection_points(sphere_list, ray) if inter_list != []: mindex = 0 for i in range(1,len(inter_list)): if (distance(ray.pt,inter_list[i][1]) < distance(ray.pt,inter_list[mindex][1])): mindex = i result_sphere = inter_list[mindex][0] inter_point = inter_list[mindex][1] sphere_color = result_sphere.color sphere_finish = result_sphere.finish sphere_normal = collisions.sphere_normal_at_point(result_sphere, inter_point) pt_off_sphere = find_pt_off_sphere(inter_point,sphere_normal) l_dir = vector_math.normalize_vector( vector_math.vector_from_to(pt_off_sphere, light.pt)) l_dot_n = vector_math.dot_vector(sphere_normal,l_dir) ray_off_to_l = data.Ray(pt_off_sphere,l_dir) inter_list = collisions.find_intersection_points(sphere_list,ray_off_to_l) diffuse_list = determine_diffuse_contribution(result_sphere, pt_off_sphere, light,sphere_normal, sphere_list,l_dir, l_dot_n,ray_off_to_l, inter_list) spec_intensity = determine_specular_contribution(l_dir,l_dot_n, sphere_normal, eye_position, pt_off_sphere, light, result_sphere.finish, ray_off_to_l,inter_list) result_r = ((sphere_color.r * sphere_finish.ambient * ambient_color.r) + diffuse_list[0] + spec_intensity[0]) result_g = ((sphere_color.g * sphere_finish.ambient * ambient_color.g) + diffuse_list[1] + spec_intensity[1]) result_b = ((sphere_color.b * sphere_finish.ambient * ambient_color.b) + diffuse_list[2] + spec_intensity[2]) return data.Color(result_r,result_g,result_b) else: return ambient_color
def cast_all_rays(min_x, max_x, min_y, max_y, width, height, eye_point, sphere_list, color, light, file): """ Loop through all potetial points in xy-plane, calculating the ray from eye_point to that point. For each point, determine the projected color by applying cast_ray on the sphere list Outputs one line per pixel with decimal r, g, b values separated by a space """ for y in range(height): for x in range(width): pt = Point(min_x + (max_x - min_x) * x / float(width), max_y - (max_y - min_y) * y / float(height), 0.0) ray = Ray(eye_point, vector_from_to(eye_point, pt)) c = cast_ray(ray, sphere_list, color, light) file.write(str(int(c.r * 255)) + ' ') file.write(str(int(c.g * 255)) + ' ') file.write(str(int(c.b * 255)) + ' ')
def distance(p1, p2): vector = vector_math.vector_from_to(p1, p2) return vector_math.length_vector(vector)
def test_vector_from_to_1(self): p1 = data.Point(0.0, 0.0, 0.0) p2 = data.Point(1.0, 2.0, 3.0) v = vector_math.vector_from_to(p1, p2) self.assertEqual(v, data.Vector(1.0, 2.0, 3.0))
def test_vector_from_to_1(self): from_point1 = data.Point(4, 8, 7) to_point1 = data.Point(5, 9, 6) travel = data.Point(1, 1, -1) self.assertEqual(vector_math.vector_from_to(from_point1, to_point1), travel)
def test_vector_from_to_2(self): from_point2 = data.Point(-8, 5, -6) to_point2 = data.Point(12, 15, -24) travel = data.Point(20, 10, -18) self.assertEqual(vector_math.vector_from_to(from_point2, to_point2), travel)
def test_vector_from_to_2(self): pt_1 = data.Point(2, 2, 2) pt_2 = data.Point(6, 6, 6) n_v = data.Vector(4, 4, 4) self.assertAlmostEqual(vector_math.vector_from_to(pt_1, pt_2), n_v)
def test_vector_from_to_again(self): vft = vector_math.vector_from_to(data.Point(0, 0, 1), data.Point(-3.3, 8, 9.9)) self.assertEqual(vft, data.Vector(-3.3, 8, 8.9))
def test_vector_from_to(self): vft = vector_math.vector_from_to(data.Point(3, -6, 2.9), data.Point(7, -7, 0.3)) self.assertEqual(vft, data.Vector(4, -1, -2.6))
def sphere_normal_at_point(sphere,point): return vector_math.normalize_vector(vector_math.vector_from_to(sphere.center, point))
def test_vector_from_to(self): pt_1 = data.Point(1, 1, 1) pt_2 = data.Point(5, 5, 5) n_v = data.Vector(4, 4, 4) self.assertAlmostEqual(vector_math.vector_from_to(pt_1, pt_2), n_v)