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 testNormals(self): sphere = Sphere(transformation=scaling(Vec(2.0, 1.0, 1.0))) ray = Ray(origin=Point(1.0, 1.0, 0.0), dir=Vec(-1.0, -1.0)) intersection = sphere.ray_intersection(ray) # We normalize "intersection.normal", as we are not interested in its length assert intersection.normal.normalize().is_close( Normal(1.0, 4.0, 0.0).normalize())
def testNormalDirection(self): # Scaling a sphere by -1 keeps the sphere the same but reverses its # reference frame sphere = Sphere(transformation=scaling(Vec(-1.0, -1.0, -1.0))) ray = Ray(origin=Point(0.0, 2.0, 0.0), dir=-VEC_Y) intersection = sphere.ray_intersection(ray) # We normalize "intersection.normal", as we are not interested in its length assert intersection.normal.normalize().is_close( Normal(0.0, 1.0, 0.0).normalize())
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)
def testUVCoordinates(self): sphere = Sphere() # The first four rays hit the unit sphere at the # points P1, P2, P3, and P4. # # ^ y # | P2 # , - ~ * ~ - , # , ' | ' , # , | , # , | , # , | , P1 # -----*-------------+-------------*---------> x # P3 , | , # , | , # , | , # , | , ' # ' - , _ * _ , ' # | P4 # # P5 and P6 are aligned along the x axis and are displaced # along z (ray5 in the positive direction, ray6 in the negative # direction). ray1 = Ray(origin=Point(2.0, 0.0, 0.0), dir=-VEC_X) assert sphere.ray_intersection(ray1).surface_point.is_close( Vec2d(0.0, 0.5)) ray2 = Ray(origin=Point(0.0, 2.0, 0.0), dir=-VEC_Y) assert sphere.ray_intersection(ray2).surface_point.is_close( Vec2d(0.25, 0.5)) ray3 = Ray(origin=Point(-2.0, 0.0, 0.0), dir=VEC_X) assert sphere.ray_intersection(ray3).surface_point.is_close( Vec2d(0.5, 0.5)) ray4 = Ray(origin=Point(0.0, -2.0, 0.0), dir=VEC_Y) assert sphere.ray_intersection(ray4).surface_point.is_close( Vec2d(0.75, 0.5)) ray5 = Ray(origin=Point(2.0, 0.0, 0.5), dir=-VEC_X) assert sphere.ray_intersection(ray5).surface_point.is_close( Vec2d(0.0, 1 / 3)) ray6 = Ray(origin=Point(2.0, 0.0, -0.5), dir=-VEC_X) assert sphere.ray_intersection(ray6).surface_point.is_close( Vec2d(0.0, 2 / 3))