Advertisement
XanthicDragon

RBX_LUA (ROBLOX Lua) - SK XML to OBJ

Mar 24th, 2015
238
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 8.81 KB | None | 0 0
  1. --[[--
  2.     BEFORE YOU START:
  3.    
  4.     Please realize:
  5.         1) Models may not seem as they do in the viewer. Reason: Texture mapping can change the appearance of a model
  6.         2) Certain models may not render 100% -- If this happens, message me and I will get right to work. (Though I think I fixed this)
  7. --]]--
  8.  
  9. scale = 50 --Sets how big the model is. 1 is default (but rather small)
  10. incre = 25 -- Sets how many triangles it generates before waiting a bit.
  11.  
  12. Type = "Articulated" -- If it's a normal model, put this. If it is a character, put "Character", if it is a skybox (i.e. the skydome), put "Skybox"
  13. --THE ABOVE IS VERY IMPORTANT FOR PROPER RENDERING!
  14.  
  15. TestAnyway = false --If true, it will enable "beta-mode" and allow the unfinished functions to run
  16.  
  17. Collision = true --If true, triangles will collide. HOWEVER: Scales below 10 may appear malformed.
  18.  
  19. print("Waiting for XML.")
  20. repeat wait() until _G.XML
  21. local Main = require(script.MainHandle)
  22. local xml = _G.XML
  23. st = 0
  24. print("Got XML.")
  25. wait(1)
  26. local tim = 0
  27. coroutine.resume(coroutine.create(function ()
  28.     while wait(0.1) do
  29.         tim = tim + 0.1
  30.     end
  31. end))
  32.  
  33. local f = {}
  34. local bones = {}
  35. local tris = {}
  36. local array = {}
  37. _, CountOfFaces1 = string.gsub(xml, "<v1>", "<v1>")
  38. _, CountOfFaces2 = string.gsub(xml, "<v2>", "<v2>")
  39. _, CountOfFaces3 = string.gsub(xml, "<v3>", "<v3>")
  40. CountOfFaces = CountOfFaces1+CountOfFaces2+CountOfFaces3
  41.  
  42. print("Vertex count = "..CountOfFaces)
  43. print("Face count = "..CountOfFaces/3)
  44.  
  45. function GetIndex(strt)
  46.     --print("Getting indices (order of vertecies)")
  47.     local str = "<indices>"
  48.     local estr = "</indices>"
  49.     local stp = xml:find(str, strt)
  50.     if not stp then return end
  51.     local st = stp+str:len()
  52.     local fn = xml:find(estr, strt)-1
  53.     local ind = {}
  54.     --loadstring("ind = {"..xml:sub(st, fn).."}")()
  55.     local txt = xml:sub(st, fn)
  56.     local c = 0
  57.     for i, _ in string.gmatch(txt, ", ") do
  58.         if c == 0 then
  59.             ff = txt:find(", ")-1
  60.             tt = txt:sub(1, ff)
  61.             table.insert(ind, tt)
  62.         else
  63.             local nff = ff+2
  64.             local ff2 = txt:find(", ", nff)-1
  65.             local tt = txt:sub(nff+1, ff2)
  66.             ff = ff2
  67.             table.insert(ind, tt)
  68.         end
  69.         c = c + 1
  70.         if c%500 == 0 then wait() end
  71.     end
  72.     --Now, using this EASY shortcut, I get a table from the set of indices
  73.     --[[--
  74.         NOTE:
  75.         index count = vertex count / 2
  76.     --]]--
  77.     --IND WILL SHOW NIL! IT IS NOT NIL!
  78.     --print("Got indices. Applying to three-group format...")
  79.     for i = 1, #ind do
  80.         if i % 3 == 0 then
  81.             local a = i-2
  82.             local b = i-1
  83.             local c = i
  84.             local A = tonumber(ind[a])+1
  85.             local B = tonumber(ind[b])+1
  86.             local C = tonumber(ind[c])+1
  87.             table.insert(f, {A, B, C})
  88.         end
  89.     end
  90.     --print("Index groups complete!")
  91. end
  92.  
  93. function GetTriangles()
  94.     repeat
  95.         if not st2 then
  96.             st2 = 0
  97.         end
  98.         v1, v2, v3, st = Main:FindTriangles(st2, xml)
  99.         st2 = st
  100.         table.insert(tris, {v1*scale, v2*scale, v3*scale, tostring(st2)})
  101.     until not string.find(xml, "<v1>", st)
  102. end
  103.  
  104. function GetOffsetsAndTriangles()
  105.     ofst = {}
  106.     repeat
  107.         if not st2 then
  108.             st2 = 0
  109.         end
  110.         if not st4 then
  111.             st4 = 0
  112.         end
  113.         local v1, st, bone, count = Main:GetSkyBoneOffsets(st2, xml)
  114.         st2 = st
  115.         GetIndex(st)
  116.         if count > 0 and bone and v1 then
  117.             for i = 1, count do
  118.                 table.insert(ofst, v1)
  119.             end
  120.         end
  121.     until not string.find(xml, "<v1>", st)
  122.     print("Got all bone data chains")
  123.     local r = 0
  124.     st2 = 0
  125.     repeat
  126.         r = r + 1
  127.         if not ofst[r] then
  128.             warn("Broke loop! ofst[r] = nil")
  129.             break
  130.         end
  131.         local v1, v2, v3, st = Main:FindTrianglesWithOffset(st2, xml, ofst[r])
  132.         st2 = st
  133.         table.insert(tris, {v1*scale, v2*scale, v3*scale})
  134.     until not string.find(xml, "<triangle>", st)
  135. end
  136. if Type:lower():find("articulated") then
  137.     GetTriangles()
  138.     GetIndex(0)
  139. elseif Type:lower():find("skybox") then
  140.     warn("Skybox not ready.")
  141.     if not TestAnyway then
  142.         GetTriangles()
  143.         GetIndex(0)
  144.     else
  145.         warn("Beta mode active! Running unfinished function for SkyBox")
  146.         GetOffsetsAndTriangles()
  147.     end
  148. elseif Type:lower():find("character") then
  149.     warn("Character not ready.")
  150.     GetTriangles()
  151.     GetIndex(0)
  152. end
  153.  
  154. local Tri = {}
  155. mesh2 = Instance.new("Model", workspace)
  156. mesh2.Name = "Triangles"
  157. function Tri.new(a, b, c, color)
  158.     local this = {}
  159.     local mPart1 = Instance.new('WedgePart')
  160.     setupPart(mPart1)
  161.     local mPart2 = Instance.new('WedgePart')
  162.     setupPart(mPart2)
  163.     function this:Set(a, b, c)
  164.         local ab, bc, ca = b-a, c-b, a-c
  165.         local abm, bcm, cam = ab.magnitude, bc.magnitude, ca.magnitude
  166.         local edg1 = math.abs(0.5 + ca:Dot(ab)/(abm*abm))
  167.         local edg2 = math.abs(0.5 + ab:Dot(bc)/(bcm*bcm))
  168.         local edg3 = math.abs(0.5 + bc:Dot(ca)/(cam*cam))
  169.         -- Idea: Find the edge onto which the vertex opposite that
  170.         -- edge has the projection closest to 1/2 of the way along that
  171.         -- edge. That is the edge thatwe want to split on in order to
  172.         -- avoid ending up with small "sliver" triangles with one very
  173.         -- small dimension relative to the other one.
  174.         if edg1 < edg2 then
  175.             if edg1 < edg3 then
  176.                 -- min is edg1: less than both
  177.                 -- nothing to change - All good!
  178.             else           
  179.                 -- min is edg3: edg3 < edg1 < edg2
  180.                 -- "rotate" verts twice counterclockwise to get edg1 < edg2 < edg3
  181.                 a, b, c = c, a, b
  182.                 ab, bc, ca = ca, ab, bc
  183.                 abm = cam
  184.             end
  185.         else
  186.             if edg2 < edg3 then
  187.                 -- min is edg2: less than both
  188.                 -- "rotate" verts once counterclockwise - same as above else statement
  189.                 a, b, c = b, c, a
  190.                 ab, bc, ca = bc, ca, ab
  191.                 abm = bcm
  192.             else
  193.                 -- min is edg3: edg3 < edg2 < edg1
  194.                 -- "rotate" verts twice counterclockwise:
  195.                 a, b, c = c, a, b
  196.                 ab, bc, ca = ca, ab, bc
  197.                 abm = cam
  198.             end
  199.         end
  200.      
  201.         --calculate lengths
  202.         local len1 = -ca:Dot(ab)/abm
  203.         local len2 = abm - len1
  204.         local width = (ca + ab.unit*len1).magnitude
  205.      
  206.         --calculate "base" CFrame to pasition parts by
  207.         local maincf = CFrameFromTopBack(a, ab:Cross(bc).unit, -ab.unit)
  208.        
  209.         --make parts
  210.         color = nil
  211.         if not Collision then
  212.             mPart1.Parent = mesh2
  213.             mPart1.Size = Vector3.new(0.2, 0.2, 0.2)
  214.             mPart1.Mesh.Scale = Vector3.new(0, width, len1)/0.2
  215.             mPart1.CFrame = maincf*CFrame.Angles(math.pi,0,math.pi/2)*CFrame.new(0,width/2,len1/2)
  216.             mPart1.BrickColor = BrickColor.Gray()
  217.            
  218.             mPart2.Parent = mesh2
  219.             mPart2.Size = Vector3.new(0.2, 0.2, 0.2)
  220.             mPart2.Mesh.Scale = Vector3.new(0, width, len2)/0.2
  221.             mPart2.CFrame = maincf*CFrame.Angles(math.pi,math.pi,-math.pi/2)*CFrame.new(0,width/2,-len1 - len2/2)
  222.             mPart2.BrickColor = BrickColor.Gray()
  223.         else
  224.             mPart1.Parent = mesh2
  225.             mPart1.Size = Vector3.new(0.2, width, len1)
  226.             mPart1.Mesh.Scale = Vector3.new(0, 1, 1)
  227.             mPart1.CFrame = maincf*CFrame.Angles(math.pi,0,math.pi/2)*CFrame.new(0,width/2,len1/2)
  228.             mPart1.BrickColor = BrickColor.Gray()
  229.            
  230.             mPart2.Parent = mesh2
  231.             mPart2.Size = Vector3.new(0.2, width, len2)
  232.             mPart2.Mesh.Scale = Vector3.new(0, 1, 1)
  233.             mPart2.CFrame = maincf*CFrame.Angles(math.pi,math.pi,-math.pi/2)*CFrame.new(0,width/2,-len1 - len2/2)
  234.             mPart2.BrickColor = BrickColor.Gray()
  235.         end
  236.         return mPart1, mPart2
  237.     end
  238.    
  239.     function this:SetProperty(prop, value)
  240.         mPart1[prop] = value
  241.         mPart2[prop] = value
  242.     end
  243.     function this:Destroy()
  244.         mPart1:Destroy()
  245.         mPart2:Destroy()
  246.     end
  247.     --this:Set(a, b, c)
  248.     return this:Set(a, b, c) --return this
  249. end
  250.  
  251. function CFrameFromTopBack(at, top, back)
  252.     local right = top:Cross(back)
  253.     return CFrame.new(at.x, at.y, at.z,
  254.                       right.x, top.x, back.x,
  255.                       right.y, top.y, back.y,
  256.                       right.z, top.z, back.z)
  257. end
  258. function setupPart(part)
  259.     part.Anchored = true
  260.     part.FormFactor = 'Custom'
  261.     part.CanCollide = true
  262.     part.BrickColor = BrickColor.Black()
  263.     part.TopSurface = 'SmoothNoOutlines'
  264.     part.BottomSurface = 'SmoothNoOutlines'
  265.     part.LeftSurface = 'SmoothNoOutlines'
  266.     part.RightSurface = 'SmoothNoOutlines'
  267.     part.FrontSurface = 'SmoothNoOutlines'
  268.     part.BackSurface = 'SmoothNoOutlines'
  269.    
  270.     local mesh = Instance.new("SpecialMesh", part)
  271.     mesh.MeshType = "Wedge"
  272.     mesh.Scale = Vector3.new(0,1,1)
  273. end
  274.  
  275. print("Mapping triangles")
  276.  
  277. for _,v in ipairs(tris) do
  278.     local face = f[_]
  279.     if face and face[1] and face[2] and face[3] and tris[a] and tris[b] and tris[c] then
  280.         a = face[1]
  281.         b = face[2]
  282.         c = face[3]
  283.         local x1 = tris[a][1]
  284.         local y1 = tris[a][2]
  285.         local z1 = tris[a][3]
  286.         local x2 = tris[b][1]
  287.         local y2 = tris[b][2]
  288.         local z2 = tris[b][3]
  289.         local x3 = tris[c][1]
  290.         local y3 = tris[c][2]
  291.         local z3 = tris[c][3]
  292.         local t1, t1a = Tri.new(x1, y1, z1)
  293.         local t2, t2a = Tri.new(x2, y2, z2)
  294.         local t3, t3a = Tri.new(x3, y3, z3)
  295.         if tris[a][4] and tris[b][4] and tris[c][4] then
  296.             t1.Name = tris[a][4]
  297.             t1a.Name = tris[a][4]
  298.             t2.Name = tris[b][4]
  299.             t2a.Name = tris[b][4]
  300.             t3.Name = tris[c][4]
  301.             t3a.Name = tris[c][4]
  302.         end
  303.     else
  304.         Tri.new(v[1], v[2], v[3])
  305.     end
  306.     if _%incre == 0 then wait() end
  307. end
  308. print("Rendered "..#tris.." triangles")
  309. print("Done! ("..tim.." seconds)")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement