def local_normal_at(self, shape_point: Point) -> Vector: maxc = max(abs(shape_point.x), abs(shape_point.y), abs(shape_point.z)) if maxc == abs(shape_point.x): return vector(shape_point.x, 0, 0) elif maxc == abs(shape_point.y): return vector(0, shape_point.y, 0) else: return vector(0, 0, shape_point.z)
def local_normal_at(self, shape_point: Point) -> Vector: # compute the square of teh distance from the y axis distance = shape_point.x**2 + shape_point.z**2 # Calculating the normal at the top cap if distance < 1 and shape_point.y >= self.maximum - EPSILON: return vector(0, 1, 0) # Calculating the normal at the bottom cap elif distance < 1 and shape_point.y <= self.minimum + EPSILON: return vector(0, -1, 0) # The normal is at the side of the cylinders else: return vector(shape_point.x, 0, shape_point.z)
def ch7(): # Step 1 floor = Sphere() floor.transform = Matrix.scaling(10, 0.01, 10) floor.material = Material() floor.material.color = Color(1, 0.9, 0.9) floor.material.specular = 0 # Step 2 left_wall = Sphere() left_wall.transform = Matrix.translation(0, 0, 5) * Matrix.rotation_y(-45) * \ Matrix.rotation_x(90) * Matrix.scaling(10, 0.01, 10) left_wall.material = floor.material # Step 3 right_wall = Sphere() right_wall.transform = Matrix.translation(0, 0, 5) * Matrix.rotation_y(45) * \ Matrix.rotation_x(90) * Matrix.scaling(10, 0.01, 10) right_wall.material = floor.material # Step 4 middle = Sphere() middle.transform = Matrix.translation(-0.5, 1, 0.5) middle.material = Material() middle.material.color = Color(0.1, 1, 0.5) middle.material.diffuse = 0.7 middle.material.specular = 0.3 # Step 5 right = Sphere() right.transform = Matrix.translation(1.5, 0.5, -0.5) * Matrix.scaling( 0.5, 0.5, 0.5) right.material = Material() right.material.color = Color(0.5, 1, 0.1) right.material.diffuse = 0.7 right.material.specular = 0.3 # Step 6 left = Sphere() left.transform = Matrix.translation(-1.5, 0.33, -0.75) * Matrix.scaling( 0.33, 0.33, 0.33) left.material = Material() left.material.color = Color(1, 0.8, 0.1) left.material.diffuse = 0.7 left.material.specular = 0.3 world = World() world.light = PointLight(point(-10, 10, -10), Color(1, 1, 1)) world.objects.extend([floor, left_wall, right_wall, middle, right, left]) camera = Camera(100, 50, 60) # camera = Camera(500, 250, 60) camera.transform = view_transform(point(0, 1.5, -5), point(0, 1, 0), vector(0, 1, 0)) canvas = camera.render(world) with open('ch8.ppm', 'w') as fp: fp.write(canvas.to_ppm())
def ch14(): world = World() world.light = PointLight(point(-10, 10, -10), Color(1, 1, 1)) hex = hexagon() world.objects.append(hex) camera = Camera(100, 50, 60) camera.transform = view_transform(point(0, 2, -1), point(0, 0, 0), vector(0, 1, 0)) canvas = camera.render(world) with open('ch14.ppm', 'w') as fp: fp.write(canvas.to_ppm())
def ch9(): # Step 1 floor = Plane() floor.transform = Matrix.scaling(10, 0.01, 10) floor.material = Material() floor.material.color = Color(1, 0.9, 0.9) floor.material.specular = 0 floor.material.pattern = StripePattern(Color(1, 0, 0), Color(0, 0, 1)) # Middle biggest sphere middle = Sphere() middle.transform = Matrix.translation(-0.5, 1, 0.5) middle.material = Material() middle.material.color = Color(0.1, 1, 0.5) middle.material.diffuse = 0.7 middle.material.specular = 0.3 middle.material.pattern = RingPattern(Color(1, 0, 1), Color(1, 1, 1)) middle.material.pattern.transform = Matrix.scaling(0.25, 0.5, 0.25) # Smaller right sphere right = Sphere() right.transform = Matrix.translation(1.5, 0.5, -0.5) * Matrix.scaling(0.5, 0.5, 0.5) right.material = Material() right.material.color = Color(0.5, 1, 0.1) right.material.diffuse = 0.7 right.material.specular = 0.3 right.material.reflective = 1.0 # Left yellow sphere left = Sphere() left.transform = Matrix.translation(-1.5, 0.33, -0.75) * Matrix.scaling(0.33, 0.33, 0.33) left.material = Material() left.material.color = Color(1, 0.8, 0.1) left.material.diffuse = 0.7 left.material.specular = 0.3 world = World() world.light = PointLight(point(-10, 10, -10), Color(1, 1, 1)) world.objects.extend([floor, middle, right, left]) camera = Camera(100, 50, 60) # camera = Camera(500, 250, 60) camera.transform = view_transform(point(0, 1.5, -5), point(0, 1, 0), vector(0, 1, 0)) canvas = camera.render(world) with open('ch9.ppm', 'w') as fp: fp.write(canvas.to_ppm())
def step_impl(context, x, y, z): context.v = vector(x, y, z)
def step_impl(context, x, y, z): context.up_vector = vector(x, y, z)
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.inv * context.v assert expected == result, f'inv * v != {expected}'
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.transform * context.v assert expected == result, f'transform * v != {expected}'
# Can probably have this done internally in the Canvas class, but left # it here for simplicity and it doesn't hide how the conversion is done. def convert_position_to_canvas(canvas: Canvas, world_position: Vec3): """Converts the position from world to canvas. This is done by subtracting the y world position from the canvas height, the other positions are left alone.""" return point(round(world_position.x), round(canvas.height - world_position.y), round(world_position.z)) if __name__ == '__main__': start = point(0, 1, 0) # The starting position can be set anywhere different velocity = vector(1, 1.8, 0).normalize( ) * 11.25 # This can be changed to any value to change the trajectory p = Projectile(start, velocity) gravity = vector( 0, -0.1, 0) # This can be changed to force the projectile down faster/slower wind = vector( -0.01, 0, 0) # This can changed to force the projectile forward less or more e = Environment(gravity, wind) screen_width = 900 # You can play around with the width of the canvas screen_height = 550 # You can play around with the height of the canvas c = Canvas(screen_width, screen_height)
def step_impl(context, px, py, pz, vx, vy, vz): context.r = Ray(point(px, py, pz), vector(vx, vy, vz))
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.comps.normalv assert expected == result, f'comps.normalv != {expected}'
def step_impl(context, x, y, z): context.direction = vector(x, y, z)
def step_impl(context, x, y, z): expected = vector(x, y, z) assert context.t.normal == expected, f't.normal != vector({x}, {y}, {z})'
def step_impl(context, x, y, z): context.n = context.s.normal_to_world(vector(x, y, z))
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.n3 assert expected == result, f'n3 != {expected}'
def local_normal_at(self, shape_point: Vec3) -> Vec3: return vector(shape_point.x, shape_point.y, shape_point.z)
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.comps.reflectv assert expected == result, f'{result} != {expected}'
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.r2.direction assert expected == result, f'r2.direction != {expected}'
def step_impl(context, x, y, z): expected = vector(x, y, z) assert expected == context.r.direction, f'r.origin != {expected}'
def step_impl(context, x, y, z): expected = vector(x, y, z) result = context.s.saved_ray.direction assert expected == result, f's.saved_ray.direction != {expected}'