-
Notifications
You must be signed in to change notification settings - Fork 1
/
scene.py
116 lines (91 loc) · 3.12 KB
/
scene.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
'''
See examples.py, constants.py, or main.py for configurable code.
'''
from graphics import *
from marching import *
import platform
if platform.system() in ( 'Windows', 'Darwin' ):
import threading
Worker = threading.Thread
else:
import multiprocessing
Worker = multiprocessing.Process
from utils import clamp
from vec3 import Vec3
from constants import *
class Scene:
'''
The scene is where the ray marching algorithm is run and
the graphics components are used self.buffer = np.ndarray((height,width,3), dtype=np.uint8)to display it.
'''
_Pixels = {
'fast': Pixels,
'slow': PixelDrawer,
'test': PixelBase
}['fast']
def __init__(self, object, lights):
# Turtle Rendering
self.window = Window(WIDTH, HEIGHT)
self.pixels = Scene._Pixels(RESOLUTION[0], RESOLUTION[1])
# Raymarching Calculations
self.camera = Camera(
RESOLUTION[0], RESOLUTION[1],
position=Vec3(*POSITION),
angle=[ math.radians(c) for c in ANGLE ],
fov=FOV
)
self.object = object
self.lights = lights
self.material = Material(
SPECULAR,
DIFFUSE,
AMBIENT,
SHININESS
)
if THREADS > 1:
self.update_pixels = lambda: self.update_pixels_multi(THREADS)
else:
self.update_pixels = lambda: self.update_pixels()
def is_running(self):
return self.window.running
def execute(self):
self.update_pixels()
self.window.draw(self.pixels)
def get_pixel(self, x, y):
ray = self.camera.get_ray(x, y)
hit = MarchRay(ray, self.object)
if hit.collided:
return self.get_color_phong(hit)
else:
return Vec3(*BACKGROUND_COLOR)
def get_color_normal(self, hit):
return 255 * (hit.normal * 0.5 + 0.5)
def get_color_phong(self, hit):
base_color = Vec3(0,0,0)
for light in self.lights:
base_color += light.get_lighting(self.object, hit, self.material)
return base_color
def update_pixels_single(self):
for x, y in self.pixels.cors():
self.pixels.set_pixel(x, y, self.get_pixel(x,y))
def update_pixels_multi(self, thread_count):
thread_count = clamp(thread_count, 0, self.pixels.height)
coords = list(self.pixels.cors())
def on_thread(which, thread_count):
for x, y in coords[which::thread_count]:
try:
color = self.get_pixel(x, y)
self.pixels.set_pixel(x, y, color)
except Exception as e:
self.window._stop_running()
raise e
thread_pool = []
for which in range(thread_count):
thread = Worker(target=on_thread, args=(which, thread_count))
thread_pool += [thread]
thread.start()
for thread in thread_pool:
if ANIMATE_FILL:
while thread.is_alive():
self.window.draw(self.pixels)
thread.join()