-
Notifications
You must be signed in to change notification settings - Fork 0
/
common.lua
486 lines (392 loc) · 13.2 KB
/
common.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
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
--require("lldebugger").start()
require('algebra')
s = 50 -- size
polygon_x = { -- x=0
{ z = 0, y = 0, x = 0 },
{ z = 0, y = s, x = 0 },
{ z = s, y = s, x = 0 },
{ z = s, y = 0, x = 0 },
color = { 0, 1, 1 },
}
polygon_x2 = { -- x=s
{ z = s, y = 0, x = s },
{ z = s, y = s, x = s },
{ z = 0, y = s, x = s },
{ z = 0, y = 0, x = s },
color = { 0, 0, 1 }
}
polygon_y = { -- y=0
{ x = 0, z = 0, y = 0 },
{ x = 0, z = s, y = 0 },
{ x = s, z = s, y = 0 },
{ x = s, z = 0, y = 0 },
color = { 1, 1, 1 },
}
polygon_y2 = { -- y=s
{ x = s, z = 0, y = s },
{ x = s, z = s, y = s },
{ x = 0, z = s, y = s },
{ x = 0, z = 0, y = s },
color = { 0, 0, 1 }
}
polygon_z = { -- z=0
{ x = s, y = 0, z = 0 },
{ x = s, y = s, z = 0 },
{ x = 0, y = s, z = 0 },
{ x = 0, y = 0, z = 0 },
color = { 1, 0, 0 }
}
polygon_z2 = { -- z=s
{ x = 0, y = 0, z = s },
{ x = 0, y = s, z = s },
{ x = s, y = s, z = s },
{ x = s, y = 0, z = s },
color = { 1, 1, 0 },
}
polygons_original = {
polygon_x, polygon_x2,
polygon_y, polygon_y2,
polygon_z, polygon_z2,
}
function convert_polygons_to_triangles(polygons_original)
local triangles_original = {}
for _, polygon_iterated in ipairs(polygons_original) do
if #polygon_iterated == 4 then
local triangle1, triangle2
triangle1 = {
color = polygon_iterated.color,
polygon_iterated[1],
polygon_iterated[2],
polygon_iterated[3],
}
triangle2 = {
color = polygon_iterated.color,
polygon_iterated[3],
polygon_iterated[4],
polygon_iterated[1],
}
table.insert(triangles_original, triangle1)
table.insert(triangles_original, triangle2)
end
end
return triangles_original
end
triangles_original = convert_polygons_to_triangles(polygons_original)
--*****************************************
require("loader")
local file_path = "assets/stl-ascii-teapot-axes.stl"
local vertices_bounds
---triangles_original= load_stl_file(file_path)
triangles_original = {}
----print("bounding box", string.format("x %f %f, y %f %f, z %f %f", unpack(vertices_bounds) ) )
---triangles_original= load_obj_file"assets/teapot.obj"
--*****************************************
function point_translate(point, x, y, z)
return {
x = point.x + x,
y = point.y + y,
z = point.z + z
}
end
--[[
function point_rotate(point, radiants)
return {
x = math.cos(radiants)*point.x - math.sin(radiants)*point.y ,
y = math.cos(radiants)*point.y + math.sin(radiants)*point.x }
end --]]
function point_rotate_axes(axes, point_in, radiants)
local point_out = { x = point_in.x, y = point_in.y, z = point_in.z }
local one, two = string.sub(axes, 1, 1), string.sub(axes, 2, 2)
point_out[one] = math.cos(radiants) * point_in[one] - math.sin(radiants) * point_in[two]
point_out[two] = math.cos(radiants) * point_in[two] + math.sin(radiants) * point_in[one]
return point_out
end
function point_rotate_z(point, radiants)
return point_rotate_axes('xy', point, radiants)
end
function point_rotate_y(point, radiants)
return point_rotate_axes('xz', point, radiants)
end
function polygon_transform(polygon, degrees)
local radiants = (degrees / 360) * (math.pi * 2)
local polygon_origin = {}
for i, point in ipairs(polygon) do
table.insert(polygon_origin, point_translate(point,
--[[
-(vertices_bounds[2]-vertices_bounds[1])/2 ,
-(vertices_bounds[4]-vertices_bounds[3])/2 ,
-(vertices_bounds[6]-vertices_bounds[5])/2
--]]
-25, -25, -25
)) -- -25,-25,-25 centering cube 50
end
--[[
local polygon_rotated1={}
for i,point in ipairs(polygon_origin) do
table.insert( polygon_rotated1, point_rotate_z(point, 0 ) ) -- radiants | 0
end
--]]
local polygon_rotated2 = {}
for i, point in ipairs(polygon_origin) do --- polygon_rotated1
table.insert(polygon_rotated2, point_rotate_y(point, radiants)) -- radiants | 0
end
local polygon_rotated_translated = {}
for i, point in ipairs(polygon_rotated2) do
table.insert(polygon_rotated_translated, point_translate(point, 150, 150, -200))
end
local polygon_transformed = polygon_rotated_translated
polygon_transformed.color = polygon.color -- same color
---[[
if polygon[1].normal then
polygon_transformed[1].normal = point_rotate_y(polygon[1].normal, radiants) -- same normal WIP
polygon_transformed[2].normal = point_rotate_y(polygon[2].normal, radiants) -- same normal WIP
polygon_transformed[3].normal = point_rotate_y(polygon[3].normal, radiants) -- same normal WIP
end
--]]
return polygon_transformed
end
degrees = 0.0
local obj_cube = load_obj_file("assets/head.obj")
--obj_cube = {} -- WIP to simplify
function update(dt)
local degrees_increment
degrees_increment = dt * 45
degrees = (degrees + degrees_increment) % 360
local polygons_transformed = {}
function polygons_transform(polygons, degrees)
assert(polygons)
for i, polygon in ipairs(polygons) do
table.insert(polygons_transformed, polygon_transform(polygon, degrees))
end
return polygons_transformed
end
polygons_transformed = polygons_transform(triangles_original, degrees)
---polygons_transformed = triangles_original
polygons_transformed = polygons_transform(obj_cube, (degrees + 180) % 360)
local s = 50
local depth = 10
local polygon_z2 = { -- z=s
{ x = 0, y = 0, z = depth },
{ x = 0, y = s, z = depth },
{ x = s, y = s, z = depth },
{ x = s, y = 0, z = depth },
color = { 1, 1, 0 },
}
local polygons_transformed_addon
polygons_transformed_addon = {
polygon_z2, -- WIP TODO turno off this debug helper, comment-out this line
}
polygons_transformed_addon = convert_polygons_to_triangles(
polygons_transformed_addon)
-- polygons_transformed_addon = convert_polygons_to_triangles( { polygon_z2 } )
local polygons_accumulator = polygons_transformed
for i, polygon in ipairs(polygons_transformed_addon) do
table.insert(polygons_accumulator, polygon)
end
polygons_to_render = polygons_accumulator
end
function shading(polygon_iterated)
--[[
if not polygon_iterated.normal then -- caching
polygon_iterated.normal = polygon_normal(polygon_iterated)
end
--]]
local normal_vector = polygon_normal(polygon_iterated) -- not cached
--[[
function polygon_iterated.depth(px, py)
if not polygon_iterated.normal then -- caching, it's cached
polygon_iterated.normal = polygon_normal(polygon_iterated)
end
local x,y,z,x1,y1,z1,a,b,c
local normal_vector = polygon_iterated.normal -- cached
x=px
y=py
x1=polygon_iterated[1].x
y1=polygon_iterated[1].y
z1=polygon_iterated[1].z
a=normal_vector.x
b=normal_vector.y
c=normal_vector.z
z = -(a*x +b*y -(a*x1 +b*y1 +c*z1) )/c
return z
end
--]]
--[[
shaded_color=color*(dot(facing_direction,light_direction))
i.e. face_color scaled to cos_angle obtained as
vector dot product of face_normal and to_light vectors
--]]
if not polygon_iterated.color_diffuse then
local color = polygon_iterated.color or { 1, 1, 0 } -- default if missing
local face_normal = normal_vector -- not cached
local to_light = vunit({ x = -1, y = -1, z = -1 })
local cos_angle = vdot(face_normal, to_light)
cos_angle = unit_clamp(cos_angle)
color = scale3(cos_angle, color)
local ambient_light_intensity = 0.2
local ambient_light_color = {
ambient_light_intensity,
ambient_light_intensity,
ambient_light_intensity }
color = sum3(color, ambient_light_color)
color = clamp3(color)
polygon_iterated.color_diffuse = color
end
end
--[[
function perspective(polygon_iterated)
local vanishing_point = { x = render_width / 2, y = render_height / 2 }
for i, vertex in ipairs(polygon_iterated) do
local z_scaling = (-vertex.z + 100) / 100
vertex.x = (vertex.x - vanishing_point.x) / z_scaling + vanishing_point.x
vertex.y = (vertex.y - vanishing_point.y) / z_scaling + vanishing_point.y
end
end
--]]
function vertex_color_from_vertex_normal(triangle, vertex, color, to_light, ambient_light_color)
local normal
if vertex.normal then
normal = vertex.normal
else
normal = polygon_normal(triangle)
end
local cos_angle = vdot(normal, to_light)
cos_angle = unit_clamp(cos_angle)
color = scale3(cos_angle, color)
color = sum3(color, ambient_light_color)
color = clamp3(color)
vertex.color = color
end
function shading_smooth_preset1(triangle)
local ambient_light_intensity = 0.2
local ambient_light_color = {
ambient_light_intensity,
ambient_light_intensity,
ambient_light_intensity }
local color = { 1, 0.5, 0.5 } -- 0,1,1
local to_light = vunit({ x = -1, y = -1, z = -1 })
vertex_color_from_vertex_normal(triangle, triangle[1], color, to_light, ambient_light_color)
vertex_color_from_vertex_normal(triangle, triangle[2], color, to_light, ambient_light_color)
vertex_color_from_vertex_normal(triangle, triangle[3], color, to_light, ambient_light_color)
end
function draw()
local render_width, render_height = 300, 300
for i, polygon_iterated in ipairs(polygons_to_render) do
shading_smooth_preset1(polygon_iterated)
end
for i, polygon_iterated in ipairs(polygons_to_render) do
---perspective(polygon_iterated) -- WIP improve
end
-- z-buffer
local depth_buffer = {}
for py = 0, render_height do
local line = {}
for px = 0, render_width do
table.insert(line, px, math.huge) -- reset value
end
table.insert(depth_buffer, py, line)
end
--[[
-- pixels
for py=0,render_height do
for px=0,render_width do
for i,polygon_iterated in ipairs(polygons_to_render) do
local check = false
check = in_convex_polygon(px, py, polygon_iterated)
--]]
function inside_polygon(polygon, point)
local last = polygon[#polygon]
for i = 1, #polygon do
local current = polygon[i]
--[[
if side(point, last, current) > 0 then
return false
end
--]]
function halfplane(px, p1, p2)
return ((p2.x - p1.x) * (px.y - p1.y) - (p2.y - p1.y) * (px.x - p1.x)) > 0
end
if halfplane(point, last, current) then
return false
end
last = current
end
return true
end
-- testing: function color_interpolate(point, polygon)
--polygons_to_render = {}
--[[
table.insert(polygons_to_render,
{
{x=300, y=10, z=10, color={1,1,0}},
{x=10, y=10, z=10, color={1,0,0}},
{x=10, y=300,z=10, color={0,1,0}},
}
)
--]]
for i, polygon_iterated in ipairs(polygons_to_render) do
local x_min = math.huge
local x_max = -math.huge
local y_min = math.huge
local y_max = -math.huge
for i, point in ipairs(polygon_iterated) do
if point.x < x_min then x_min = point.x end
if point.x > x_max then x_max = point.x end
if point.y < y_min then y_min = point.y end
if point.y > y_max then y_max = point.y end
end
x_min = math.max(x_min, 0)
x_max = math.min(x_max, render_width)
y_min = math.max(y_min, 0)
y_max = math.min(y_max, render_height)
x_min = math.floor(x_min)
x_max = math.floor(x_max)
y_min = math.floor(y_min)
y_max = math.floor(y_max)
local pre_baryc_coords = barycentric_coords_precalculated_for_polygon(polygon_iterated)
for py = y_min, y_max do
for px = x_min, x_max do
local point = { x = px, y = py }
local polygon = polygon_iterated
local function check_polygon()
return inside_polygon(polygon, point)
end
local function check_wireframe()
local ra, rb, rc = barycentric_coordinates(point, polygon)
function quasi_zero(number) return math.abs(number) <= 0.05 end
return quasi_zero(ra) or quasi_zero(rb) or quasi_zero(rc)
end
if check_polygon() then
local rgb = polygon_iterated.color_diffuse
local function depth(px, py, polygon_iterated)
if not polygon_iterated.normal then -- caching, it's cached
polygon_iterated.normal = polygon_normal(polygon_iterated)
end
local x, y, z, x1, y1, z1, a, b, c
local normal_vector = polygon_iterated.normal -- cached
x = px
y = py
x1 = polygon_iterated[1].x
y1 = polygon_iterated[1].y
z1 = polygon_iterated[1].z
a = normal_vector.x
b = normal_vector.y
c = normal_vector.z
z = -(a * x + b * y - (a * x1 + b * y1 + c * z1)) / c
return z
end
local point = { x = px, y = py }
---local z = depth(px,py, polygon_iterated) -- NOT precalc
local z = position_interpolate_precalc(point, polygon, pre_baryc_coords).z
local current_depth = depth_buffer[py][px]
if z < current_depth then
---if not rgb then rgb = color_interpolate({x=px, y=py}, polygon_iterated) end -- NOT precalc
if not rgb then rgb = color_interpolate_precalc(point, polygon, pre_baryc_coords) end
draw_pixel(rgb, { px, (render_height - 1) - py }) -- mirrored y axis
depth_buffer[py][px] = z -- successive depth
end
end
end
end
end
end