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))
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))
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
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, )
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, )
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)