예제 #1
0
    def split_bounds(self):
        # figure out the box's largest dimension
        dx = abs(self.min.x - self.max.x)
        dy = abs(self.min.y - self.max.y)
        dz = abs(self.min.z - self.max.z)

        greatest = max(dx, dy, dz)

        # variables to help construct the points on
        # the dividing plane
        x0, y0, z0 = self.min.x, self.min.y, self.min.z
        x1, y1, z1 = self.max.x, self.max.y, self.max.z

        # adjust the points so that they lie on the
        # dividing plane
        if greatest == dx:
            x0 = x1 = x0 + dx / 2.0
        elif greatest == dy:
            y0 = y1 = y0 + dy / 2.0
        else:
            z0 = z1 = z0 + dz / 2.0

        mid_min = point(x0, y0, z0)
        mid_max = point(x1, y1, z1)

        # construct and return the two halves of
        # the bounding box
        left = BoundingBox(self.min, mid_max)
        right = BoundingBox(mid_min, self.max)

        return left, right
예제 #2
0
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())
예제 #3
0
 def __init__(self, min: Point = None, max: Point = None):
     if min is None:
         self.min = point(float('inf'), float('inf'), float('inf'))
     else:
         self.min = min
     if max is None:
         self.max = point(float('-inf'), float('-inf'), float('-inf'))
     else:
         self.max = max
예제 #4
0
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())
예제 #5
0
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 ray_for_pixel(self, px: int, py: int) -> Ray:
        # the offset from the edge of the canvas to pixel's center
        xoffset = (px + 0.5) * self.pixel_size
        yoffset = (py + 0.5) * self.pixel_size

        # the untransformed coordinates of the pixel in world space.
        # (remember that the camera looks toward -z, so +x is to the *left*.)
        world_x = self.half_width - xoffset
        world_y = self.half_height - yoffset

        # using the camera matrix, transform the canvas point and the origin,
        # and then compute the ray's direction vector.
        # (remember that the canvas is at z=-1)
        pixel = self.transform.inverse() * point(world_x, world_y, -1)
        origin = self.transform.inverse() * point(0, 0, 0)
        direction = (pixel - origin).normalize()

        return Ray(origin, direction)
def default_world():
    world = World()
    world.light = PointLight(point(-10, 10, -10), Color(1, 1, 1))

    s1 = Sphere()
    s1.material.color = Color(0.8, 1.0, 0.6)
    s1.material.diffuse = 0.7
    s1.material.specular = 0.2
    world.objects.append(s1)

    s2 = Sphere()
    s2.transform = Matrix.scaling(0.5, 0.5, 0.5)
    world.objects.append(s2)

    return world
예제 #8
0
    def local_intersect(self, shape_ray: Ray) -> GroupIntersections:
        # the vector from the sphere's center, to the ray origin
        # remember: the sphere is centered at the world origin
        sphere_to_ray = shape_ray.origin - point(0, 0, 0)

        a = Vec3.dot(shape_ray.direction, shape_ray.direction)
        b = 2 * Vec3.dot(shape_ray.direction, sphere_to_ray)
        c = Vec3.dot(sphere_to_ray, sphere_to_ray) - 1

        discriminant = (b**2) - (4 * a * c)
        if discriminant < 0:
            return GroupIntersections()
        else:
            t1 = Intersection((-b - math.sqrt(discriminant)) / (2 * a), self)
            if discriminant == 0:
                return GroupIntersections(t1, t1)
            t2 = Intersection((-b + math.sqrt(discriminant)) / (2 * a), self)
            return GroupIntersections(
                t1, t2) if t1 < t2 else GroupIntersections(t2, t1)
예제 #9
0
    def transform(self, matrix: Matrix):
        p1 = self.min
        p2 = point(self.min.x, self.min.y, self.max.z)
        p3 = point(self.min.x, self.max.y, self.min.z)
        p4 = point(self.min.x, self.max.y, self.max.z)
        p5 = point(self.max.x, self.min.y, self.min.z)
        p6 = point(self.max.x, self.min.y, self.max.z)
        p7 = point(self.max.x, self.max.y, self.min.z)
        p8 = self.max

        new_bounding_box = BoundingBox()
        for p in [p1, p2, p3, p4, p5, p6, p7, p8]:
            new_bounding_box.add(matrix * p)

        return new_bounding_box
예제 #10
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.full_quarter * context.p
    assert expected == result, f'full_quarter * p != {expected}'
예제 #11
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.half_quarter * context.p
    assert expected == result, f'half_quarter * p({result}) != {expected}'
예제 #12
0
def step_impl(context, x, y, z):
    context.p = point(x, y, z)
예제 #13
0
def step_impl(context, attribute, min_x, min_y, min_z, max_x, max_y, max_z):
    setattr(
        context, attribute,
        BoundingBox(point(min_x, min_y, min_z), point(max_x, max_y, max_z)))
예제 #14
0
def step_impl(context, x, y, z):
    context.to_point = point(x, y, z)
예제 #15
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.T * context.p
    assert expected == result
예제 #16
0
def step_impl(context, t, x, y, z):
    expected = point(x, y, z)
    result = context.r.position(t)
    assert expected == result, f'position(r, 0) - {result} != {expected}'
예제 #17
0
def step_impl(context, px, py, pz, vx, vy, vz):
    context.r = Ray(point(px, py, pz), vector(vx, vy, vz))
예제 #18
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.r2.origin
    assert expected == result, f'r2.origin != {expected}'
예제 #19
0
def step_impl(context, x, y, z):
    context.origin = point(x, y, z)
예제 #20
0
def step_impl(context, x, y, z, r, g, b):
    context.w.light = PointLight(point(x, y, z), Color(r, g, b))
예제 #21
0
def step_impl(context, attribute, x, y, z):
    expected = point(x, y, z)
    obj = getattr(context, attribute)
    result = obj.max
    is_equal = expected == result
    assert is_equal, f'box.max:{result} != {expected}'
예제 #22
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.p2
    assert expected == result, f'p2({result}) != {expected}'
예제 #23
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.p4
    assert expected == result, f'p4 != {expected}'
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))
예제 #25
0
def step_impl(context, x, y, z):
    context.from_point = point(x, y, z)
예제 #26
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.transform * context.p
    assert expected == result, f'transform * p != point({x}, {y}, {z})'
예제 #27
0
 def bounds_of(self) -> BoundingBox:
     return BoundingBox(point(-1, -1, -1), point(1, 1, 1))
예제 #28
0
def step_impl(context, x, y, z):
    expected = point(x, y, z)
    result = context.inv * context.p
    assert expected == result, f'inv * p != point({x}, {y}, {z})'
    proj.velocity = proj.velocity + env.gravity + env.wind
    return Projectile(proj.position, proj.velocity)


# 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
예제 #30
0
 def bounds_of(self) -> BoundingBox:
     a = abs(self.minimum)
     b = abs(self.maximum)
     limit = max(a, b)
     return BoundingBox(point(-limit, self.minimum, -limit),
                        point(limit, self.maximum, limit))