Esempio n. 1
0
class Shape:
    def __init__(self):
        self.transform = Identity()
        self.material = Material()
        self.parent = None

    def set_material(self, material: Material):
        self.material = material

    def set_transform(self, t: Matrix):
        self.transform *= t

    def __eq__(self, other):
        return (self.__class__ == other.__class__
                and self.material == other.material
                and self.parent == other.parent
                and self.transform == other.transform)

    def intersect(self, ray: Ray):
        local_ray = ray.transform(self.transform.inverse())
        return self.local_intersect(local_ray)

    def normal_at(self, world_point: Point):
        local_point = self.world_to_object(world_point)
        local_normal = self.local_normal_at(local_point)
        return self.normal_to_world(local_normal)

    def world_to_object(self, point: Point):
        if self.parent is not None:
            point = self.parent.world_to_object(point)
        return self.transform.inverse() * point

    def normal_to_world(self, normal: Vector):
        normalv = self.transform.inverse().transpose() * normal
        normalv.w = 0
        normalv = normalv.normalize()

        if self.parent is not None:
            normalv = self.parent.normal_to_world(normalv)

        return normalv

    def local_normal_at(self, local_point):
        raise TypeError("Generic Shapes cannot be evaluated")

    def local_intersect(self, ray):
        raise TypeError("Generic Shapes cannot be evaluated")

    def __str__(self):
        return f"{self.__class__}: Transform:\n{self.transform}"
Esempio n. 2
0
class Camera:
    def __init__(self, hsize: int, vsize: int, fov: float, transform: Matrix = None):
        self.hsize = hsize
        self.vsize = vsize
        self.fov = fov
        if transform is None:
            self.transform = Identity()
        else:
            self.transform = transform

        half_view = math.tan(self.fov / 2)
        aspect = self.hsize / self.vsize
        if aspect >= 1:
            self.half_width = half_view
            self.half_height = half_view / aspect
        else:
            self.half_width = half_view * aspect
            self.half_height = half_view
        self.pixel_size = (self.half_width * 2) / self.hsize

    def ray_for_pixel(self, px, py):
        x_offset = (px + 0.5) * self.pixel_size
        y_offset = (py + 0.5) * self.pixel_size

        world_x = self.half_width - x_offset
        world_y = self.half_height - y_offset

        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 render(self, world: World):
        image = Canvas(self.hsize, self.vsize)
        for y in range(self.vsize):
            print(y)
            for x in range(self.hsize):
                ray = self.ray_for_pixel(x, y)
                color = world.color_at(ray)
                image.write_pixel(x, y, color)
        return image
Esempio n. 3
0
class Pattern:
    def __init__(self):
        self.transform = Identity()

    def set_pattern_transform(self, t: Matrix):
        self.transform *= t

    def pattern_at_shape(self, shape, world_point: Point):
        object_point = shape.world_to_object(world_point)
        pattern_point = self.transform.inverse() * object_point
        return self.pattern_at(pattern_point)

    def pattern_at(self, point):
        raise TypeError("Generic Pattern Cannot be evaluated")