Skip to content

Commit 3da6d81

Browse files
committed
Better 3D effects
1 parent cf251ab commit 3da6d81

File tree

2 files changed

+43
-26
lines changed

2 files changed

+43
-26
lines changed

geometry.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ def intersection_value(self, line):
5050
else:
5151
return []
5252

53-
def color_at_point(self, p):
54-
if int(p[0]) % 2 == int(p[1]) % 2:
53+
def color_at_point(self, point):
54+
if int(point[0]) % 2 == int(point[1]) % 2:
5555
return self.color1
5656
else:
5757
return self.color2
5858

59+
def normal(self, point):
60+
return Vector((0, 0, 1))
61+
5962
class Sphere():
6063
def __init__(self, center, radius, color):
6164
"""
@@ -77,9 +80,14 @@ def intersection_value(self, line):
7780
C = q.squared_norm() - self.radius**2
7881
return solve_quadradic(A, B, C)
7982

80-
def color_at_point(self, p):
83+
def color_at_point(self, point):
8184
return self.color
8285

86+
def normal(self, point):
87+
line = Line.through_points(self.center, point)
88+
q = Vector(line.slope)
89+
return q.normalize()
90+
8391
class Vector():
8492
def __init__(self, coords):
8593
self.coords = coords
@@ -118,6 +126,10 @@ def project(self, v2):
118126
n = float(self.scalar_product(v2))/v2.scalar_product(v2)
119127
return v2.mul_by_number(n)
120128

129+
def normalize(self):
130+
n = 1.0/self.norm()
131+
return self.mul_by_number(n)
132+
121133
def solve_quadradic(a, b, c):
122134
delta = b**2 - 4*a*c
123135
if delta < 0:

render.py

+28-23
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
from geometry import *
22
from PIL import Image
33

4-
path = "./rays.png"
5-
size = 300
6-
tmp = Image.new('RGB', (size, size), "white")
7-
rays = tmp.load()
8-
9-
def coordinates(num, sz = size):
4+
def coordinates(num, sz):
105
"""
116
Take a number in range(size) and returns the proportional value between 1 and 5
127
"""
138
return 4.0*num/(sz - 1) + 1
149

1510
def create_world():
16-
S1 = Sphere((4, 4, 2), 2, (100, 220, 0))
11+
S1 = Sphere((1, 4, 2), 2, (100, 220, 0))
1712
S2 = Sphere((2, 2, 1), 1, (0, 100, 200))
1813
S3 = Sphere((3, 1, 1), 1, (100, 100, 200))
1914
P = HorizontalPlane(0, (200, 100, 200), (0, 20, 200))
@@ -31,26 +26,36 @@ def first_intersection(scene, line):
3126
ans.sort()
3227
return [ans[0]]
3328

34-
def first_intersection_color(scene, line):
29+
def first_intersection_color(scene, line, light):
3530
ans = first_intersection(scene, line)
3631
if not ans:
3732
return (255, 255, 255)
38-
to_light = first_intersection(scene, Line.through_points(ans[0][2], light))
33+
l = Line.through_points(ans[0][2], light)
34+
to_light = first_intersection(scene, l)
3935
if to_light and to_light[0][0] < 1:
4036
return (0, 0, 0)
41-
return ans[0][1].color_at_point(ans[0][2])
37+
a, b, c = ans[0][1].color_at_point(ans[0][2])
38+
vector1 = Vector(l.slope).normalize()
39+
vector2 = ans[0][1].normal(ans[0][2])
40+
cos = vector1.scalar_product(vector2)
41+
return (int(a*cos), int(b*cos), int(c*cos))
42+
4243

43-
world = create_world()
44-
camera = (3, -1, 3)
45-
light = (3, -1, 5)
44+
def render(size):
45+
path = "./rays.png"
46+
tmp = Image.new('RGBA', (size, size), "white")
47+
rays = tmp.load()
48+
world = create_world()
49+
camera = (2, -1, 3)
50+
light = (3, -1, 10)
51+
# Colouring each pixel
52+
for i in range(size):
53+
x0 = coordinates(i, size)
54+
for k in range(size):
55+
y0 = coordinates(k, size)
56+
j = size - 1 - k
57+
l = Line.through_points(camera, (x0, 0, y0))
58+
rays[i, j] = first_intersection_color(world, l, light)
59+
tmp.save(path)
4660

47-
# Colouring each pixel
48-
for i in range(size):
49-
x0 = coordinates(i)
50-
for k in range(size):
51-
y0 = coordinates(k)
52-
j = size - 1 - k
53-
l = Line.through_points(camera, (x0, 0, y0))
54-
rays[i, j] = first_intersection_color(world, l)
55-
56-
tmp.save(path)
61+
render(300)

0 commit comments

Comments
 (0)