diff --git a/__pycache__/camera.cpython-33.pyc b/__pycache__/camera.cpython-33.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7ac9cd14ce80218af0287c5e0f604d59b9c1e5cf Binary files /dev/null and b/__pycache__/camera.cpython-33.pyc differ diff --git a/__pycache__/intersection.cpython-33.pyc b/__pycache__/intersection.cpython-33.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fae1ae74b367b9008f501976711328e4472c8010 Binary files /dev/null and b/__pycache__/intersection.cpython-33.pyc differ diff --git a/__pycache__/light.cpython-33.pyc b/__pycache__/light.cpython-33.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25de9666d344f0b6096dd800e61ad58c1f75cdfd Binary files /dev/null and b/__pycache__/light.cpython-33.pyc differ diff --git a/__pycache__/operation_vector.cpython-33.pyc b/__pycache__/operation_vector.cpython-33.pyc new file mode 100644 index 0000000000000000000000000000000000000000..200dee8539d5beca61dbe0c0a5cc3b84ef2dcba1 Binary files /dev/null and b/__pycache__/operation_vector.cpython-33.pyc differ diff --git a/__pycache__/raytracer.cpython-33.pyc b/__pycache__/raytracer.cpython-33.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d438c668c55e9e716dd620b8256fd685dab4b5db Binary files /dev/null and b/__pycache__/raytracer.cpython-33.pyc differ diff --git a/__pycache__/scene.cpython-33.pyc b/__pycache__/scene.cpython-33.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac3f713769654225108a1111d89b0afaa5f39b8a Binary files /dev/null and b/__pycache__/scene.cpython-33.pyc differ diff --git a/camera.py b/camera.py index a4e5e2347fbc09707b6870d2133024208fc041d9..083f32bdf7603e87e5d8f6ec2fda3564ed537ed4 100644 --- a/camera.py +++ b/camera.py @@ -1,4 +1,5 @@ from operation_vector import Vector +from raytracer import Ray class Camera: def __init__(self, image_nrows, image_ncols, distance_focale): @@ -11,6 +12,6 @@ class Camera: x = (n-row)/n n = self.image_ncols//2 y = (n-col)/n - return Vector((x, y, self.focal_length)) + return Ray(Vector([0,0,0]), Vector((x, y, self.focal_length))) diff --git a/light.py b/light.py index c324f9d66aac43f5dec06a588ad9b6e0b3f38294..674fb4ea1105b6b63f1b27715bc37f765bd15f15 100644 --- a/light.py +++ b/light.py @@ -13,7 +13,13 @@ def phong_illuminate(light, position, normal, object, viewer): R = 2*(L*N)*N - L V = (viewer - position).normalized() - i = ((kd*(L*N) + ks*(R*V)**alpha))*(N*L > 0) + if (N*L) <= 0: + return 0*position + i = ((kd*(L*N) + ks*(R*V)**alpha)) + if i < 0: + i = 0 + elif i > 1: + i = 1 return i*(light.color ** object.material.color) diff --git a/one_sphere.png b/one_sphere.png deleted file mode 100644 index 090a8d4f232416bfe3d6ea894b2eb203cac83bfb..0000000000000000000000000000000000000000 Binary files a/one_sphere.png and /dev/null differ diff --git a/operation_vector.py b/operation_vector.py index 0c9825c83c19c4005d54aff44dd6ae39547b6679..fe5ffd241221cd40c19373327dc9434580349cdd 100644 --- a/operation_vector.py +++ b/operation_vector.py @@ -3,12 +3,12 @@ from random import random class Vector: def __init__(self, coord): x, y, z = coord - self.x = x - self.y = y - self.z = z + self.x = float(x) + self.y = float(y) + self.z = float(z) def coord(self): - return (self.x, self.y, self.z) + return (float(self.x), float(self.y), float(self.z)) def __add__(first, second): if type(second) == Vector: @@ -19,7 +19,7 @@ class Vector: def __rmul__(vector, item): d, e, f = vector.coord() - return Vector((item*d, item*e, item*f)) + return Vector((float(item*d), float(item*e), float(item*f))) def __radd__(vector, item): return vector + item diff --git a/raytracer.py b/raytracer.py index 4b746b31408141b2d1830ff7ddbcb2636311af38..fe34768add2db921f28bc0fd4393e2577df39d74 100644 --- a/raytracer.py +++ b/raytracer.py @@ -25,7 +25,7 @@ def trace_ray(ray, scene, camera): color += phong_illuminate(light, class_intersect.position, class_intersect.normal, class_intersect.object, Vector([0,0,0])) color_object = class_intersect.object.material.color c_x, c_y, c_z = color.coord() - return Vector([min(c_x,1), min(c_y,1), min(c_z,1)]) + return Vector([max(min(c_x, 1), 0), max(0, min(c_y, 1)), max(0, min(c_z,1))]) def raytracer_render(camera, scene): n_lignes = camera.image_nrows @@ -33,8 +33,7 @@ def raytracer_render(camera, scene): affiche = zeros((n_lignes, n_colonnes,3)) for i in range(n_lignes): for j in range(n_colonnes): - ray_direction = camera.ray_at(i, j) - ray = Ray(Vector((0,0,0)), ray_direction) + ray = camera.ray_at(i, j) color = trace_ray(ray, scene, camera) affiche[i,j,:] = color.coord() return affiche diff --git a/scene.py b/scene.py index ff44e7be4a0772fe083cf3b3c28253869ae5b527..c18a96bce3cfcdc353f36e09f7b6754cf9666f04 100644 --- a/scene.py +++ b/scene.py @@ -7,12 +7,13 @@ class Sphere: self.material = material class Material: - def __init__(self, color, ambiant, diffuse, specular, shininess): + def __init__(self, color, ambiant, diffuse, specular, shininess, reflection): self.color = color self.ambiant = ambiant self.diffuse = diffuse self.specular = specular self.shininess = shininess + self.reflection = reflection class Scene: def __init__(self): diff --git a/script_one_sphere.py b/script_one_sphere.py index ff511e40fb2a0223c721501a9bbdcce397667b54..eeec468916dc9534f061f79d1aa18c7423655a0e 100644 --- a/script_one_sphere.py +++ b/script_one_sphere.py @@ -3,13 +3,22 @@ from light import Spotlight from camera import Camera from raytracer import raytracer_render from matplotlib.image import imsave +from math import cos, sin, pi camera = Camera(200,200,2) -materiau_sphere = Material(Vector((0,0,1)), .1, .3, .8, 20) +materiau_sphere = Material(Vector((0,0,1)), .5, .3, .7, 20, 1) sphere = Sphere(Vector([0,0,3]), 1, materiau_sphere) -lumiere = Spotlight(Vector((1, 1, 0)), Vector((1,1,1))) -scene = Scene() -scene.add_object(sphere) -scene.add_light(lumiere) -affiche = raytracer_render(camera, scene) -imsave('one_sphere.png',affiche) +for theta in range(36): + a = 3*cos(theta*pi/18) + b = 3*sin(theta*pi/18) + lumiere = Spotlight(Vector((0, a, 3+b)), Vector((1,1,1))) + lumiere_2 = Spotlight(Vector((0, -a, 3-b)), Vector((1,1,1))) + scene = Scene() + scene.add_object(sphere) + scene.add_light(lumiere) + scene.add_light(lumiere_2) + affiche = raytracer_render(camera, scene) + imsave('one_sphere_' + str(theta) + '.png',affiche) + print(theta) + + diff --git a/tests/01_camera_ok.py b/tests/01_camera_ok.py new file mode 100644 index 0000000000000000000000000000000000000000..362b2281e2525e0b0606730ce50303d34dd42874 --- /dev/null +++ b/tests/01_camera_ok.py @@ -0,0 +1,14 @@ +# Show to python where to find the Camera module +import sys +sys.path.append('..') + +# Import the Camera module +from camera import * + +# Instantiate a Camera object +c = Camera(100, 200, 3) + +# Test its members +assert(c.image_nrows == 100) +assert(c.image_ncols == 200) +assert(c.focal_length == 3) diff --git a/tests/02_rayon_ok.py b/tests/02_rayon_ok.py new file mode 100644 index 0000000000000000000000000000000000000000..1ce0c2f0970b1d1b089debc914b25d951318e8fa --- /dev/null +++ b/tests/02_rayon_ok.py @@ -0,0 +1,31 @@ +# Show to python where to find the Camera module +import sys +sys.path.append('..') + +import numpy as np +from camera import * +from operation_vector import Vector + +c = Camera(100, 200, 3) + +r_center = c.ray_at(c.image_nrows / 2, c.image_ncols / 2); + +assert (abs(r_center.direction*Vector([0,0,1]) - r_center.direction.norm()) < 0.01, "c.ray_at(c.image_nrows / 2, c.image_ncols / 2) should have the direction [0,0,1].") + +r_zero = c.ray_at(0,0); + +r_zero_ref_dir = Vector([1,1,c.focal_length]) +r_zero_ref_dir = r_zero_ref_dir / r_zero_ref_dir.norm() + +assert abs(r_zero.direction* (r_zero_ref_dir) - + r_zero.direction.norm()) < 0.01, "c.ray_at(0,0) should have the direction [1,1,camera.focal_length]."; + + +r_one = c.ray_at(c.image_nrows, c.image_ncols); +r_one_ref_dir = Vector([-1,-1,c.focal_length]) +r_one_ref_dir = r_one_ref_dir / r_one_ref_dir.norm() + +assert abs(r_one.direction*(r_one_ref_dir) - + r_one.direction.norm() < 0.01), "c.ray_at(c.nrows,c.ncols) should have the direction [-1,-1,c.focal_length."; + + diff --git a/tests/03_sphere_intersection_ok.py b/tests/03_sphere_intersection_ok.py new file mode 100644 index 0000000000000000000000000000000000000000..d7893c8e4c6da6384174ef4611ba33236fa7c6e4 --- /dev/null +++ b/tests/03_sphere_intersection_ok.py @@ -0,0 +1,33 @@ +# Show to python where to find the modules +import sys +sys.path.append('..') +from operation_vector import Vector + +from scene import * +from camera import * +from intersection import * + +def is_parallel(v1, v2): + return ((v1*v2) / (v1.norm() * v2.norm()) - 1.) < 0.01 + +s = Sphere(Vector([0,0,3]), 1, Material(Vector([0,0,1.]), 1, 1, 1, 1, 1)) + +r = Ray(Vector([0,0,0]), Vector([0,0,1])) +i = intersect(s, r) +assert (i.position == Vector([0,0,2.])), "Error with a ray starting outside the sphere." +assert is_parallel(i.normal, Vector([0,0,-1.])), "Error with the normal of a ray starting outside the sphere." + +r = Ray(Vector([0,0,10]), Vector([0,0,-1])) +i = intersect(s, r) +assert (i.position == Vector([0,0,4.])), "Error with a ray starting outside the sphere." +assert is_parallel(i.normal, Vector([0,0,1.])), "Error with the normal of a ray starting outside the sphere." + +r = Ray(Vector([0,0,3]), Vector([0,0,-1])) +i = intersect(s, r) +assert (i.position == Vector([0,0,2.])), "Error with a ray starting inside the sphere." +assert is_parallel(i.normal, Vector([0,0,1.])), "Error with the normal of a ray starting inside the sphere." + +r = Ray(Vector([0,0,5]), Vector([0,0,1])) +i = intersect(s, r) +assert i is None, "Error with a ray not intersecting the sphere: intersect should return None." + diff --git a/tests/04_material_ok.py b/tests/04_material_ok.py new file mode 100644 index 0000000000000000000000000000000000000000..1f12e23d669524d4d76cae1dd4a4bd30634e81eb --- /dev/null +++ b/tests/04_material_ok.py @@ -0,0 +1,14 @@ +import sys +sys.path.append('..') +from operation_vector import Vector + +from scene import * + +m = Material(Vector([0,0,1]), 0.1, 0.2, 0.3, 0.4, 0.5); + +assert((m.color == Vector([0,0,1]))) +assert(m.ambiant == 0.1) +assert(m.diffuse == 0.2) +assert(m.specular == 0.3) +assert(m.shininess == 0.4) +assert(m.reflection == 0.5) diff --git a/tests/05_phong_ok.py b/tests/05_phong_ok.py new file mode 100644 index 0000000000000000000000000000000000000000..9d7dedf6ab5d4dfd0c09d46e7bef9e6d35792abb --- /dev/null +++ b/tests/05_phong_ok.py @@ -0,0 +1,32 @@ +# Show to python where to find the Camera module +import sys +sys.path.append('..') +from operation_vector import Vector + +# Import the Camera module +from scene import * +from light import * + +s = Sphere(Vector([0,0,3]), 1, Material(Vector([0.1,0.2,0.3]), 0.1, 0.2, 0.3, 0.4, 0.5)); +n = Vector([0,0,-1]) +l = Spotlight(Vector([0,0,0]), Vector([0,0,1])); +p = Vector([0,0,2]) +v = Vector([0,0,0]) + +assert((phong_illuminate(l, p, n, s, v) == Vector([0,0,0.15]))) + +s = Sphere(Vector([0,0,3]), 1, Material(Vector([0.1,0.2,0.3]), 0.1, 0.2, 0.3, 0.4, 0.5)); +n = Vector([0,0,-1]) +l = Spotlight(Vector([1,1,0]), Vector([0,0,1])); +p = Vector([0,0,2]) +v = Vector([0,0,0]) +assert((phong_illuminate(l, p, n, s, v) - Vector([0, 0, 0.13])).norm() < 0.01) + + +s = Sphere(Vector([0,0,3]), 1, Material(Vector([0.1,0.2,0.3]), 0.1, 0.2, 0.3, 0.4, 0.5)); +n = Vector([0,0,-1]) +l = Spotlight(Vector([0,0,10]), Vector([0,0,1])); +p = Vector([0,0,2]) +v = Vector([0,0,0]) +assert((phong_illuminate(l, p, n, s, v) == Vector([0,0,0]))) +