Advertisement
9551

3D testing V?

Oct 24th, 2021
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.25 KB | None | 0 0
  1. local function makeProjection(w,h,n,f)
  2.     --w = width
  3.     --h = height
  4.     --n = near plane
  5.     --f = far plane
  6.     return {
  7.         {2*n/w,0,0,0},
  8.         {0,2*n/h, 0,0},
  9.         {0,0,f/(f-n),-n*f/(f-n)},
  10.         {0,0,-1,0}
  11.     }
  12. end
  13. local makeIdentity = function()
  14.     return {
  15.         {1,0,0,0},
  16.         {0,1,0,0},
  17.         {0,0,1,0},
  18.         {0,0,0,1}
  19.     }
  20. end
  21. local makeTranslation = function(cords)
  22.     return {
  23.         {1,0,0,cords.x},
  24.         {0,1,0,cords.y},
  25.         {0,0,1,cords.z},
  26.         {0,0,0,1}
  27.     }
  28. end
  29. local function makeScale(scale)
  30.     return
  31.     {
  32.         {scale.x, 0, 0, 0},
  33.         {0, scale.y, 0, 0},
  34.         {0, 0, scale.z, 0},
  35.         {0, 0, 0, 1}
  36.     }        
  37. end
  38. local function makeRotation(eulers)
  39.     local x = math.rad(eulers.x)
  40.     local y = math.rad(eulers.y)
  41.     local z = math.rad(eulers.z)
  42.     local sx = math.sin(x)
  43.     local sy = math.sin(y)
  44.     local sz = math.sin(z)
  45.    
  46.     local cx = math.cos(x)
  47.     local cy = math.cos(y)
  48.     local cz = math.cos(z)
  49.     return
  50.     {
  51.         {cy * cz, -cy * sz, sy, 0},
  52.         {(sx * sy * cz) + (cx * sz), (-sx * sy * sz) + (cx * cz), -sx * cy, 0},
  53.         {(-cx * sy * cz) + (sx * sz), (cx * sy * sz) + (sx * cz), cx * cy, 0},
  54.         {0, 0, 0, 1,}
  55.     }
  56. end
  57. local function makePerspective(width, height, n, f, fov)
  58.     local aspectRatio = 3/2*height / width  
  59.     --local aspectRatio = height / width  
  60.     fov = math.rad(fov)
  61.     return
  62.     {
  63.         {aspectRatio/math.tan(fov*0.5),0,0,0},
  64.         {0,1/(math.tan(fov*0.5)),0,0},
  65.         {0,0,-f/(f-n),-f*n/(f-n)},
  66.         {0,0,-1,0}
  67.     },width,height
  68. end
  69. local function matmul(m1, m2)
  70.     if #m1[1] ~= #m2 then
  71.         error("Columns m1 must match rows m2",2)
  72.     end
  73.     local result = {}
  74.     for i = 1, #m1 do
  75.         result[i] = {}
  76.         for j = 1, #m2[1] do
  77.             local sum = 0
  78.             for k = 1, #m2 do sum = sum + (m1[i][k] * m2[k][j]) end
  79.             result[i][j] = sum
  80.         end
  81.     end
  82.     return result
  83. end
  84. local function drawLine(startX, startY, endX, endY, color)
  85.     local sc = term.getBackgroundColor()
  86.     term.setBackgroundColor(color)
  87.     local drawPixelInternal = function(x,y) term.setCursorPos(x,y) term.write(" ") end
  88.     local startX,startY,endX,endY = math.floor(startX),math.floor(startY),math.floor(endX),math.floor(endY)
  89.     if startX == endX and startY == endY then drawPixelInternal(startX, startY) term.setBackgroundColor(sc) return end
  90.     local minX = math.min(startX, endX)
  91.     local maxX, minY, maxY
  92.     if minX == startX then minY = startY maxX = endX maxY = endY
  93.     else minY = endY maxX = startX maxY = startY end
  94.     local xDiff,yDiff = maxX - minX,maxY - minY
  95.     if xDiff > math.abs(yDiff) then
  96.         local y,dy = minY,yDiff / xDiff
  97.         for x = minX, maxX do drawPixelInternal(x, math.floor(y+0.5)) y = y + dy end
  98.     else
  99.         local x,dx = minX,xDiff / yDiff
  100.         if maxY >= minY then for y = minY, maxY do drawPixelInternal(math.floor(x ), y) x = x + dx end
  101.         else for y = minY, maxY, -1 do drawPixelInternal(math.floor(x+0.5), y) x = x - dx end end
  102.     end
  103.     term.setBackgroundColor(sc)
  104. end
  105. local function drawFlatTriangle(peripheralWrapper,px1,px2,y,color)
  106.     local xStart = math.ceil(px1 - 0.5)
  107.     local xEnd =   math.ceil(px2 - 0.5)
  108.     for x = xStart, xEnd do
  109.         if y > 0 and x > 0 then
  110.             peripheralWrapper.setCursorPos(x,y)
  111.             peripheralWrapper.setBackgroundColor(color)
  112.             peripheralWrapper.write(" ")
  113.         end
  114.     end
  115. end
  116. local function drawFlatTopTriangle( peripheralWrapper,vec1,vec2,vec3,color)
  117.     local m1 = (vec3.x - vec1.x) / (vec3.y - vec1.y)
  118.     local m2 = (vec3.x - vec2.x) / (vec3.y - vec2.y)
  119.     local yStart = math.ceil(vec1.y - 0.5)
  120.     local yEnd =   math.ceil(vec3.y - 0.5)-1
  121.     for y = yStart, yEnd do
  122.         local px1 = m1 * (y + 0.5 - vec1.y) + vec1.x
  123.         local px2 = m2 * (y + 0.5 - vec2.y) + vec2.x
  124.         drawFlatTriangle( peripheralWrapper,px1,px2,y,color)
  125.     end
  126. end
  127. local function drawFlatBottomTriangle( peripheralWrapper,vec1,vec2,vec3,color)
  128.     local m1 = (vec2.x - vec1.x) / (vec2.y - vec1.y)
  129.     local m2 = (vec3.x - vec1.x) / (vec3.y - vec1.y)
  130.     local yStart = math.ceil(vec1.y-0.5)
  131.     local yEnd =   math.ceil(vec3.y-0.5)-1
  132.     for y = yStart, yEnd do
  133.         local px1 = m1 * (y + 0.5 - vec1.y) + vec1.x
  134.         local px2 = m2 * (y + 0.5 - vec1.y) + vec1.x
  135.         drawFlatTriangle( peripheralWrapper,px1,px2,y,color)
  136.     end
  137. end
  138. local function drawSolidTriangle( peripheralWrapper,vec1,vec2,vec3,color)
  139.     local pv1 = vec1
  140.     local pv2 = vec2
  141.     local pv3 = vec3
  142.     if pv2.y < pv1.y then pv1,pv2 = pv2,pv1 end
  143.     if pv3.y < pv2.y then pv2,pv3 = pv3,pv2 end
  144.     if pv2.y < pv1.y then pv1,pv2 = pv2,pv1 end
  145.     if pv1.y == pv2.y then
  146.         if pv2.x < pv1.x then pv1,pv2 = pv2,pv1 end
  147.         drawFlatTopTriangle(peripheralWrapper,pv1,pv2,pv3,color)
  148.     elseif pv2.y == pv3.y then
  149.         if pv3.x < pv2.x then pv3,pv2 = pv2,pv3 end
  150.         drawFlatBottomTriangle(peripheralWrapper,pv1,pv2,pv3,color)
  151.     else
  152.         local alphaSplit = (pv2.y-pv1.y)/(pv3.y-pv1.y)
  153.         local vi ={
  154.             x = pv1.x + ((pv3.x - pv1.x) * alphaSplit),      
  155.             y = pv1.y + ((pv3.y - pv1.y) * alphaSplit), }
  156.         if pv2.x < vi.x then
  157.             drawFlatBottomTriangle(peripheralWrapper,pv1,pv2,vi,color)
  158.             drawFlatTopTriangle(peripheralWrapper,pv2,vi,pv3,color)
  159.         else
  160.             drawFlatBottomTriangle(peripheralWrapper,pv1,vi,pv2,color)
  161.             drawFlatTopTriangle(peripheralWrapper,vi,pv2,pv3,color)
  162.         end
  163.     end
  164. end
  165. local function createColor(whitelist,blacklist)
  166.     local cols,clist,cCount = {},{},0
  167.     local acls = whitelist or {}
  168.     local useall = not whitelist
  169.     local bcls = blacklist or {}
  170.     local clist = {}
  171.     for k,v in pairs(colors) do
  172.         if type(v) == "number" and useall or acls[v] and not bcls[v] then
  173.             table.insert(clist,v)
  174.         end
  175.     end
  176.     return setmetatable({},{
  177.         __index=function(t,k)
  178.             cCount = cCount + 1
  179.             local col = clist[cCount]
  180.             if cCount >= #clist then cCount = 0 end
  181.             t[k]=col
  182.             return col
  183.         end
  184.     })
  185. end
  186. --[[local function createColor(clist)
  187.     local clist = clist or {}
  188.     local cCount = 0
  189.     return setmetatable({},{
  190.         __index=function(t,k)
  191.             cCount = cCount + 1
  192.             local col = clist[cCount]
  193.             if cCount >= #clist then cCount = 0 end
  194.             t[k]=col
  195.             return col
  196.         end
  197.     })
  198. end]]
  199. local function createPerspective(width,height,FOV)
  200.     return {makePerspective(width,height,100,10,FOV)}
  201. end
  202. local function createCamera(locVector,rotVector)
  203.     return {
  204.         loc=makeTranslation(-locVector),
  205.         rot=makeRotation(-rotVector)
  206.     }
  207. end
  208. local function getDrawArgs()
  209.     return {
  210.         doCulling = true,
  211.         drawWireFrame = false,
  212.         drawTriangles = true
  213.     }
  214. end
  215. local function interpolate(p1,p2,y)
  216.     return (((y-p1.y)*(p2.x-p1.x)) / (p2.y-p1.y) + p1.x)
  217. end
  218. local function clip1(v1,v2,v3)
  219.     local alphaA = (-v1.z)/(v2.z-v1.pos.z)
  220.     local alphaB = (-v1.z)/(v2.z-v1.pos.z)
  221.     local v1a = interpolate(v1,v2,alphaA)
  222.     local v1b = interpolate(v1,v3,alphaB)
  223.     return {{v1a,v1,v2},{v1b,v1a,v2}}
  224. end
  225. local function clip2(v1,v2,v3)
  226.     local alpha1 = (-v1.z)/(v3.z-v1.z)
  227.     local alpha2 = (-v2.z)/(v3.z-v2.z)
  228.     local v1 = interpolate(v1,v3,alpha1)
  229.     local v2 = interpolate(v2,v3,alpha2)
  230.     return {{v1,v2,v3}}
  231. end
  232. local function clipCullTriangle(v1,v2,v3)
  233.     if v1.x > v1.w and v2.x > v2.w and v3.x > v3.w then return false
  234.     elseif v1.x > -v1.w and v2.x > -v2.w and v3.x > -v3.w then return false
  235.     elseif v1.y > v1.w and v2.y > v2.w and v3.y > v3.w then return false
  236.     elseif v1.y > -v1.w and v2.y > -v2.w and v3.y > -v3.w then return false
  237.     elseif v1.z > v1.w and v2.z > v2.w and v3.z > v3.w then return false
  238.     elseif v1.z > -v1.w and v2.z > -v2.w and v3.z > -v3.w then return false end
  239.     return v1,v2,v3
  240. end
  241. local function transform(objList,persperctive,camera)
  242.     local objectsInt = setmetatable({},
  243.         {
  244.             __index=function(t,k)
  245.                 local new = {}
  246.                 t[k]=new
  247.                 return new
  248.             end
  249.         }
  250.     )
  251.     for k,v in pairs(objList) do
  252.         objectsInt[k] = {main=v,vectors={},origins={},connections=v.connections}
  253.         local scale = makeScale(v.scale/(v.divider or 1))
  254.         local rot = makeRotation(v.rot)
  255.         local loc = makeTranslation(v.loc)
  256.         local tempObj = {}
  257.         for k1,v1 in pairs(v.vertices) do
  258.             local model = matmul(loc, matmul(rot, matmul(scale, v1)))
  259.             local cam = matmul(camera.rot, matmul(camera.loc, model))
  260.             local projected = matmul(persperctive[1],cam)
  261.             table.insert(tempObj,projected)
  262.         end
  263.         for kc,vc in ipairs(v.connections) do
  264.             local v1 = vector.new(tempObj[vc[1]][1][1],tempObj[vc[1]][2][1],tempObj[vc[1]][3][1])
  265.             local v2 = vector.new(tempObj[vc[2]][1][1],tempObj[vc[2]][2][1],tempObj[vc[2]][3][1])
  266.             local v3 = vector.new(tempObj[vc[3]][1][1],tempObj[vc[3]][2][1],tempObj[vc[3]][3][1])
  267.             v1.w,v2.w,v3.w = tempObj[vc[1]][4][1],tempObj[vc[2]][4][1],tempObj[vc[3]][4][1]
  268.             if clipCullTriangle(v1,v2,v3) then
  269.                 if v1.z < 0 then
  270.                     if v2.z < 0 then something[something] = clip2(v1,v2,v3)
  271.                     elseif v3.z < 0 then something[something] = clip2(v1,v3,v2)
  272.                     else something[something] = clip1(v1,v2,v3) end
  273.                 elseif v2.z < 0 then
  274.                     if v3.z < 0 then something[something] = clip2(v2,v3,v1)
  275.                     else something[something] = clip1(v2,v1,v3) end
  276.                 elseif v3.z < 0 then
  277.                     something[something] = clip2(v3,v1,v2)
  278.                 end
  279.             end
  280.         end
  281.         for k2,v2 in pairs(tempObj) do
  282.             local projected = v2
  283.             local w = 1/projected[4][1]
  284.             projected[1][1] = (projected[1][1] * w  +1) * (persperctive[2] / 2)
  285.             projected[2][1] = (-projected[2][1] * w +1) * (persperctive[3] / 2)
  286.             table.insert(objectsInt[k].vectors,projected)
  287.             table.insert(objectsInt[k].origins,v2)
  288.         end
  289.     end
  290.     return objectsInt
  291. end
  292. local function drawTransformed(termObj,objects,arguments)
  293.     local term = termObj or term
  294.     if not arguments then
  295.         arguments = {
  296.             doCulling = true,
  297.             drawWireFrame = false,
  298.             drawTriangles = true
  299.         }
  300.     end
  301.     for k,vm in pairs(objects) do
  302.         for k,v in pairs(vm.connections) do
  303.             local v1 = vector.new(vm.origins[v[1]][1][1],vm.origins[v[1]][2][1],vm.origins[v[1]][3][1])
  304.             local v2 = vector.new(vm.origins[v[2]][1][1],vm.origins[v[2]][2][1],vm.origins[v[2]][3][1])
  305.             local v3 = vector.new(vm.origins[v[3]][1][1],vm.origins[v[3]][2][1],vm.origins[v[3]][3][1])
  306.             if ((v2:cross(v3)):dot(v1) >= 0) or not arguments.doCulling then
  307.                 if arguments.drawTriangles then
  308.                     drawSolidTriangle(termObj,v1,v2,v3,vm.main.color[k])
  309.                     --termObj.addTriangle({v1.x,v1.y},{v2.x,v2.y},{v3.x,v3.y},vm.main.color[k])
  310.                 end
  311.                 if arguments.drawWireFrame then
  312.                     drawLine(vm.vectors[v[1]][1][1],vm.vectors[v[1]][2][1],vm.vectors[v[2]][1][1],vm.vectors[v[2]][2][1],vm.main.color[k])
  313.                     drawLine(vm.vectors[v[2]][1][1],vm.vectors[v[2]][2][1],vm.vectors[v[3]][1][1],vm.vectors[v[3]][2][1],vm.main.color[k])
  314.                     drawLine(vm.vectors[v[3]][1][1],vm.vectors[v[3]][2][1],vm.vectors[v[1]][1][1],vm.vectors[v[1]][2][1],vm.main.color[k])
  315.                 end
  316.             end
  317.         end
  318.         term.setBackgroundColor(colors.black)
  319.     end
  320. end
  321. local function newSquare()
  322.     local objData = {
  323.         scale = vector.new(1,1,1),
  324.         loc = vector.new(0,0,0),
  325.         rot = vector.new(0,0,0),
  326.         color = createColor(),
  327.         indexList = {1},
  328.         vertices = {
  329.             {{-0.5}, {-0.5}, {0}, {1}},
  330.             {{0.5}, {-0.5}, {0}, {1}},
  331.             {{-0.5},  {0.5}, {0}, {1}},
  332.             {{0.5},  {0.5}, {0}, {1}},
  333.         },
  334.         connections = {
  335.             {3,2,1},
  336.             {2,4,3},
  337.             {1,2,3},
  338.             {3,4,2},
  339.         }
  340.     }
  341.     for i,val in ipairs(objData.indexList) do
  342.         objData.indexList[i] = val*4-3
  343.     end
  344.     return objData
  345. end
  346. local function newCube()
  347.     local objData = {
  348.         scale = vector.new(1,1,1),
  349.         loc = vector.new(0,0,0),
  350.         rot = vector.new(0,0,0),
  351.         color = createColor(),
  352.         indexList = {1},
  353.         vertices = {
  354.             { { -0.5}, { -0.5}, {0.5}, {1} },  
  355.             { {0.5}, { -0.5}, {0.5}, {1} },
  356.             { { -0.5}, {0.5}, {0.5}, {1} },
  357.             { {0.5}, {0.5}, {0.5}, {1} },
  358.             { { -0.5}, { -0.5}, { -0.5}, {1}},
  359.             { {0.5}, { -0.5}, { -0.5}, {1}},
  360.             { { -0.5}, {0.5}, { -0.5}, {1}},
  361.             { {0.5}, {0.5}, { -0.5}, {1}}
  362.         },
  363.         connections = {{ 1,3,4 },{ 1,4,2 },{ 5,7,3 },{ 5,3,1 },{ 6,8,7 },{ 6,7,5 },{ 2,4,8 },{ 2,8,6 },{ 3,7,8 },{ 3,8,4 },{ 5,1,2 },{ 5,2,6 }}
  364.     }
  365.     for i,val in ipairs(objData.indexList) do
  366.         objData.indexList[i] = val*4-3
  367.     end
  368.     return objData
  369. end
  370. local function newPyramid()
  371.     local objData = {
  372.         scale = vector.new(1,1,1),
  373.         loc = vector.new(0,0,0),
  374.         rot = vector.new(0,0,0),
  375.         color = createColor(),
  376.         indexList = {1},
  377.         vertices = {
  378.             {{-0.5}, {-0.5}, {-0.5}, {1}},
  379.             {{0.5}, {-0.5}, {-0.5}, {1}},
  380.             {{-0.5}, {-0.5}, {0.5}, {1}},
  381.             {{0.5}, {-0.5}, {0.5}, {1}},
  382.             {{0}, {0.5}, {0}, {1}}
  383.         },
  384.         connections = {{3,2,1},{3,4,2},{2,5,1},{3,5,4},{4,5,2},{1,5,3}}
  385.     }
  386.     for i,val in ipairs(objData.indexList) do
  387.         objData.indexList[i] = val*4-3
  388.     end
  389.     return objData
  390. end
  391. local function newIcosahedron()
  392.     local objData = {
  393.         scale = vector.new(1,1,1),
  394.         loc = vector.new(0,0,0),
  395.         rot = vector.new(0,0,0),
  396.         color = createColor(),
  397.         indexList = {1},
  398.         divider = 30,
  399.         vertices = {
  400.             {{0},{30},{0},{1}},
  401.             {{26},{15},{0},{1}},
  402.             {{8},{15},{25},{1}},
  403.             {{-21},{15},{15},{1}},
  404.             {{-21},{15},{-15},{1}},
  405.             {{8},{15},{-25},{1}},
  406.             {{21},{-15},{15},{1}},
  407.             {{-8},{-15},{25},{1}},
  408.             {{-26},{-15},{0},{1}},
  409.             {{-8},{-15},{-25},{1}},
  410.             {{21},{-15},{-15},{1}},
  411.             {{0},{-30},{-15},{1}}
  412.         },
  413.         connections = {{1,2,3},{1,4,3},{1,4,5},{1,6,5},{1,6,2},{2,3,7},{8,3,7},{3,4,8},{9,4,8},{4,5,9},{10,5,9},{5,6,10},{11,6,10},{6,2,11},{7,2,11},{12,11,10},{12,9,10},{12,9,8},{12,7,8},{12,7,11}}        
  414.     }
  415.     for i,val in ipairs(objData.indexList) do
  416.         objData.indexList[i] = val*4-3
  417.     end
  418.     return objData
  419. end
  420. return {
  421.     transform = transform,
  422.     drawTransformed = drawTransformed,
  423.     objects = {
  424.         newSquare = newSquare,
  425.         newCube = newCube,
  426.         newPyramid = newPyramid,
  427.         newIcosahedron = newIcosahedron,
  428.     },
  429.     createColor = createColor,
  430.     createPerspective = createPerspective,
  431.     createCamera = createCamera,
  432.     getDrawArgs = getDrawArgs
  433. }
  434.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement