예제 #1
0
    def testTransformation(self):
        sphere = Sphere(transformation=translation(Vec(10.0, 0.0, 0.0)))

        ray1 = Ray(origin=Point(10, 0, 2), dir=-VEC_Z)
        intersection1 = sphere.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(10.0, 0.0, 1.0),
            normal=Normal(0.0, 0.0, 1.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=sphere.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(13, 0, 0), dir=-VEC_X)
        intersection2 = sphere.ray_intersection(ray2)
        assert intersection2
        assert HitRecord(
            world_point=Point(11.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=2.0,
            ray=ray2,
            material=sphere.material,
        ).is_close(intersection2)

        # Check if the sphere failed to move by trying to hit the untransformed shape
        assert not sphere.ray_intersection(
            Ray(origin=Point(0, 0, 2), dir=-VEC_Z))

        # Check if the *inverse* transformation was wrongly applied
        assert not sphere.ray_intersection(
            Ray(origin=Point(-10, 0, 0), dir=-VEC_Z))
예제 #2
0
    def testHit(self):
        sphere = Sphere()

        ray1 = Ray(origin=Point(0, 0, 2), dir=-VEC_Z)
        intersection1 = sphere.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(0.0, 0.0, 1.0),
            normal=Normal(0.0, 0.0, 1.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=sphere.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(3, 0, 0), dir=-VEC_X)
        intersection2 = sphere.ray_intersection(ray2)
        assert intersection2
        assert HitRecord(
            world_point=Point(1.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=2.0,
            ray=ray2,
            material=sphere.material,
        ).is_close(intersection2)

        assert not sphere.ray_intersection(
            Ray(origin=Point(0, 10, 2), dir=-VEC_Z))
예제 #3
0
    def testTransformation(self):
        plane = Plane(transformation=rotation_y(angle_deg=90.0))

        ray1 = Ray(origin=Point(1, 0, 0), dir=-VEC_X)
        intersection1 = plane.ray_intersection(ray1)
        assert intersection1
        assert HitRecord(
            world_point=Point(0.0, 0.0, 0.0),
            normal=Normal(1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.0),
            t=1.0,
            ray=ray1,
            material=plane.material,
        ).is_close(intersection1)

        ray2 = Ray(origin=Point(0, 0, 1), dir=VEC_Z)
        intersection2 = plane.ray_intersection(ray2)
        assert not intersection2

        ray3 = Ray(origin=Point(0, 0, 1), dir=VEC_X)
        intersection3 = plane.ray_intersection(ray3)
        assert not intersection3

        ray4 = Ray(origin=Point(0, 0, 1), dir=VEC_Y)
        intersection4 = plane.ray_intersection(ray4)
        assert not intersection4
예제 #4
0
    def ray_intersection(self, ray: Ray) -> Union[HitRecord, None]:
        """Checks if a ray intersects the sphere

        Return a `HitRecord`, or `None` if no intersection was found.
        """
        inv_ray = ray.transform(self.transformation.inverse())
        origin_vec = inv_ray.origin.to_vec()
        a = inv_ray.dir.squared_norm()
        b = 2.0 * origin_vec.dot(inv_ray.dir)
        c = origin_vec.squared_norm() - 1.0

        delta = b * b - 4.0 * a * c
        if delta <= 0.0:
            return None

        sqrt_delta = sqrt(delta)
        tmin = (-b - sqrt_delta) / (2.0 * a)
        tmax = (-b + sqrt_delta) / (2.0 * a)

        if (tmin > inv_ray.tmin) and (tmin < inv_ray.tmax):
            first_hit_t = tmin
        elif (tmax > inv_ray.tmin) and (tmax < inv_ray.tmax):
            first_hit_t = tmax
        else:
            return None

        hit_point = inv_ray.at(first_hit_t)
        return HitRecord(
            world_point=self.transformation * hit_point,
            normal=self.transformation *
            _sphere_normal(hit_point, inv_ray.dir),
            surface_point=_sphere_point_to_uv(hit_point),
            t=first_hit_t,
            ray=ray,
        )
예제 #5
0
파일: shapes.py 프로젝트: ziotom78/pytracer
    def ray_intersection(self, ray: Ray) -> Union[HitRecord, None]:
        """Checks if a ray intersects the plane

        Return a `HitRecord`, or `None` if no intersection was found.
        """
        inv_ray = ray.transform(self.transformation.inverse())
        if abs(inv_ray.dir.z) < 1e-5:
            return None

        t = -inv_ray.origin.z / inv_ray.dir.z

        if (t <= inv_ray.tmin) or (t >= inv_ray.tmax):
            return None

        hit_point = inv_ray.at(t)

        return HitRecord(
            world_point=self.transformation * hit_point,
            normal=self.transformation *
            Normal(0.0, 0.0, 1.0 if inv_ray.dir.z < 0.0 else -1.0),
            surface_point=Vec2d(hit_point.x - floor(hit_point.x),
                                hit_point.y - floor(hit_point.y)),
            t=t,
            ray=ray,
            material=self.material,
        )
예제 #6
0
    def testInnerHit(self):
        sphere = Sphere()

        ray = Ray(origin=Point(0, 0, 0), dir=VEC_X)
        intersection = sphere.ray_intersection(ray)
        assert intersection
        assert HitRecord(
            world_point=Point(1.0, 0.0, 0.0),
            normal=Normal(-1.0, 0.0, 0.0),
            surface_point=Vec2d(0.0, 0.5),
            t=1.0,
            ray=ray,
        ).is_close(intersection)