Last active
June 16, 2020 14:24
-
-
Save mutoo/858df40c7ff0f9576158f685fb1bf260 to your computer and use it in GitHub Desktop.
draw random triangles in aseprite
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local image = app.activeCel.image:clone() | |
local black = Color { r = 0, g = 0, b = 0, a = 255 } | |
local white = Color { r = 255, g = 255, b = 255, a = 255 } | |
local width = image.width | |
local height = image.height | |
local size = width * height | |
local nearest = 0.1 | |
local farest = 1000 | |
function area(p0, p1, p) | |
return (p1[1] - p0[1]) * (p[2] - p0[2]) - (p1[2] - p0[2]) * (p[1] - p0[1]) | |
end | |
function createBuffer(size, fill) | |
local buffer = {} | |
for i = 0, size - 1 do | |
buffer[i] = fill | |
end | |
return buffer | |
end | |
local frameBuffer = createBuffer(size, nil) | |
local zBuffer = createBuffer(size, farest) | |
local camera = { 0, 0, 3 } | |
function getBoundingBox(p0, p1, p2) | |
local t, r, b, l | |
t = math.floor(math.max(0, math.min(p0[2], p1[2], p2[2]))) | |
r = math.floor(math.min(math.max(p0[1], p1[1], p2[1]), width - 1)) | |
b = math.floor(math.min(math.max(p0[2], p1[2], p2[2]), height - 1)) | |
l = math.floor(math.max(0, math.min(p0[1], p1[1], p2[1]))) | |
return { t, r, b, l } | |
end | |
function worldToCamera(p) | |
local x = p[1] - camera[1] | |
local y = p[2] - camera[2] | |
local z = p[3] - camera[3] | |
return { x, y, z } | |
end | |
function cameraToScreen(p) | |
local x = nearest * p[1] / -p[3] | |
local y = nearest * p[2] / -p[3] | |
local z = -p[3] | |
return { x, y, z } | |
end | |
local t = 2 | |
local l = -2 | |
local b = -2 | |
local r = 2 | |
function screenToNDC(p) | |
local x = 2 * p[1] / (r - l) - (r + l) / (r - l); | |
local y = 2 * p[2] / (t - b) - (t + b) / (t - b); | |
return { x, y } | |
end | |
function NDCToCanvas(p) | |
local x = (p[1] + 1) / 2 * width | |
local y = (p[2] + 1) / 2 * height | |
local z = p[3] | |
return { x, y, z } | |
end | |
local triangles = {} | |
for i = 1, 1000 do | |
local p0 = { math.random(-50, 50), math.random(-50, 50), -math.random(1, 10) } | |
local p1 = { math.random(-50, 50), math.random(-50, 50), -math.random(1, 10) } | |
local p2 = { math.random(-50, 50), math.random(-50, 50), -math.random(1, 10) } | |
table.insert(triangles, { p0, p1, p2 }) | |
end | |
function drawPoint(buffer, p, c) | |
local x = math.floor(p[1]) | |
local y = math.floor(p[2]) | |
buffer[x + y * width] = c | |
end | |
for _, triangle in ipairs(triangles) do | |
local t0, t1, t2 = table.unpack(triangle) | |
local p0 = NDCToCanvas(screenToNDC(cameraToScreen(worldToCamera(t0)))) | |
local p1 = NDCToCanvas(screenToNDC(cameraToScreen(worldToCamera(t1)))) | |
local p2 = NDCToCanvas(screenToNDC(cameraToScreen(worldToCamera(t2)))) | |
-- local p0, p1, p2 = table.unpack(triangle) | |
local w = area(p0, p1, p2) | |
if w >= 0 then | |
local bbox = getBoundingBox(p0, p1, p2) | |
local c = Color { r = math.random(0, 255), g = math.random(0, 255), b = math.random(0, 255), a = 255 } | |
-- drawPoint(frameBuffer, p0, c) | |
-- drawPoint(frameBuffer, p1, c) | |
-- drawPoint(frameBuffer, p2, c) | |
for row = bbox[1], bbox[3] do | |
for col = bbox[4], bbox[2] do | |
local p = { col, row } | |
local w0 = area(p0, p1, p) | |
local w1 = area(p1, p2, p) | |
local w2 = area(p2, p0, p) | |
if w0 >= 0 and w1 >= 0 and w2 >= 0 then | |
local oneOverZ = p0[2] * w0 + p1[2] * w1 + p2[2] * w2; | |
local z = 1 / oneOverZ | |
local idx = row * image.width + col | |
if z < zBuffer[idx] then | |
zBuffer[idx] = z | |
frameBuffer[idx] = c.rgbaPixel | |
end | |
end | |
end | |
end | |
end | |
end | |
for it in image:pixels() do | |
local c = it() | |
it(frameBuffer[it.y * image.width + it.x] or black.rgbaPixel) | |
end | |
app.activeCel.image = image | |
app.refresh() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the very basic bounding-box triangle rasterization algorithm from:
https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/overview-rasterization-algorithm