def test_intersect(self): # test an intersection ray = Ray(Point(0, 0, 10), Vector(0, 0, -1)) intersection = Intersection() intersected = self.grid_accel.intersect(ray, intersection) self.assertFalse(intersected) ray.maxt = float('inf') intersected = self.grid_accel.intersect_p(ray) self.assertFalse(intersected) # test an intersection ray2 = Ray(Point(10, 0, 10), Vector(0, 0, -1)) intersection = Intersection() intersected = self.grid_accel.intersect(ray2, intersection) self.assertTrue(intersected) self.assertEqual(intersection.primitive_id, self.primitive_sphere1.primitive_id) self.assertEqual(intersection.shape_id, self.sphere1.shape_id) ray2.maxt = float('inf') intersected = self.grid_accel.intersect_p(ray2) self.assertTrue(intersected) # test an intersection ray3 = Ray(Point(-10, 0, 10), Vector(0, 0, -1)) intersection = Intersection() intersected = self.grid_accel.intersect(ray3, intersection) self.assertTrue(intersected) self.assertEqual(intersection.primitive_id, self.primitive_sphere2.primitive_id) self.assertEqual(intersection.shape_id, self.sphere2.shape_id) ray3.maxt = float('inf') intersected = self.grid_accel.intersect_p(ray3) self.assertTrue(intersected)
def generate_ray(self, sample): """Generate a Ray from the camera.""" # Generate raster and camera samples p_ras = Point(sample.image_x, sample.image_y, 0) p_camera = self.raster_to_camera(p_ras) ray = Ray(Point(0, 0, 0), normalize(Vector.from_point(p_camera)), 0.0, float('inf')) # Modify ray for depth of field if self.lens_radius > 0.0: # Sample point on lens lens_u, lens_v = concentric_sample_disk(sample.lens_u, sample.lens_v) lens_u *= self.lens_radius lens_v *= self.lens_radius # Compute point on plane of focus ft = self.focal_distance / ray.d.z p_focus = ray(ft) # Update ray for effect of lens ray.o = Point(lens_u, lens_v, 0.0) ray.d = normalize(p_focus - ray.o) ray.time = sample.time ray = self.camera_to_world(ray) return 1.0, ray
def test_ray_differential(self): r = Ray(Point(0, 0, 0), Vector(1, 2, 3)) rd = RayDifferential(Point(0, 0, 0), Vector(1, 2, 3)) # test copy constructor from Ray rd.has_differentials = True rd1 = RayDifferential.from_ray_differential(rd) self.assertTrue(isinstance(rd1, RayDifferential)) self.assertEqual(rd1.o, rd.o) self.assertEqual(rd1.d, rd.d) self.assertEqual(rd1.rx_origin, rd.rx_origin) self.assertEqual(rd1.ry_origin, rd.ry_origin) self.assertEqual(rd1.rx_direction, rd.rx_direction) self.assertEqual(rd1.ry_direction, rd.ry_direction) self.assertEqual(rd1.has_differentials, rd.has_differentials) # test copy constructor from Ray rd2 = RayDifferential.from_ray(r) self.assertTrue(isinstance(rd2, RayDifferential)) self.assertEqual(rd2.d, r.d) self.assertEqual(rd2.has_differentials, False) # test constructor from parent ray rd3 = RayDifferential.from_ray_parent(r.o, r.d, r, r.mint) self.assertTrue(isinstance(rd3, RayDifferential)) self.assertEqual(rd3.depth, r.depth + 1) # test operator() p = rd(1.7) self.assertEqual(p, Point(1.7, 3.4, 5.1))
def main(): """Main function.""" if len(sys.argv) < 5: print "Error. Specify filename, sene, width, height." return -1 filename = sys.argv[1] scene = sys.argv[2] width = int(sys.argv[3]) height = int(sys.argv[4]) if scene == "sp": primitives = create_simple_sphere() cam_pos = Point(0, 3, 8) cam_look = Point(0, 0.8, 0) cam_up = Vector(0, 1, 0) elif scene == "py": primitives = create_pyramid() cam_pos = Point(10, 10, 4) cam_look = Point(0, 0, 2) cam_up = Vector(0, 0, 1) else: print "unknown scene" return -1 cam_transform = look_at(cam_pos, cam_look, cam_up) scene = create_scene(primitives) film = create_film(filename, width, height) camera = create_camera(film, cam_transform) renderer = create_renderer(camera) # launch render renderer.render(scene) return 0
def test_bounding_box_1(self): # test default constructor b = BBox() self.assertEqual(b.p_min, Point(float('inf'), float('inf'), float('inf'))) self.assertEqual(b.p_max, Point(-float('inf'), -float('inf'), -float('inf')))
def test_transform_ray(self): ray = Ray(origin=Point(1, 2, 3), direction=Vector(10, 20, 30)) ray_transformed = translate(Point(10, 20, 30))(ray) self.assertTrue(isinstance(ray_transformed, Ray)) self.assertEqual(ray_transformed.o, Point(11, 22, 33)) self.assertEqual(ray_transformed.d, Vector(10, 20, 30))
def __init__(self, camera_to_world, screen_window, s_open, s_close, lens_radius, focal_distance, fov, film): super(PerspectiveCamera, self).__init__(camera_to_world, perspective(fov, 1e-2, 1000.0), screen_window, s_open, s_close, lens_radius, focal_distance, film) self.dx_camera = self.raster_to_camera(Point(1, 0, 0)) - \ self.raster_to_camera(Point(0, 0, 0)) self.dy_camera = self.raster_to_camera(Point(0, 1, 0)) - \ self.raster_to_camera(Point(0, 0, 0))
def time_sphere_intersection(): # create a transform o2w = translate(Vector(10,0,0)) * scale(1.3, 1.8, 2.0) w2o = o2w.inverse() # create the sphere sphere = Sphere(o2w, w2o, False, 1.0, -1.0, 1.0, 360) # create a large amount of rays, # choose so that half of them will intersect the ray positions = [Point(random.randint(0,100), random.randint(0,100), random.randint(0,100) ) for i in range(size)] ray = Ray(Point(0,0,0), Vector(1.0, 1.0, 1.0)) vectors = [] for i in xrange(size): position = positions[i] if i%2 == 0: # make sure this ray hit the sphere vector = sphere.object_to_world(Point(0, 0, 0)) - position vector /= float(random.randint(1,10)) else: # construct a random vector vector = Vector((random.random()-0.5)*random.randint(1,5), (random.random()-0.5)*random.randint(1,5), (random.random()-0.5*random.randint(1,5))) vectors.append(vector) intersections = 0 t1 = time.time() for i in xrange(nb_calls): ray.o = positions[i%size] ray.d = vectors[i%size] if sphere.intersect_p(ray): intersections += 1 t2 = time.time() for i in xrange(nb_calls): ray.o = positions[i%size] ray.d = vectors[i%size] sphere.intersect(ray) t3 = time.time() print "%d calls, %d intersections" % (nb_calls, intersections) print "Sphere.intersect_p() %.2fms" % ((t2-t1)/float(nb_calls)*1000.0) print "Sphere.intersect() %.2fms" % ((t3-t2)/float(nb_calls)*1000.0)
def test_bounding_box_9(self): bbox = BBox(Point(-1, -1, -1), Point(1, 1, 1)) ray1 = Ray(Point(10, 10, 10), Vector(-1, -1, -1)) intersect, hit0, hit1 = bbox.intersect_p(ray1) self.assertTrue(intersect) ray2 = Ray(Point(10, 10, 10), Vector(-1, 1, -1)) intersect, hit0, hit1 = bbox.intersect_p(ray2) self.assertFalse(intersect) ray3 = Ray(Point(0, 0, 10), Vector(0, 0, -1)) intersect, hit0, hit1 = bbox.intersect_p(ray3) self.assertTrue(intersect) self.assertEqual(hit0, 9.0) self.assertEqual(hit1, 11.0)
def test_point(self): # operator[] p = Point(1.0, 2.0, 3.0) self.assertEqual(p[0], 1.0) self.assertEqual(p[1], 2.0) self.assertEqual(p[2], 3.0) self.assertEqual(self.p1 * 4, 2 * self.p2) self.assertEqual(self.p2 - self.p1, self.v1) # operator[] for assignments p = Point(1.0, 2.0, 3.0) for i in range(3): p[i] = 9.0 self.assertEqual(p[i], 9.0)
def create_pyramid(): primitives = [] # create the sphere primitive material = None object_to_world = Transform() world_to_object = Transform() sphere = Sphere(object_to_world, world_to_object, False, 1.0, -1.0, 1.0, 360) primitive = GeometricPrimitive(sphere, material, None) # now create the instances # create the objects, with this layout (shown in 2D) # O O O O level 0, width 4, pos_x -6 # O O O level 1, width 3, pos_x -4 # O O level 2, width 2, pos_x -2 # O level 3, width 1, pos_x 0 for level in range(4): width_array = 4 - level start_pos = Point(-2.0 * (3 - level), -2.0 * (3 - level), level * 2.0) for i in range(width_array): start_pos_i = start_pos + i * Vector(2.0, 0.0, 0.0) for j in range(width_array): pos = start_pos_i + j * Vector(0.0, 2.0, 0.0) transform = translate(pos).inverse() world_to_primitive = AnimatedTransform(transform, 0.0, transform, 1.0) instance = TransformedPrimitive(primitive, world_to_primitive) primitives.append(instance) return primitives
def test_ray(self): r = Ray(Point(0, 0, 0), Vector(1, 2, 3)) # test copy constructor r2 = Ray.from_ray(r) self.assertTrue(isinstance(r2, Ray)) self.assertEqual(r2.d, r.d) # test constructor from parent ray r3 = Ray.from_ray_parent(r.o, r.d, r, r.mint) self.assertTrue(isinstance(r3, Ray)) self.assertEqual(r3.depth, r.depth + 1) # test operator() p = r(1.7) self.assertEqual(p, Point(1.7, 3.4, 5.1))
def sample_p(self, p, u1, u2): """Sample at point p.""" # Compute coordinate system for sphere sampling p_center = self.object_to_world(Point(0, 0, 0)) wc = normalize(p_center - p) wc_x, wc_y = coordinate_system(wc) # Sample uniformly on sphere if $\pt{}$ is inside it if (distance_squared(p, p_center) - self.radius * self.radius) < 1e-4: return self.sample(u1, u2) # Sample sphere uniformly inside subtended cone sin_theta_max2 = self.radius * self.radius / distance_squared( p, p_center) cos_theta_max = math.sqrt(max(0.0, 1.0 - sin_theta_max2)) raise Exception("next_line") # r = Ray(p, uniform_sample_cone(u1, u2, cos_theta_max, wcX, wcY, wc), 1e-3) r = Ray(p) intersect, t_hit, ray_epsilon, dg_sphere = self.intersect(r) if not intersect: t_hit = dot(p_center - p, normalize(r.d)) ps = r(t_hit) ns = Normal(normalize(ps - p_center)) if (self.reverse_orientation): ns *= -1.0 return ps, ns
def sample(self, u1, u2): """Sample the shape.""" raise Exception("check_next_line") p = Point(0, 0, 0) + self.radius * 1.0 # uniform_sample_sphere(u1, u2) ns = normalize(self.object_to_world(Normal(p.x, p.y, p.z))) if (self.reverse_orientation): ns *= -1.0 return self.object_to_world(p), ns
def create_simple_sphere(): primitives = [] material = None object_to_world = translate(Point(0, 1, 0)) world_to_object = object_to_world.inverse() sphere = Sphere(object_to_world, world_to_object, False, 1.0, -1.0, 1.0, 360) primitive = GeometricPrimitive(sphere, material, None) primitives.append(primitive) return primitives
def test_bounding_box_4(self): # test copy constructor bbox = BBox(Point(5, 5, 5), Point(7, 7, 7)) bbox2 = BBox.from_bbox(bbox) self.assertEqual(bbox.p_min, bbox2.p_min) self.assertEqual(bbox.p_max, bbox2.p_max) p1 = Point(6, 5.5, 7) p2 = Point(6, 7.5, 7) p3 = Point(6, 6.5, 4.5) # test methods self.assertEqual(bbox.inside(p1), True) self.assertEqual(bbox.inside(p2), False) self.assertEqual(bbox.inside(p3), False) bbox.expand(1) self.assertEqual(bbox.inside(p1), True) self.assertEqual(bbox.inside(p2), True) self.assertEqual(bbox.inside(p3), True)
def test_inverse(self): m1 = scale(2.0, 3.0, 4.0) m2 = scale(1.0/2.0, 1.0/3.0, 1.0/4.0) self.assertEqual(m1.inverse(), m2) self.assertEqual(m1.m_inv, m2.m) self.assertEqual(m2.m_inv, m1.m) m3 = translate(Point(5, 6, 7)) * scale(2, -3 , 4) * rotate(17, Vector(-1, 4, -2)) m4 = m3.inverse() identity = Transform() self.assertTrue((m3*m4).is_identity()) self.assertTrue((m4*m3).is_identity())
def test_intersect(self): # test an intersection ray = Ray(Point(20, 10, 10), Vector(-1, -1, -1)) intersect, t_hit, ray_epsilon, dg = self.sphere.intersect(ray) self.assertTrue(intersect) intersect = self.sphere.intersect_p(ray) self.assertTrue(intersect) # test an intersection ray = Ray(Point(20, 10, 10), Vector(-1, 1, -1)) intersect, t_hit, ray_epsilon, dg = self.sphere.intersect(ray) self.assertFalse(intersect) intersect = self.sphere.intersect_p(ray) self.assertFalse(intersect) # test an intersection ray = Ray(Point(10, 0, 0), Vector(3, 1, -2)) intersect, t_hit, ray_epsilon, dg = self.sphere.intersect(ray) self.assertTrue(intersect) intersect = self.sphere.intersect_p(ray) self.assertTrue(intersect)
def test_transform_bbox(self): box = BBox(Point(-1, -2, 0), Point(0, 3, -4)) box_transformed = translate(Point(10, 20, 30))(box) self.assertTrue(isinstance(box_transformed, BBox)) self.assertEqual(box_transformed.p_min, Point(9, 18, 26)) self.assertEqual(box_transformed.p_max, Point(10, 23, 30)) box_transformed2 = scale(2, 3, 4)(box) self.assertTrue(isinstance(box_transformed2, BBox)) self.assertEqual(box_transformed2.p_min, Point(-2, -6, -16)) self.assertEqual(box_transformed2.p_max, Point(0, 9, 0))
def test_bounding_box_7(self): bbox1 = BBox(Point(0, 0, 0), Point(2, 2, 2)) bbox2 = BBox(Point(2.5, 2.5, 2.5), Point(3, 3, 3)) self.assertEqual(bbox1.overlaps(bbox2), False) bbox3 = BBox(Point(-1, -1, -1), Point(0.5, 0.5, 0.5)) self.assertEqual(bbox1.overlaps(bbox3), True)
def pdf_wi(self, p, wi): """Intersect sample ray with area light geometry.""" p_center = self.object_to_world(Point(0, 0, 0)) # Return uniform weight if point inside sphere if (distance_squared(p, p_center) - self.radius * self.radius) < 1e-4: return Shape.pdf_wi(self, p, wi) # Compute general sphere weight sin_theta_max2 = self.radius * self.radius / distance_squared( p, p_center) cos_theta_max = math.sqrt(max(0.0, 1.0 - sin_theta_max2)) raise Exception("next_line") # return uniform_cone_pdf(cos_theta_max) return 0.0
def generate_ray_differential(self, sample): """Generate a RayDifferential from the camera.""" # Generate raster and camera samples p_ras = Point(sample.image_x, sample.image_y, 0) p_camera = self.raster_to_camera(p_ras) ray = RayDifferential(Point(0, 0, 0), normalize(Vector.from_point(p_camera)), 0.0, float('inf')) # Modify ray for depth of field if self.lens_radius > 0.0: # Sample point on lens lens_u, lens_v = concentric_sample_disk(sample.lens_u, sample.lens_v) lens_u *= self.lens_radius lens_v *= self.lens_radius # Compute point on plane of focus ft = self.focal_distance / ray.d.z p_focus = ray(ft) # Update ray for effect of lens ray.o = Point(lens_u, lens_v, 0.0) ray.d = normalize(p_focus - ray.o) ray.rx_origin = Point.from_point(ray.o) ray.ry_origin = Point.from_point(ray.o) ray.rx_direction = normalize(Vector.from_point(p_camera) + \ self.dx_camera) ray.ry_direction = normalize(Vector.from_point(p_camera) + \ self.dy_camera) ray.time = sample.time ray = self.camera_to_world(ray) ray.has_differentials = True return 1.0, ray
def test_transform_ray(self): ray_differential = RayDifferential(origin=Point(1,2,3), direction=Vector(10,20,30)) ray_differential.rx_origin = Point(4,5,6) ray_differential.ry_origin = Point(5,6,7) ray_differential.rx_direction = Vector(2,3,4) ray_differential.ry_direction = Vector(3,4,5) ray_transformed = translate(Point(10,20,30))(ray_differential) self.assertTrue(isinstance(ray_transformed, RayDifferential)) self.assertEqual(ray_transformed.o, Point(11,22,33)) self.assertEqual(ray_transformed.d, Vector(10,20,30)) self.assertEqual(ray_transformed.rx_origin, Point(14,25,36)) self.assertEqual(ray_transformed.ry_origin, Point(15,26,37)) self.assertEqual(ray_transformed.rx_direction, Vector(2,3,4)) self.assertEqual(ray_transformed.ry_direction, Vector(3,4,5))
def __init__(self, camera_to_world, projection, screen_window, s_open, s_close, lens_radius, focal_distance, film): """Default constructor for ProjectiveCamera.""" super(ProjectiveCamera, self).__init__(camera_to_world, s_open, s_close, film) # initialize depth of field parameters self.lens_radius = lens_radius self.focal_distance = focal_distance # compute projective camera transformations self.camera_to_screen = projection # compute projective camera screen transformations sc1 = scale(float(film.x_resolution), float(film.y_resolution), 1.0) sc2 = scale(1.0 / (screen_window[1] - screen_window[0]), 1.0 / (screen_window[2] - screen_window[3]), 1.0) tr = translate(Point(-screen_window[0], -screen_window[3], 0.0)) self.screen_to_raster = sc1 * sc2 * tr self.raster_to_screen = inverse(self.screen_to_raster) self.raster_to_camera = inverse(self.camera_to_screen) * \ self.raster_to_screen
def test_transform(self): p = Point(1, 2, 3) p2 = translate(Point(10, 20, 30))(p) self.assertTrue(isinstance(p2, Point)) self.assertEqual(p2, Point(11, 22, 33)) v = Vector(1, 2, 3) v2 = translate(Point(10, 20, 30))(v) self.assertTrue(isinstance(v2, Vector)) self.assertEqual(v2, Vector(1, 2, 3)) self.assertEqual(scale(2, 3, 4)(Point(1, 2, 3)), Point(2, 6, 12)) self.assertEqual(scale(2, 3, 4)(Vector(1, 2, 3)), Vector(2, 6, 12)) self.assertEqual(rotate(90, Vector(0, 1, 0))(Normal(1, 0, 0)), Normal(0, 0, -1))
def __init__(self): """Default constructor for DifferentialGeometry.""" self.p = Point() self.nn = Normal() self.u = 0.0 self.v = 0.0 self.shape = None self.dp_du = Vector() self.dp_dv = Vector() self.dn_du = Normal() self.dn_dv = Normal() self.dp_dx = Vector() self.dp_dy = Vector() self.du_dx = 0.0 self.dv_dx = 0.0 self.du_dy = 0.0 self.dv_dy = 0.0
def test_transform_transform(self): m1 = scale(2, 3, 4) * translate(Point(10, 20, 30)) m2 = translate(Point(20, 60, 120)) * scale(2, 3, 4) self.assertEqual(m1, m2)
def __call__(self, elt): """Overload the operator(). Supported operations: * Transform(Point) * Transform(Vector) * Transform(Normal) * Transform(Ray) * Transform(RayDifferential) * Transform(BBox) """ if isinstance(elt, Point): x = elt.x y = elt.y z = elt.z xp = self.m.m[0][0] * x + self.m.m[0][1] * y + self.m.m[0][ 2] * z + self.m.m[0][3] yp = self.m.m[1][0] * x + self.m.m[1][1] * y + self.m.m[1][ 2] * z + self.m.m[1][3] zp = self.m.m[2][0] * x + self.m.m[2][1] * y + self.m.m[2][ 2] * z + self.m.m[2][3] wp = self.m.m[3][0] * x + self.m.m[3][1] * y + self.m.m[3][ 2] * z + self.m.m[3][3] if wp == 1.0: return Point(xp, yp, zp) else: return Point(xp, yp, zp) / wp elif isinstance(elt, Vector): x = elt.x y = elt.y z = elt.z xp = self.m.m[0][0] * x + self.m.m[0][1] * y + self.m.m[0][2] * z yp = self.m.m[1][0] * x + self.m.m[1][1] * y + self.m.m[1][2] * z zp = self.m.m[2][0] * x + self.m.m[2][1] * y + self.m.m[2][2] * z return Vector(xp, yp, zp) elif isinstance(elt, Normal): x = elt.x y = elt.y z = elt.z return Normal( self.m_inv.m[0][0] * x + self.m_inv.m[1][0] * y + self.m_inv.m[2][0] * z, self.m_inv.m[0][1] * x + self.m_inv.m[1][1] * y + self.m_inv.m[2][1] * z, self.m_inv.m[0][2] * x + self.m_inv.m[1][2] * y + self.m_inv.m[2][2] * z) elif isinstance(elt, RayDifferential): ray = RayDifferential.from_ray_differential(elt) ray.o = self(ray.o) ray.d = self(ray.d) ray.rx_origin = self(ray.rx_origin) ray.ry_origin = self(ray.ry_origin) ray.rx_direction = self(ray.rx_direction) ray.ry_direction = self(ray.ry_direction) return ray elif isinstance(elt, Ray): ray = Ray.from_ray(elt) ray.o = self(ray.o) ray.d = self(ray.d) return ray elif isinstance(elt, BBox): ret = BBox(self(Point(elt.p_min.x, elt.p_min.y, elt.p_min.z))) ret = union(ret, self(Point(elt.p_max.x, elt.p_min.y, elt.p_min.z))) ret = union(ret, self(Point(elt.p_min.x, elt.p_max.y, elt.p_min.z))) ret = union(ret, self(Point(elt.p_min.x, elt.p_min.y, elt.p_max.z))) ret = union(ret, self(Point(elt.p_min.x, elt.p_max.y, elt.p_max.z))) ret = union(ret, self(Point(elt.p_max.x, elt.p_max.y, elt.p_min.z))) ret = union(ret, self(Point(elt.p_max.x, elt.p_min.y, elt.p_max.z))) ret = union(ret, self(Point(elt.p_max.x, elt.p_max.y, elt.p_max.z))) return ret
def test_transform_handedness(self): m1 = translate(Point(-17, 2, 31)) * scale(0.5, 6 , 1.4) * rotate(35, Vector(-15, 20, 0.2)) self.assertFalse(m1.swap_handedness()) m2 = translate(Point(5, 6, 7)) * scale(2, -3 , 4) * rotate(17, Vector(-1, 4, -2)) self.assertTrue(m2.swap_handedness())
def object_bound(self): """Return bounding box in object space.""" return BBox(Point(-self.radius, -self.radius, self.z_min), Point(self.radius, self.radius, self.z_max))
def setUp(self): self.v1 = Vector(1, 1, 1) self.v2 = Vector(2, 2, 2) self.p1 = Point(1, 1, 1) self.p2 = Point(2, 2, 2)