Advertisement
nonogamer9

Utah Teapot on ComputerCraft

Sep 20th, 2024
46
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.36 KB | Software | 0 0
  1. function loadOBJ(filePath)
  2.     local vertices = {}
  3.     local faces = {}
  4.  
  5.     local file = fs.open(filePath, "r")
  6.     if not file then
  7.         error("File not found: " .. filePath)
  8.     end
  9.  
  10.     while true do
  11.         local line = file.readLine()
  12.         if not line then break end
  13.  
  14.         local parts = {}
  15.         for word in string.gmatch(line, "%S+") do
  16.             table.insert(parts, word)
  17.         end
  18.        
  19.         if parts[1] == "v" then
  20.             local x = tonumber(parts[2])
  21.             local y = tonumber(parts[3])
  22.             local z = tonumber(parts[4])
  23.             table.insert(vertices, {x, y, z})
  24.         elseif parts[1] == "f" then
  25.             local v1 = tonumber(string.match(parts[2], "%d+"))
  26.             local v2 = tonumber(string.match(parts[3], "%d+"))
  27.             local v3 = tonumber(string.match(parts[4], "%d+"))
  28.             table.insert(faces, {v1, v2, v3})
  29.         end
  30.     end
  31.     file.close()
  32.  
  33.     return vertices, faces
  34. end
  35.  
  36. function normalizeVertices(vertices, maxSize)
  37.     local minX, minY, minZ = math.huge, math.huge, math.huge
  38.     local maxX, maxY, maxZ = -math.huge, -math.huge, -math.huge
  39.    
  40.     for _, vertex in ipairs(vertices) do
  41.         local x, y, z = vertex[1], vertex[2], vertex[3]
  42.         minX, maxX = math.min(minX, x), math.max(maxX, x)
  43.         minY, maxY = math.min(minY, y), math.max(maxY, y)
  44.         minZ, maxZ = math.min(minZ, z), math.max(maxZ, z)
  45.     end
  46.  
  47.     local scale = maxSize / math.max(maxX - minX, maxY - minY, maxZ - minZ)
  48.     local centerX, centerY, centerZ = (minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2
  49.  
  50.     local normalizedVertices = {}
  51.     for _, vertex in ipairs(vertices) do
  52.         local x = (vertex[1] - centerX) * scale
  53.         local y = (vertex[2] - centerY) * scale
  54.         local z = (vertex[3] - centerZ) * scale
  55.         table.insert(normalizedVertices, {x, y, z})
  56.     end
  57.  
  58.     return normalizedVertices
  59. end
  60.  
  61. function rotatePoint(x, y, z, angleX, angleY, angleZ)
  62.     local sinX, cosX = math.sin(angleX), math.cos(angleX)
  63.     local sinY, cosY = math.sin(angleY), math.cos(angleY)
  64.     local sinZ, cosZ = math.sin(angleZ), math.cos(angleZ)
  65.  
  66.     local y1 = y * cosX - z * sinX
  67.     local z1 = y * sinX + z * cosX
  68.     local x2 = x * cosY + z1 * sinY
  69.     local z2 = -x * sinY + z1 * cosY
  70.     local x3 = x2 * cosZ - y1 * sinZ
  71.     local y3 = x2 * sinZ + y1 * cosZ
  72.  
  73.     return x3, y3, z2
  74. end
  75.  
  76. function project(x, y, z, screenWidth, screenHeight, fov, viewerDistance)
  77.     local factor = fov / (viewerDistance + z)
  78.     local xProj = math.floor(screenWidth / 2 + x * factor)
  79.     local yProj = math.floor(screenHeight / 2 - y * factor * 0.5)
  80.  
  81.     return xProj, yProj
  82. end
  83.  
  84. function getASCIICharacter(z)
  85.     local chars = " .:-=+*%@#"
  86.     local index = math.floor((-z + 10) / 20 * (#chars - 1)) + 1
  87.    
  88.     if index < 1 then index = 1 end
  89.     if index > #chars then index = #chars end
  90.    
  91.     return chars:sub(index, index)
  92. end
  93.  
  94. local function createBuffer(width, height)
  95.     local buffer = {}
  96.     for y = 1, height do
  97.         buffer[y] = {}
  98.         for x = 1, width do
  99.             buffer[y][x] = " "
  100.         end
  101.     end
  102.     return buffer
  103. end
  104.  
  105. local function drawPixel(buffer, x, y, char)
  106.     if x >= 1 and x <= #buffer[1] and y >= 1 and y <= #buffer then
  107.         buffer[y][x] = char
  108.     end
  109. end
  110.  
  111. local function drawLine(buffer, x0, y0, x1, y1, z)
  112.     local dx, dy = math.abs(x1 - x0), math.abs(y1 - y0)
  113.     local sx, sy = x0 < x1 and 1 or -1, y0 < y1 and 1 or -1
  114.     local err = dx - dy
  115.  
  116.     while true do
  117.         drawPixel(buffer, x0, y0, getASCIICharacter(z))
  118.         if x0 == x1 and y0 == y1 then break end
  119.         local e2 = err * 2
  120.         if e2 > -dy then
  121.             err = err - dy
  122.             x0 = x0 + sx
  123.         end
  124.         if e2 < dx then
  125.             err = err + dx
  126.             y0 = y0 + sy
  127.         end
  128.     end
  129. end
  130.  
  131. local function renderBuffer(buffer)
  132.     for y = 1, #buffer do
  133.         term.setCursorPos(1, y)
  134.         term.write(table.concat(buffer[y]))
  135.     end
  136. end
  137.  
  138. function sortByDepth(faces)
  139.     table.sort(faces, function(a, b)
  140.         return (a[2] or 0) > (b[2] or 0)
  141.     end)
  142.     return faces
  143. end
  144.  
  145. function drawTeapot(vertices, faces)
  146.     local screenWidth, screenHeight = term.getSize()
  147.     local angleX, angleY, angleZ = 0, 0, 0
  148.     local fov = 60  
  149.     local viewerDistance = 20  
  150.  
  151.     while true do  
  152.         local buffer = createBuffer(screenWidth, screenHeight)
  153.  
  154.         local projectedVertices = {}  
  155.         for _, vertex in ipairs(vertices) do  
  156.             local x, y, z = table.unpack(vertex)  
  157.             local xRot, yRot, zRot = rotatePoint(x, y, z, angleX, angleY, angleZ)  
  158.             local xProj, yProj = project(xRot, yRot, zRot, screenWidth, screenHeight, fov, viewerDistance)  
  159.             table.insert(projectedVertices, {xProj, yProj, zRot})  
  160.         end  
  161.  
  162.         local sortedFaces = {}  
  163.         for _, face in ipairs(faces) do  
  164.             local v1, v2, v3 = face[1], face[2], face[3]  
  165.             if projectedVertices[v1] and projectedVertices[v2] and projectedVertices[v3] then  
  166.                 local avgZ = (projectedVertices[v1][3] + projectedVertices[v2][3] + projectedVertices[v3][3]) / 3  
  167.                 table.insert(sortedFaces, {face, avgZ})  
  168.             end  
  169.         end  
  170.  
  171.         sortedFaces = sortByDepth(sortedFaces)  
  172.  
  173.         for _, faceData in ipairs(sortedFaces) do  
  174.             local face, avgZ = faceData[1], faceData[2]  
  175.             local v1, v2, v3 = face[1], face[2], face[3]  
  176.             local x1, y1 = projectedVertices[v1][1], projectedVertices[v1][2]  
  177.             local x2, y2 = projectedVertices[v2][1], projectedVertices[v2][2]  
  178.             local x3, y3 = projectedVertices[v3][1], projectedVertices[v3][2]  
  179.  
  180.             drawLine(buffer, x1, y1, x2, y2, avgZ)  
  181.             drawLine(buffer, x2, y2, x3, y3, avgZ)  
  182.             drawLine(buffer, x3, y3, x1, y1, avgZ)  
  183.         end  
  184.  
  185.         renderBuffer(buffer)
  186.  
  187.         angleX = angleX + 0.05  
  188.         angleY = angleY + 0.03  
  189.         angleZ = angleZ + 0.02  
  190.  
  191.         sleep(0.05)  
  192.     end  
  193. end
  194.  
  195. shell.run("wget https://raw.githubusercontent.com/alecjacobson/common-3d-test-models/master/data/teapot.obj teapot.obj")
  196. local vertices, faces = loadOBJ("teapot.obj")
  197. local maxSize = 15  
  198. vertices = normalizeVertices(vertices, maxSize)  
  199. drawTeapot(vertices, faces)
  200.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement