2bc8365aeb2c9464850f05423951d6c7ec771461
4 Emil Mikulic <emikulic@gmail.com> was here 2012.
7 from accidental_complexity
import show
8 # this file contains mostly essential complexity
11 return np
.array((x
, y
, z
), dtype
=np
.float)
14 return np
.reshape(vec(r
,g
,b
), (1,1,3))
17 return (a
* b
).sum(axis
=2)
20 return np
.sqrt(np
.square(a
).sum(axis
=2))
23 return np
.expand_dims(a
, axis
=2)
26 return a
/ depthwise(mag(a
))
29 c
= n
* depthwise(dot(n
, -i
))
33 return depthwise(dot(n
, l
).clip(0, 1))
35 def specular(r
, l
, power
):
36 return pow(diffuse(r
, l
), power
)
38 def lerp(ar
, a
, b
, u
, v
):
39 "[u,v] is mapped to [a,b]"
40 return a
+ (b
-a
) * (ar
.clip(u
,v
) - u
) / (v
-u
)
44 self
.light1
= vec(20,10,-10)
45 self
.light1_col
= color(1,.5,.3)
46 self
.light2
= vec(-5,5,5)
47 self
.light2_col
= color(1,1,1) - self
.light1_col
48 self
.sky_col
= color(.2, .3, .6)
49 self
.sph_center
= vec(-.5,0,0)
51 self
.sph_col
= color(1,1,1)
52 self
.camera
= vec(0,0,-5)
53 self
.ground_col1
= color(.4,.4,.4)
54 self
.ground_col2
= color(.8,.8,.8)
55 self
.plane_n
= vec(0,1,0)
58 self
.plane_height
= -0.5
62 def trace_bg(self
, camera
, ray
):
64 plane_depth
= (self
.plane_height
- camera
[:,:,1]) / ray
[:,:,1]
65 plane_p
= camera
+ depthwise(plane_depth
) * ray
66 plane_l1
= norm(self
.light1
- plane_p
)
67 plane_l2
= norm(self
.light2
- plane_p
)
68 plane_xpos
= plane_p
[:,:,0] - np
.floor(plane_p
[:,:,0])
69 plane_zpos
= plane_p
[:,:,2] - np
.floor(plane_p
[:,:,2])
70 checkers
= depthwise(np
.logical_xor(plane_xpos
< 0.5, plane_zpos
< 0.5))
72 # trace shadows (light 1)
73 ec
= plane_p
- self
.sph_center
74 b
= 2 * dot(plane_l1
, ec
)
75 c
= dot(ec
, ec
) - np
.square(self
.sph_rad
)
77 depth
= (-b
- np
.sqrt(det
)) / 2
78 illum_l1
= np
.where(depthwise(depth
> 0), 0, self
.light1_col
)
81 b
= 2 * dot(plane_l2
, ec
)
83 depth
= (-b
- np
.sqrt(det
)) / 2
84 illum_l2
= np
.where(depthwise(depth
> 0), 0, self
.light2_col
)
87 plane_col
= np
.where(checkers
, self
.ground_col1
, self
.ground_col2
) * (
88 self
.plane_amb
+ self
.plane_dif
* (
89 diffuse(self
.plane_n
, plane_l1
) * illum_l1
+
90 diffuse(self
.plane_n
, plane_l2
) * illum_l2
))
92 fog_dist
= mag(plane_p
- vec(0, self
.plane_height
, 0))
93 fog
= lerp(fog_dist
, 1, 0, self
.fog_near
, self
.fog_far
)
94 plane_col
*= depthwise(np
.square(fog
))
96 sky
= self
.sky_col
* depthwise(ray
[:,:,1])
97 return np
.where(depthwise(plane_depth
> 0), plane_col
, sky
)
99 def render(self
, w
, h
):
107 # points on the screen plane (z = 0)
108 aspect
= float(w
) / float(h
)
109 scr_x
= np
.linspace(-1 + 1./w
, 1 - 1./w
, w
) * aspect
110 scr_y
= np
.linspace(-1 + 1./h
, 1 - 1./h
, h
) * -1
111 scr
= np
.zeros((h
,w
,3), dtype
=np
.float)
112 scr
[:,:,0] = np
.reshape(scr_x
, (1, w
))
113 scr
[:,:,1] = np
.reshape(scr_y
, (h
, 1))
115 ray
= norm(scr
- self
.camera
)
118 ec
= self
.camera
- self
.sph_center
120 c
= ec
.dot(ec
) - np
.square(self
.sph_rad
)
122 sph_depth
= (-b
- np
.sqrt(det
)) / 2
125 sph_p
= self
.camera
+ depthwise(sph_depth
) * ray
126 sph_l1
= norm(self
.light1
- sph_p
)
127 sph_l2
= norm(self
.light2
- sph_p
)
128 sph_n
= (sph_p
- self
.sph_center
) / self
.sph_rad
129 sph_r
= norm(reflect(ray
, sph_n
))
130 r_col
= self
.trace_bg(sph_p
, sph_r
)
132 sph
= self
.sph_col
* (sph_amb
+
133 sph_diff
* diffuse(sph_n
, sph_l1
) * self
.light1_col
+
134 sph_diff
* diffuse(sph_n
, sph_l2
) * self
.light2_col
+
135 sph_spec
* specular(sph_r
, sph_l1
, sph_shine
) * self
.light1_col
+
136 sph_spec
* specular(sph_r
, sph_l2
, sph_shine
) * self
.light2_col
+
139 bg
= self
.trace_bg(np
.reshape(self
.camera
, (1,1,3)), ray
)
140 return np
.where(depthwise(sph_depth
> 0), sph
, bg
)
142 show(Scene().render(800, 600))
143 # vim:set ts=2 sw=2 et: