-
Notifications
You must be signed in to change notification settings - Fork 0
/
algebra.lua
184 lines (149 loc) · 5.37 KB
/
algebra.lua
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
function clamp_generic(n, low, high) return math.min(math.max(n, low), high) end
function unit_clamp(n) return clamp_generic(n, 0, 1) end
-- vector algebra
string_indices_point = { 'x', 'y', 'z' }
zero3 = { x = 0, y = 0, z = 0 }
function voperation(v1, v2, op, string_indices_option) -- abstract vector operation (then specialized)
local string_indices
if not string_indices_option then
string_indices = string_indices_point
else
string_indices = string_indices_option
end
local result = {}
for index = 1, #string_indices do
local string_index = string_indices[index]
local n = op(v1[string_index], v2[string_index])
result[string_index] = n
end
return result
end
function vadd(v1, v2) -- addition (sum)
return voperation(v1, v2, function(a, b) return a + b end)
end
function vsubtract(v1, v2) -- subtraction (difference)
return voperation(v1, v2, function(a, b) return a - b end)
end
function vminus(v1) -- apply minus (-v1)
return vsubtract(zero3, v1)
end
function vscale(scalar, v1) -- multiply (scale)
return voperation(zero3, v1, function(_, b) return scalar * b end)
end
function vdivide(v1, scalar) -- divide
return voperation(v1, zero3, function(a, _) return a / scalar end)
end
function vmagnitude(v1) -- magnitude (length) of the vector
return math.sqrt(v1.x * v1.x + v1.y * v1.y + v1.z * v1.z)
end
function vunit(v1) -- set unit magnitude (vector normalization)
return vdivide(v1, vmagnitude(v1))
end
function vcross(v1, v2) -- vector cross product
return {
x = v1.y * v2.z - v1.z * v2.y,
y = v1.z * v2.x - v1.x * v2.z,
z = v1.x * v2.y - v1.y * v2.x
}
end
function vdot(v1, v2) -- vector dot product
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
end
function vstringify(v) -- xyz vector to string
return "(" .. v.x .. "," .. v.y .. "," .. v.z .. ")"
end
-- function color_scale
function scale3(scalar, vec3)
return { vec3[1] * scalar, vec3[2] * scalar, vec3[3] * scalar }
end
function sum3(vec3_a, vec3_b)
return { vec3_a[1] + vec3_b[1], vec3_a[2] + vec3_b[2], vec3_a[3] + vec3_b[3] }
end
function clamp3(vec3)
return { unit_clamp(vec3[1]), unit_clamp(vec3[2]), unit_clamp(vec3[3]) }
end
--[[
string_indices_color = {'r','g','b'}
color_zero={r=0,g=0,b=0}
function color_scale(scalar,color) -- multiply (scale)
return voperation(color_zero,color,function(_,b_color_component) return scalar*b_color_component end, string_indices_color)
end
--]]
-- *********************************
function polygon_normal(polygon)
local v1 = vsubtract(polygon[2], polygon[1])
local v2 = vsubtract(polygon[3], polygon[1])
local normal = vcross(v1, v2)
return vunit(normal)
end
function barycentric_coordinates(point, polygon)
local a = polygon[1]
local b = polygon[2]
local c = polygon[3]
local ra = ((b.y - c.y) * (point.x - c.x) + (c.x - b.x) * (point.y - c.y)) / ((b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y))
local rb = ((c.y - a.y) * (point.x - c.x) + (a.x - c.x) * (point.y - c.y)) / ((b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y))
local rc = 1 - ra - rb
return ra, rb, rc
end
function color_interpolate(point, polygon)
local ra, rb, rc = barycentric_coordinates(point, polygon)
local a = polygon[1]
local b = polygon[2]
local c = polygon[3]
return sum3(scale3(ra, a.color), sum3(scale3(rb, b.color), scale3(rc, c.color)))
end
-- with pre-calculation per-polygon
function barycentric_coords_precalculated_for_polygon(polygon)
local a = polygon[1]
local b = polygon[2]
local c = polygon[3]
local pre_baryc_coords = {}
pre_baryc_coords.common = (b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y)
pre_baryc_coords.ax = b.y - c.y
pre_baryc_coords.ay = c.x - b.x
pre_baryc_coords.bx = c.y - a.y
pre_baryc_coords.by = a.x - c.x
pre_baryc_coords.cx = c.x
pre_baryc_coords.cy = c.y
return pre_baryc_coords
end
function barycentric_coordinates_cache_by_polygon(point, pre)
local ra = (pre.ax * (point.x - pre.cx) + pre.ay * (point.y - pre.cy)) / pre.common
local rb = (pre.bx * (point.x - pre.cx) + pre.by * (point.y - pre.cy)) / pre.common
local rc = 1 - ra - rb
return { ra = ra, rb = rb, rc = rc }
end
function color_interpolate_precalc(point, polygon, pre)
local coords = barycentric_coordinates_cache_by_polygon(point, pre)
local ra, rb, rc = coords.ra, coords.rb, coords.rc
local a = polygon[1]
local b = polygon[2]
local c = polygon[3]
return sum3(scale3(ra, a.color), sum3(scale3(rb, b.color), scale3(rc, c.color))) -- ra*a + rb*b + rc*c
end
function position_interpolate_precalc(point, polygon, pre)
local coords = barycentric_coordinates_cache_by_polygon(point, pre)
local ra, rb, rc = coords.ra, coords.rb, coords.rc
local a = polygon[1]
local b = polygon[2]
local c = polygon[3]
return vadd(vscale(ra, a), vadd(vscale(rb, b), vscale(rc, c))) -- ra*a + rb*b + rc*c
end
-- *********************************
function algebra_module_test()
local cross = vcross({ x = 1, y = 0, z = 0 }, { x = 0, y = 1, z = 0 }) -- (0,0,1)
print(vstringify(cross))
local result1 = vscale(2, vminus(cross))
local result2 = vadd(result1, cross) -- (0,0,-1)
print(vstringify(result2))
local polygon_reference = {
{ x = 0, y = 0, z = 0 }, { x = 0, y = 50, z = 0 }, { x = 50, y = 0, z = 0 },
}
local normal = polygon_normal(polygon_reference)
print(vstringify(normal)) -- (0,0,-1)
end
if not ... then
algebra_module_test()
else
print('algebra_module_test skipped')
end