def run() -> None: room = create_room() objects = create_objects() world = World() world.light = PointLight(point(-10, 10, -10), Color(1, 1, 1)) world.objects.extend(room) world.objects.extend(objects) camera = Camera(400, 200, math.pi / 3) camera.transform = view_transform(point(0, 1.5, -5), point(0, 1, 0), vector(0, 1, 0)) canvas = camera.render(world) PPM(canvas).save_to_file("scene.ppm")
def canvas_to_world(canvas_coordinate: Point) -> Point: pixel_size = WALL_SIZE / CANVAS_SIZE x = pixel_size * canvas_coordinate.x - WALL_SIZE / 2 y = -(pixel_size * canvas_coordinate.y - WALL_SIZE / 2) z = WALL_Z return point(x, y, z)
def run() -> None: STEPS = 180 SIZE = 600 MIDDLE = SIZE // 2 canvas = Canvas(SIZE, SIZE) color = Color(1, 0, 0) color_increment = Color(0, 0, 1.0 / STEPS) position = point(0, 1, 0) rotate = rotation_z(-2 * math.pi / STEPS) translate = translation(MIDDLE, MIDDLE, 0) scale = scaling(SIZE // 3, SIZE // 3, 1) for i in range(STEPS): canvas_position = translate * scale * position assert isinstance(canvas_position, Point) canvas.write_pixel( int(round(canvas_position.x)), SIZE - int(round(canvas_position.y)), color, ) position = rotate * position color += color_increment ppm = PPM(canvas) file_name = "clocks.ppm" ppm.save_to_file(file_name) print(f"Output stored to {file_name}")
def normal_at(self, world_point: Point) -> Vector: transformer = inverse(self.transform) object_point = transformer * world_point object_normal = object_point - point(0, 0, 0) world_normal = transpose(transformer) * object_normal world_normal = vector(world_normal.x, world_normal.y, world_normal.z) # set w to 0 return normalize(world_normal)
def check_attribute_point(context, var, att, tuple_type, x, y, z): if tuple_type == "point": expected = point(x, y, z) elif tuple_type == "vector": expected = vector(x, y, z) elif tuple_type == "color": expected = Color(x, y, z) # type: ignore else: raise ValueError(f"tuple type '{tuple_type}' not recognized") my_variable = context.variables[var] assert (getattr( my_variable, att) == expected), f"{getattr(my_variable, att)} == {expected}"
def run() -> None: # Eye is at (0,0, 5) origin = point(0, 0, 5) shape = Sphere() # shape.set_transform(scaling(0.5, 1, 1)) shape.material.color = Color(0.9, 0.2, 1) light = PointLight(point(-10, 10, 10), Color(1, 1, 1)) canvas = Canvas(CANVAS_SIZE, CANVAS_SIZE) for i in range(CANVAS_SIZE): for j in range(CANVAS_SIZE): target = canvas_to_world(point(i, j, 0)) ray = Ray(origin, normalize(target - origin)) hit = find_hit(shape.intersect(ray)) if hit is not None: hit_point = position(ray, hit.t) normal = hit.shape.normal_at(hit_point) pixel_color = lighting(hit.shape.material, light, hit_point, -ray.direction, normal) canvas.write_pixel(i, j, pixel_color) PPM(canvas).save_to_file("sphere.ppm")
def create_structure( structure_type: str, x: float, y: float, z: float ) -> Union[Tuple, Color, Matrix]: if structure_type == "vector": return vector(x, y, z) elif structure_type == "point": return point(x, y, z) elif structure_type == "color": return Color(x, y, z) elif structure_type == "scaling": return scaling(x, y, z) elif structure_type == "translation": return translation(x, y, z) else: raise NotImplementedError(f"structure type '{structure_type}' not recognized")
def default_world() -> World: """A default world with 2 spheres and a light""" sphere_1 = Sphere() sphere_1.material = Material() sphere_1.material.color = Color(0.8, 1.0, 0.6) sphere_1.material.diffuse = 0.7 sphere_1.material.specular = 0.2 sphere_2 = Sphere() sphere_2.transform = scaling(0.5, 0.5, 0.5) world = World() world.light = PointLight(point(-10, 10, -10), Color(1, 1, 1)) world.objects.append(sphere_1) world.objects.append(sphere_2) return world
def check_position(context, var, t, x, y, z): ray = context.variables[var] expected = point(x, y, z) assert position(ray, t) == expected
def assign_ray_inline(context, var, px, py, pz, vx, vy, vz): origin = point(px, py, pz) direction = vector(vx, vy, vz) context.variables[var] = Ray(origin, direction)
def __init__(self) -> None: self.origin = point(0, 0, 0) self.radius = 1.0 self.transform = identity(4) self.material = Material()
def assign_normal(context, var, obj_var, x, y, z): shape = context.variables[obj_var] context.variables[var] = shape.normal_at(point(x, y, z))
def assign_point(context, var, x, y, z): context.variables[var] = point(x, y, z)
def assign_light_inline(context, var, x, y, z, r, g, b): context.variables[var] = PointLight(point(x, y, z), Color(r, g, b))