-- lua --------------------------------------- -- UnrealASE Exporter for Modo v1.06 - --------------------------------------- -- AUTHOR: Zoltan Erdokovy (zoltan.erdokovy@gmail.com) -- -- -- This script saves the selected layer and its child layers into an ASE file. -- IMPORTANT: This exporter exports ONLY the Unreal relevant parts of the ASE format! -- So you probably can't use it to transfer objects to application other than UnrealEd. -- Although DeepExploration shows the objects properly. -- -- USAGE: -- The objects will be exported to the "objectdir" directory, located in the "content directory". -- The "objectdir" variable can be set/changed bellow, the content dir can be set in the preferences window. -- An empty "objectdir" string means that simply the content dir will be the target. -- The name of the exported file will be the name of the selected layer. -- It exports the first selected layer and any kids it has. (Child layers don't have to be selected.) -- -- The children layers should contain the collision primitives, with the proper name: Starting with -- MCDSP/MCDCX for UT2k4 -- and -- UCX/USP for U3. -- The rest of the name can be anything. -- -- The exporter exports the following vertex maps: -- UV called "UV1" -- UV called "UV2" -- UV called "UV3" -- RGB map called "Color" -- If no vertexmap found with these names, then it assigns 0,0,0 automatically. -- Set all your materials to a 89 degrees smoothing and use the separated polygon technique to achieve -- proper shading. Unreal disregards smoothinggroup ID >32, so this exporter reuses the 0-32 range. Sometimes -- this results in smoothing together otherwise independent, neighbouring poly islands. To fix this just cut and -- paste one of them to change the order of the polygons. -- Sometimes smoothing groups are not exported properly. A re-export after restarting modo will fix it. -- -- You can set what unit in modo you want to be 1 unit in unreal. Check out the "UnitSystem" variable bellow. -- I recommend using gameunits, but you can use a few other units, the object will be scaled properly. -- -- Known issues: -- You have to edit the parameters in the script. It would need too many arguments to define all aspects -- of the export, -- -- If you find a bug or have a feature requests don't hesitate to contact me. :) -- -- -- Changes in v1.06: -- -- - Removed collision layer name clamping. Now full layernames are exported, fixing compatibility with UE2 and UE2.5. -- -- Changes in v1.05: -- -- - 301 compatibility. -- - Removed older hacks. -- -- Changes in v1.04: -- -- - Fixed smoothing group numbering. -- - Fixed errors when something was selected. -- - Fixed default value for content dir. -- -- -- Changes in v1.03: -- -- - Fixed precision when scaling from game units. -- - Fixed export when no partname is assigned to polys. -- - Fixed smoothing group generation. -- - 3 UV support. -- -- -- Changes in v1.02: -- -- - Fixed quad/ngon handling, fixed discontinuos UVs. -- -- -- Changes in v1.01: -- -- - Fixed object rotation. -- - Added scale factors when using different unit systems. version = "v1.05" contentdir = "c:" -- Initial value for content dir. objectdir = "" -- The proper directory to store exported objects, inside the content dir. UnitSystem = "GAMEUNIT" -- Set what you want to be 1 unreal unit: -- "GAMEUNIT", "METER", "MILLIMETER", "FEET", "INCH". TempFileName = "temp.lxo" -- The temp file's name. bSaveTempFile = false -- If true it saves the temporary scene to a file, next to the exported files. ----------------------------- UV1Name = "UV1" UV2Name = "UV2" UV3Name = "UV3" VColName = "Color" -- -- -- FORMATNUM -- -- -- function FormatNum (Num) return (string.format("%.4f", Num)) end -- -- -- ASSIGNSGROUPS -- -- -- function AssignSGroups () SGroup = 0 -- The actual smoothing group. --lx("select.drop polygon") for i = 0, FaceNum-1 do SelectLayer(1) if FaceSGroups[i] == nil then -- If we have no stored smg... lx("select.element [1] polygon add ["..i.."]") -- Select face #i on the first layer. lx("select.connect") -- Select connected faces. --lxq("query layerservice layer.name ? 1") ActSel = lxq("query layerservice polys ? selected") -- We get back the array of indexes of selected polys. ActSelSize = table.getn(ActSel) -- Get the number of selected polys. for j = 1, ActSelSize do -- Go through all selected polys. if FaceSGroups[tonumber(ActSel[j])] == nil then -- If we have no stored data there... FaceSGroups[tonumber(ActSel[j])] = SGroup -- We set the smg. end --lxout("tonumber(ActSel[j]) == "..tonumber(ActSel[j])) end --lx("select.drop polygon") -- Deselect everything. SGroup = SGroup+1 -- Increase the smg number. if SGroup == 33 then SGroup = 0 end -- If we have reached the 32 SMG limit then we start over. else end end end -- -- -- GETFACEPOINTS -- -- -- function GetFacePoints (FaceIndex) p = lxq("query layerservice poly.vertList ? "..FaceIndex) return ({p[1],p[2],p[3]}) end -- -- -- GETPOINTPOSITION -- -- -- function GetPointPosition (PointIndex) p = lxq("query layerservice vert.pos ? "..PointIndex) -- Getting original coordinates. -- Rotating the object so it will be in the proper position in UEd. -- p = {p[1], p[3], -p[2]} -- X,Z,-Y = 90 around Unreal X p = {-p[1], p[2], -p[3]} -- -X,Y,-Z = 180 around Unreal Y p = {-p[2], p[1], p[3]} -- -Y,X,Z = 90 around Unreal Z p = {p[1]*UnitScale, p[2]*UnitScale, p[3]*UnitScale} -- Scale properly. return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])}) end -- -- -- UVSETEXISTS -- -- -- function UVSetExists (TargetUVName) lxq("query layerservice vmap_groups ? all") VmapNum = lxq("query layerservice vmap.n ? all")[1] for i = 0, VmapNum-1 do ActVmapType = lxq("query layerservice vmap.type ? "..i)[1] ActVmapName = lxq("query layerservice vmap.name ? "..i)[1] if ( ActVmapType == "texture") and ( ActVmapName == TargetUVName) then return(true) end end return(false) end -- -- -- GETPOINTUV -- -- -- function GetPointUV (PointIndex, TargetUVName) lxq("query layerservice vmap_groups ? all") VmapNum = lxq("query layerservice vmap.n ? all")[1] for i = 0, VmapNum-1 do ActVmapType = lxq("query layerservice vmap.type ? "..i)[1] ActVmapName = lxq("query layerservice vmap.name ? "..i)[1] if ( ActVmapType == "texture") and ( ActVmapName == TargetUVName) then p = lxq("query layerservice vert.vmapValue ? "..PointIndex) --if p == ("query layerservice vert.vmapValue ? "..PointIndex) then -- !!! WORKAROUND !!! -- p = nil -- If the point has no value on a vmap --end -- then the query should give back nil, -- but now it gives back the query itself. -- If the bug gets squashed, this 3 lines -- can be removed. if p == nil then p = {"0.0000","0.0000"} end -- Failsafe if a vertex doesn't have a UV value. end end return ({FormatNum(p[1]),FormatNum(p[2])}) end -- -- -- GETPOINTCOLOR -- -- -- function GetPointColor (PointIndex) p = {"0.0000","0.0000","0.0000"} lxq("query layerservice vmap_groups ? all") for i = 0, (lxq("query layerservice vmap.n ? all")[1])-1 do ActVmapType = lxq("query layerservice vmap.type ? "..i)[1] ActVmapName = lxq("query layerservice vmap.name ? "..i)[1] if ( ActVmapType == "rgb") and ( ActVmapName == VColName) then p = lxq("query layerservice vert.vmapValue ? "..PointIndex) --if p == ("query layerservice vert.vmapValue ? "..PointIndex) then -- !!! WORKAROUND !!! -- p = nil -- If the point has no value on a vmap --end -- then the query should give back nil, -- but now it gives back the query itself. -- If the bug gets squashed, this 3 lines -- can be removed. if p == nil then p = {"1.0000","1.0000","1.0000"} end -- Failsafe if a vertex doesn't have a color value. end end return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])}) end -- -- -- GETFACENORMAL -- -- -- function GetFaceNormal (FaceIndex) p = lxq("query layerservice poly.normal ? "..FaceIndex) return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])}) end -- -- -- GETPOINTNORMAL -- -- -- function GetPointNormal (PointIndex) p = lxq("query layerservice vert.normal ? "..PointIndex) return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])}) end -- -- -- GETFACEMATERIALID -- -- -- function GetFaceMaterialID (FaceIndex) m = lxq("query layerservice poly.material ? "..FaceIndex)[1] -- It gives back a material name, but we need an index. for i = 0, (MaterialNum-1) do -- Iterating through the materials. if MaterialNames[i+1] == m then MaterialID = i end end return (MaterialID) -- And return with the proper material index. end -- -- -- SELECTLAYER -- -- -- function SelectLayer (LayerIndex) lx("select.layer "..LayerIndex.." set") -- Let's make absolutely damn sure... lxq("query layerservice layer.name ? "..LayerIndex) -- ...that we have the given layer selected... lxq("query layerservice layer.index ? fg") -- ... in every possible way. end -- -- -- MAIN -- -- -- lxout("------- ASE conversion started. -------") lxout("("..version..")") StartTime = os.time() MainLayer = 0 -- The index of the main layer. MainLayerName = "" -- The name of the main layer. ActLayer = 8 -- The index of the layer we are working on. ChildrenNum = 0 -- The number of children. ChildrenLayers = {} -- Array for indices of child layers. ChildrenNames = {} -- Array for names of child layers. ChildrenIDs = {} -- Array for names of child IDs. Layers = {} -- The indices of all relevant layers: main layer + any children. LayerNames = {} -- The names of all relevant layers: main layer + any children. LayerNum = 0 -- The number of all relevant layers. MaterialNum = 0 -- The number of materials. MaterialNames = {} -- Array for material names. FacePoints = {} -- Array for the point indices of a face. FaceSGroups = {} -- Array of numbers, one for each face, representing smoothing groups. Pos = {} -- Array for point positions in both 3D and UV space. ProcFaceNum = 0 -- The total number of processed faces. -- Determining scale factor for different unit systems -- if UnitSystem == "GAMEUNIT" then UnitScale = 53.3333 elseif UnitSystem == "METER" then UnitScale = 1 elseif UnitSystem == "MILLIMETER" then UnitScale = 1000 elseif UnitSystem == "FEET" then UnitScale = 3.2808398950131 elseif UnitSystem == "INCH" then UnitScale = 39.3700787 else UnitScale = 1 end -- Dropping every selection -- --lx("select.drop vertex") --lx("select.drop edge") --lx("select.drop polygon") --lx("select.vertexMap \"\" txuv replace") --lx("select.invert") -- Setting up directories -- contentdir = lxq("pref.value lwio.lwoContentDir ?") lxout("> Content dir: "..contentdir[1]) if (contentdir == nil) then error("Please set the content directory.") end contentdir = contentdir[1] string.gsub(contentdir,"\\","/") -- Replacing all "\" to "/". savedir = contentdir..objectdir -- Adding the proper object dir to the final path. -- Collecting layer data -- MainLayer = lxq("query layerservice layer.index ? fg")[1] -- We need only the first selected layer. MainLayerName = lxq("query layerservice layer.name ? fg")[1] -- We use the name of the first fg layer as export name. MainLayerID = lxq("query layerservice layer.id ? fg")[1] -- We get the ID of the fg layer for future use. lxout("> MainLayerIndex: "..MainLayer) ChildrenNum = lxq("query layerservice layer.childCount ? "..MainLayer)[1] -- Get child count. lxout("> ChildrenNum: "..ChildrenNum) if ChildrenNum ~= 0 then -- If there are children, then get info about them. ChildrenIDs = lxq("query layerservice layer.children ? "..MainLayer) -- Get the array fo child IDs. for i=1, ChildrenNum do -- !!!WORKAROUND!!! -- We add +1 to the recieved layer indices to fix a bug in the layer.children query. --ChildrenLayers[i] = ChildrenLayers[i]+1 -- !!!WORKAROUND!!! -- The buggy layer index query does not care about passed ID, it gives back the index of the actual layer... lx("select.subItem "..ChildrenIDs[i].." set mesh") -- ...so we select the child to get a proper value from the next query. ChildrenLayers[i] = lxq("query layerservice layer.index ? "..ChildrenIDs[i])[1] lxout("> Child "..i.." index: "..ChildrenLayers[i]) -- Collecting children data -- ChildrenNames[i] = lxq("query sceneservice item.name ? "..ChildrenIDs[i])[1] ----ChildrenNames[i] = string.sub(ChildrenNames[i], 1, 3) -- Using only the first 3 characters. lxout("> Child "..i.." name: "..ChildrenNames[i]) end -- Making arrays for all relevant layer data -- Layers = ChildrenLayers table.insert(Layers,1,MainLayer) -- Collect the indices of all relevant layers. LayerNames = ChildrenNames table.insert(LayerNames,1,MainLayerName) -- Collect the names of all relevant layers. LayerNum = ChildrenNum+1 -- Compute the number of the relevant layers. else -- If no children, then we set layer data of the mainlayer. Layers = {MainLayer} LayerNames = {MainLayerName} LayerNum = 1 end lx("select.subItem "..MainLayerID.." set mesh") --Restore main layer selection after the children layer index workaround . -- Copying data to a new scene -- lxout("- Copying data to a new scene. -") OriginalScene = lxq("query sceneservice scene.index ? current")[1] -- Store the index of the source scene. lx("scene.new") NewScene = lxq("query sceneservice scene.index ? current")[1] -- Store the index of the new scene. for i = 1, LayerNum do -- Iterating through the layers. lx("scene.set "..OriginalScene) -- Go back from the new scene to the original. SelectLayer(Layers[i]) -- Select the proper layer. lx("select.copy") -- Copy layer contents. lx("scene.set "..NewScene) -- Go to the new scene. SelectLayer(i) -- Select the next empty layer. lx("select.paste") -- Paste stuff. lx("item.name "..LayerNames[i].." mesh") -- Set proper name. if (i < LayerNum) then -- If there are children, and we are not working with the last of them... lx("layer.newItem mesh") -- ... then we make a new empty layer for the next one. end end -- Preparing files -- fileOutName = savedir.."/"..MainLayerName..".ase" TempFileName = savedir.."/"..TempFileName fileOut = io.open(fileOutName, "w+") if (fileOut == nil) then error("Can't open "..fileOutName.."!") end -- Writing data to file -- -- Header -- fileOut:write("*3DSMAX_ASCIIEXPORT 200\n") fileOut:write("*COMMENT \"Generated by ASEExport4Unreal v1.0\" \n") -- Scene -- fileOut:write("*SCENE {\n") fileOut:write("\t*SCENE_FILENAME \""..LayerNames[1].."\"\n") fileOut:write("\t*SCENE_FIRSTFRAME 0\n") fileOut:write("\t*SCENE_LASTFRAME 100\n") fileOut:write("\t*SCENE_FRAMESPEED 30\n") fileOut:write("\t*SCENE_TICKSPERFRAME 160\n") fileOut:write("\t*SCENE_BACKGROUND_STATIC 0.0000\t0.0000\t0.0000\n") fileOut:write("\t*SCENE_AMBIENT_STATIC 0.0000\t0.0000\t0.0000\n") fileOut:write("}\n") --------------------------- -- Proccessing materials -- --------------------------- lxout("- Proccessing materials -") SelectLayer(1) -- Select te first layer, where we actually care about materials. -- This is the render object, all other layers are for collision. MaterialNum = lxq("query layerservice material.n ? all")[1] --lxout("> Material number: "..MaterialNum) for j = 1, MaterialNum do MaterialNames[j] = lxq("query layerservice material.name ? "..j-1)[1] end fileOut:write("*MATERIAL_LIST {\n") fileOut:write("\t*MATERIAL_COUNT 1 \n") fileOut:write("\t*MATERIAL 0 {\n") fileOut:write("\t\t*MATERIAL_NAME \""..MaterialNames[1].."\"\n") fileOut:write("\t\t*MATERIAL_CLASS \"Multi/Sub-Object\" \n") fileOut:write("\t\t*NUMSUBMTLS "..MaterialNum.."\n") for i = 1, MaterialNum do -- Iterating through the materials which become submaterials. fileOut:write("\t\t*SUBMATERIAL "..(i-1).." { \n") fileOut:write("\t\t\t*MATERIAL_NAME \""..MaterialNames[i].."\"\n") -- TODO: Check if there is no material assigned. fileOut:write("\t\t\t*MATERIAL_CLASS \"Standard\" \n") fileOut:write("\t\t\t*MAP_DIFFUSE {\n") fileOut:write("\t\t\t\t*MAP_NAME \""..MaterialNames[i].."\"\n") fileOut:write("\t\t\t\t*BITMAP \"c:\\"..MaterialNames[i]..".tga\"\n") fileOut:write("\t\t\t\t*UVW_U_TILING 1.0000 \n") fileOut:write("\t\t\t\t*UVW_V_TILING 1.0000 \n") fileOut:write("\t\t\t}\n") fileOut:write("\t\t}\n") end fileOut:write("\t}\n") fileOut:write("}\n") -------------------------- -- Proccessing geometry -- -------------------------- lxout("- Proccessing geometry -") for ActLayer = 1, LayerNum do -- Iterating through the layers. SelectLayer(ActLayer) lx("select.type polygon") lx("poly.triple") Faces = lxq("query layerservice polys ? all") -- Getting the list of faces. FaceNum = table.getn(Faces) ProcFaceNum = ProcFaceNum + FaceNum if ActLayer == 1 then -- We only bother with smoothing groups in the case of layer #1. AssignSGroups() -- Assigning the smoothing groups before the unweld destroys poly islands. end lx("select.type polygon") lx("vert.split") -- Unweld, so every vertex has it's own UV coordinates. SelectLayer(ActLayer) -- Reselect layer to make sure internal data is updated. Vertices = lxq("query layerservice verts ? all") -- Getting the list of vertices. VertexNum = table.getn(Vertices) fileOut:write("*GEOMOBJECT {\n") fileOut:write("\t*NODE_NAME \""..LayerNames[ActLayer].."\"\n") -- Geometry - Node -- fileOut:write("\t*NODE_TM {\n") fileOut:write("\t\t*NODE_NAME \""..LayerNames[ActLayer].."\"\n") fileOut:write("\t}\n") -- Geometry - Mesh -- fileOut:write("\t*MESH {\n" ) fileOut:write("\t\t*MESH_NUMVERTEX "..VertexNum.."\n") fileOut:write("\t\t*MESH_NUMFACES "..FaceNum.."\n") -- Geometry - Mesh - Vertex list -- fileOut:write("\t\t*MESH_VERTEX_LIST {\n") for j = 0, (VertexNum-1) do -- Iterating through the vertices. Pos = GetPointPosition(j) fileOut:write("\t\t\t*MESH_VERTEX\t"..j.."\t"..Pos[1].."\t"..Pos[2].."\t"..Pos[3].."\n") end fileOut:write("\t\t}\n") -- Geometry - Mesh - Face list -- fileOut:write("\t\t*MESH_FACE_LIST {\n") for j = 0, (FaceNum-1) do -- Iterating through the faces. FacePoints = GetFacePoints(j) fileOut:write("\t\t\t*MESH_FACE\t"..j..":\tA:\t"..FacePoints[1].." B:\t"..FacePoints[2].." C:\t"..FacePoints[3]) if ActLayer == 1 then -- If the actual layer is #1 then we assign the proper material ID. fileOut:write(" AB:\t1 BC:\t1 CA:\t0\t*MESH_SMOOTHING "..FaceSGroups[j].."\t*MESH_MTLID "..GetFaceMaterialID(j).."\n") else -- If the actual layer is not #1 then it's for collision info, so we force material #1, and prevent storing -- unused material references in the object. fileOut:write(" AB:\t1 BC:\t1 CA:\t0\t*MESH_SMOOTHING 0\t*MESH_MTLID 1 \n") end end fileOut:write("\t\t}\n") --------------------- -- Proccessing UVs -- --------------------- -- Texture - Vertex list - UV1 -- fileOut:write("\t\t*MESH_NUMTVERTEX "..VertexNum.."\n") fileOut:write("\t\t*MESH_TVERTLIST {\n") for j = 0, (VertexNum-1) do -- Iterating through the vertices. UVPos = GetPointUV(j,UV1Name) fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..UVPos[1].."\t"..UVPos[2].."\t0.0000\n") end fileOut:write("\t\t}\n") -- Closing MESH_TVERTLIST -- Texture - Face list -- fileOut:write("\t\t*MESH_NUMTVFACES "..FaceNum.."\n") fileOut:write("\t\t*MESH_TFACELIST {\n") for j = 0, (FaceNum-1) do -- Iterating through the faces. FacePoints = GetFacePoints(j) fileOut:write("\t\t\t*MESH_TFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n") end fileOut:write("\t\t}\n") -- Closing MESH_TFACELIST fileOut:write("\t\t*MESH_MAPPINGCHANNEL 2 {\n") -- Texture - Vertex list - UV2 -- fileOut:write("\t\t\t*MESH_NUMTVERTEX "..VertexNum.."\n") fileOut:write("\t\t\t*MESH_TVERTLIST {\n") for j = 0, (VertexNum-1) do -- Iterating through the vertices. UVPos = GetPointUV(j,UV2Name) fileOut:write("\t\t\t\t*MESH_TVERT\t"..j.."\t"..UVPos[1].."\t"..UVPos[2].."\t0.0000\n") end fileOut:write("\t\t\t}\n") -- Closing MESH_TVERTLIST -- Texture - Face list -- fileOut:write("\t\t\t*MESH_NUMTVFACES "..FaceNum.."\n") fileOut:write("\t\t\t*MESH_TFACELIST {\n") for j = 0, (FaceNum-1) do -- Iterating through the faces. FacePoints = GetFacePoints(j) fileOut:write("\t\t\t\t*MESH_TFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n") end fileOut:write("\t\t\t}\n" ) -- Closing MESH_TFACELIST fileOut:write("\t\t}\n") -- Closing MESH_MAPPINGCHANNEL 2 if UVSetExists(UV3Name) then -- If UV3 exists then we bother with writing it to the file. fileOut:write("\t\t*MESH_MAPPINGCHANNEL 3 {\n") -- Texture - Vertex list - UV3 -- fileOut:write("\t\t\t*MESH_NUMTVERTEX "..VertexNum.."\n") fileOut:write("\t\t\t*MESH_TVERTLIST {\n") for j = 0, (VertexNum-1) do -- Iterating through the vertices. UVPos = GetPointUV(j,UV3Name) fileOut:write("\t\t\t\t*MESH_TVERT\t"..j.."\t"..UVPos[1].."\t"..UVPos[2].."\t0.0000\n") end fileOut:write("\t\t\t}\n") -- Closing MESH_TVERTLIST -- Texture - Face list -- fileOut:write("\t\t\t*MESH_NUMTVFACES "..FaceNum.."\n") fileOut:write("\t\t\t*MESH_TFACELIST {\n") for j = 0, (FaceNum-1) do -- Iterating through the faces. FacePoints = GetFacePoints(j) fileOut:write("\t\t\t\t*MESH_TFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n") end fileOut:write("\t\t\t}\n" ) -- Closing MESH_TFACELIST fileOut:write("\t\t}\n") -- Closing MESH_MAPPINGCHANNEL 3 end ------------------------------ -- Proccessing vertex color -- ------------------------------ -- VertexColor - Vertex list -- fileOut:write("\t\t*MESH_NUMCVERTEX "..VertexNum.."\n") fileOut:write("\t\t*MESH_CVERTLIST {\n") for j = 0, (VertexNum-1) do -- Iterating through the vertices. Col = GetPointColor(j) fileOut:write("\t\t\t*MESH_VERTCOL\t"..j.."\t"..Col[1].."\t"..Col[2].."\t"..Col[3].."\n") end fileOut:write("\t\t}\n" ) -- VertexColor - Face list -- fileOut:write("\t\t*MESH_NUMCVFACES "..FaceNum.."\n") fileOut:write("\t\t*MESH_CFACELIST {\n") for j = 0, (FaceNum-1) do -- Iterating through the faces. FacePoints = GetFacePoints(j) fileOut:write("\t\t\t*MESH_CFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n") end fileOut:write("\t\t}\n") ------------------------- -- Proccessing normals -- ------------------------- fileOut:write("\t\t*MESH_NORMALS {\n") for j = 0, (FaceNum-1) do -- Iterating through the faces. Normal = GetFaceNormal(j) fileOut:write("\t\t\t*MESH_FACENORMAL\t"..j.."\t"..Normal[1].."\t"..Normal[2].."\t"..Normal[3].."\n") FacePoints = GetFacePoints(j) for k = 1, 3 do -- Iterating through the points of the actual face. Normal = GetPointNormal(FacePoints[k]) fileOut:write("\t\t\t\t*MESH_VERTEXNORMAL\t"..FacePoints[k].."\t"..Normal[1].."\t"..Normal[2].."\t"..Normal[3].."\n") end end fileOut:write("\t\t}\n" ) fileOut:write("\t}\n" ) fileOut:write("\t*MATERIAL_REF 0\n" ) fileOut:write("}\n" ) end ----------------- -- Cleaning up -- ----------------- if bSaveTempFile then lx("!scene.saveAs filename:\""..TempFileName.."\"") end lx("!scene.close") -- Closing scene with suppressed dialog. fileOut:close() SelectLayer(MainLayer) -- Going back to the original layer. EndTime = os.time() ExportTime = os.difftime(EndTime, StartTime) lxout("Export took "..ExportTime.." seconds.") lxout("Total number of processed polygons: "..ProcFaceNum) lxout("Speed: "..(ProcFaceNum / ExportTime).." polygons/sec.") lxout("------- Object exported. -------")