-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAlgebra.py
More file actions
209 lines (147 loc) · 5.06 KB
/
Algebra.py
File metadata and controls
209 lines (147 loc) · 5.06 KB
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#########################################
# ----------------PyPath-----------------#
# Simple Path Tracer Programmed in Python#
# ----------By: Julian Villella----------#
# ------Start Date: August 17, 2011------#
#########################################
# Modules
from math import sqrt, cos, sin
# -------------------------------------------------Vector3D class
class Vector3D:
# Initializer
def __init__(self, x_element, y_element, z_element):
self.x = x_element
self.y = y_element
self.z = z_element
# Operator Overloading
def __sub__(self, v):
return Vector3D(self.x - v.x, self.y - v.y, self.z - v.z)
def __add__(self, v):
return Vector3D(self.x + v.x, self.y + v.y, self.z + v.z)
def __mul__(self, s):
return Vector3D(self.x * s, self.y * s, self.z * s)
def __truediv__(self, s):
return Vector3D(self.x / s, self.y / s, self.z / s)
def __repr__(self):
return "Algebra.Vector3D ({}, {}, {})".format(self.x, self.y, self.z)
# Return dot product between two vectors
def Dot(a, b):
return a.x * b.x + a.y * b.y + a.z * b.z
# Return perpendicular vector
def Cross(a, b):
return Vector3D(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x)
# Return length of vector
def Length(v):
return sqrt(v.x * v.x + v.y * v.y + v.z * v.z)
# Return normalized vector (unit vector)
def Normalize(v):
return v * (1.0 / Length(v))
# Return the normal vector from a triangule
def Normal(a, b, c):
v = b - a
s = c - a
# Cross Product - Normal vector
normal = Cross(v, s)
# Normalize normal vector
return Normalize(normal)
# flip direction
def flip_direction(vector=Vector3D(0,0,0)):
return vector * -1.0
def sample_direction(u1, u2):
z = pow(1.0 - u1, 1.0 / 1.0)
phi = 6.24 * u2 # Azimuth
theta = sqrt(max(0.0, 1.0 - z * z))
p = Vector3D
p.x = theta * cos(phi)
p.y = theta * sin(phi)
p.z = z
return p
def random_direction(u1, u2, normal):
p = sample_direction(u1, u2) #random point on hemisphere
#create orthonormal basis around normal
w = normal
v = Cross(Vector3D(0.00319, 1.0, 0.0078), w) #jittered up
v = Normalize(v) #normalize
u = Cross(v, w)
hemi_dir = (u * p.x) + (v * p.y) + (w * p.z) #linear projection
return Normalize(hemi_dir)
def Parallelogram_Area(A, B, P):
v = B - A
s = P - A
cross = Cross(v, s)
return Dot(v, s)
def local_color(obj, hit_normal, ray, ambient):
# Iluminação do objeto
color = obj.color
# Iluminação ambiente
ia = ambient * float(obj.ka)
color = color + (RGBColour(ia, ia, ia))
# Iluminação difusa
p1 = Normalize(flip_direction(ray.d))
p2 = hit_normal
if (Length(p1) != 1):
p1 = Normalize(p1)
if (Length(hit_normal) != 1):
p2 = Normalize(hit_normal)
lv = 1.0 * float(obj.kd) * Dot(p1, p2)
color = color + (RGBColour(lv, lv, lv))
# Iluminação especular
p1 = Vector3D(p1.x * (-1), p1.y, p1.z)
p2 = ray.o
if (Length(p1) != 1):
p1 = Normalize(p1)
if (Length(ray.o) != 1):
p2 = Normalize(ray.o)
lv = 1.0 * float(obj.ks) * pow(Dot(p1, p2), float(obj.n))
color = color + (RGBColour(lv, lv, lv))
return color
def tonemapping(pixel, tmapping):
pixel.r = pixel.r / (pixel.r + tmapping)
pixel.g = pixel.g / (pixel.g + tmapping)
pixel.b = pixel.b / (pixel.b + tmapping)
# -------------------------------------------------Ray class
class Ray:
# Initializer
def __init__(self, origin=Vector3D(0.0, 0.0, 0.0),
direction=Vector3D(0.0, 0.0, 0.0)):
self.o = origin
self.d = direction
# Member Functions
def get_hitpoint(self, t):
return self.o + self.d * t
# -------------------------------------------------RGBColour class
class RGBColour:
# Initializer
def __init__(self, red, green, blue):
self.r = red
self.g = green
self.b = blue
# Operator Overloading
def __add__(self, c):
return RGBColour(self.r + c.r, self.g + c.g, self.b + c.b)
def __sub__(self, c):
return RGBColour(self.r - c.r, self.g - c.g, self.b - c.b)
def __mul__(self, s):
return RGBColour(self.r * s, self.g * s, self.b * s)
def __truediv__(self, s):
return RGBColour(self.r / s, self.g / s, self.b / s)
# this alows us to multipy by another RGBColour
def multiply(self, c):
return RGBColour(self.r * c.r, self.g * c.g, self.b * c.b)
# Member Functions
def clamp(self, minimum, maximum):
# red
if (self.r > maximum): self.r = maximum
if (self.r < minimum): self.r = minimum
# green
if (self.g > maximum): self.g = maximum
if (self.g < minimum): self.g = minimum
# blue
if (self.b > maximum): self.b = maximum
if (self.b < minimum): self.b = minimum
def repr(self):
return "RGBColour ({},{},{})".format(self.r, self.g, self.b)
# Constants
BLACK = RGBColour(0.0, 0.0, 0.0)
WHITE = RGBColour(1.0, 1.0, 1.0)
RED = RGBColour(1.0, 0.0, 0.0)