-- lua -------------------------------------- -- UnrealASE Exporter for Modo v1.1 - -------------------------------------- -- AUTHOR: Zoltan Erdokovy (zoltan.erdokovy@gmail.com) -- Blog: www.zspline.net -- -- Special thanks to Mika Vehkala (mika.vehkala@gmail.com) for optimizations and improvements. -- -- -- 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! -- I can't guarantee that the exported object will work with applications other than UnrealEd. -- -- USAGE: -- @Scripts\ASEExport4Unreal.lua gameunits silentsave -- -- You can pass arguments to the script in any order. -- -- For setting the unit size: -- -- gameunits -- meter -- centimeter -- millimeter -- feet -- inch -- -- The default unit system is game units. -- -- By default the script will show a file requester dialog to set the filename for the exported file. -- You can supress this dialog by using the -- -- silentsave -- -- argument. In that case the objects will be exported to the "content directory". The content dir can -- be set in modo's preferences window. The name of the exported file will be the name of the selected -- layer. -- -- The script exports the first selected layer as the render object, and any kids it might have, as collision geometry. -- (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" -- Vertexmaps with different name are discarded. -- -- 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 and/or UVs are screwed up. A re-export after -- restarting modo will fix it. -- -- -- Known issues: -- You might want 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. :) -- ------------------------------------------------ -- This software is licensed under the -- Creative Commons Attribution-Share Alike 3.0 Unported License. -- For more info please visit -- http://creativecommons.org/licenses/by-sa/3.0/ ------------------------------------------------ -- -- Changes in v1.1: -- -- - Much more stable export: the "messed up UVs and smoothing" problem appears much less frequently. -- - Missing UV2, UV3 and COLOR vertex maps will be discarded and not exported with zero values. -- - Error handling for "Gameunits" unit system. -- - Fixed optional temp file naming. -- -- Changes in v1.08: -- -- - Fixed vertex color export. -- - Added "centimeter" unit option -- -- Changes in v1.07: -- -- - Merged Mika Vehkala's optimizations. -- - The layer's pivot is used as exported pivot, instead of world origin. -- - Added optional file dialog for saving the ASE file. -- - The script now accepts arguments for setting unit scale and turning on silent save mode. -- - Removed the "objectdir" variable. -- -- 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.1" contentdir = "c:" -- Initial value for content dir. TempFileName = "temp.lxo" -- The temp file's name last part. The name of the exported layer will be added before it. bSaveTempFile = false -- If true then it saves the temporary scene to a file, next to the exported files. -- Please note that this function only works properly in SilentSave mode. UnitScale = 1 -- Default unitscale. bSilentSave = false -- If true then a file dialog won't be shown when saving data. ----------------------------- 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. Vertices = lxq("query layerservice verts ? all") -- Getting the list of vertices. 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. 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. lxout("Polycount in smoothing group #"..SGroup.." : "..ActSelSize) 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 lx("select.all") lx("select.copy") lx("select.paste") lx("select.invert") lx("delete") end -- -- -- GETFACEPOINTS -- -- -- function GetFacePoints (FaceIndex) p = lxq("query layerservice poly.vertList ? "..FaceIndex) return ({p[1],p[2],p[3]}) end -- -- -- GETPOINTPOSITION -- -- -- function GetPointPosition (PointIndex, PivotPos) p = lxq("query layerservice vert.pos ? "..PointIndex) -- Getting original coordinates. -- Compensate for pivot position. p[1] = p[1] - PivotPos[1] p[2] = p[2] - PivotPos[2] p[3] = p[3] - PivotPos[3] -- 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 -- -- -- STOREPOINTUV -- -- -- function StorePointUV (PointNum, TargetUVName) lxq("query layerservice vmap_groups ? all") VmapNum = lxq("query layerservice vmap.n ? all")[1] VmapFound = false for i = 0, VmapNum-1 do -- Go through the vertex maps. ActVmapType = lxq("query layerservice vmap.type ? "..i)[1] ActVmapName = lxq("query layerservice vmap.name ? "..i)[1] if ( ActVmapType == "texture") and ( ActVmapName == TargetUVName) then VmapFound = true lxout("Exporting UVMap "..TargetUVName..", Count "..PointNum) lxmonInit(PointNum) for j = 0, (PointNum - 1) do p = lxq("query layerservice vert.vmapValue ? "..j) if p == nil then p = {"0.0000","0.0000"} end -- Failsafe if a vertex doesn't have a UV value. fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..FormatNum(p[1]).."\t"..FormatNum(p[2]).."\t0.0000\n") if lxmonStep() == 0 then error "User break" end end end end if (VmapFound == false) then -- Write 0's for this Vmap if we could not find proper map for j = 0, (PointNum - 1) do p = {"0.0000","0.0000"} fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..FormatNum(p[1]).."\t"..FormatNum(p[2]).."\t0.0000\n") end end end -- -- -- STOREPOINTCOLOR -- -- -- function StorePointColor (PointNum) p = {"0.0000","0.0000","0.0000"} lxq("query layerservice vmap_groups ? all") VmapNum = lxq("query layerservice vmap.n ? all")[1] VmapFound = false for i = 0, VmapNum-1 do -- Go through the vertex maps. ActVmapType = lxq("query layerservice vmap.type ? "..i)[1] ActVmapName = lxq("query layerservice vmap.name ? "..i)[1] if ( ActVmapType == "rgb") and ( ActVmapName == VColName) then lxout("Exporting VColor "..VColName..", Count "..PointNum) VmapFound = true lxmonInit(PointNum) for j = 0, (PointNum - 1) do p = lxq("query layerservice vert.vmapValue ? "..j) --[[if p == nil then p = {"1.0000","1.0000","1.0000"} end -- Failsafe if a vertex doesn't have a color value. fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..FormatNum(p[1]).."\t"..FormatNum(p[2]).."\t"..FormatNum(p[3]).."\n")]]-- if p ~= nil then fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..FormatNum(p[1]).."\t"..FormatNum(p[2]).."\t"..FormatNum(p[3]).."\n") end if lxmonStep() == 0 then error "User break" end end end end if (VmapFound == false) then for j = 0, (PointNum - 1) do p = {"1.0000","1.0000","1.0000"} fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..FormatNum(p[1]).."\t"..FormatNum(p[2]).."\t"..FormatNum(p[3]).."\n") end end 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 -- -- -- PROCESS ARGUMENTS -- -- -- function ProcessArgument(arg) if (arg ~= nil) then arg = string.upper(arg) end -- Make it upper case. if(arg == "GAMEUNITS") then meter_per_gunit = lxq("!pref.value units.gameScale ?") -- Get accurate game units. if meter_per_gunit ~= nil then meter_per_gunit = meter_per_gunit[1] else lxout("WARNING: Can't read game unit preferences! Set the unit system to GameUnits. Using default value for now.") meter_per_gunit = 1 end UnitScale = (1/meter_per_gunit) elseif arg == "METER" then UnitScale = 1 elseif arg == "CENTIMETER" then UnitScale = 100 elseif arg == "MILLIMETER" then UnitScale = 1000 elseif arg == "FEET" then UnitScale = 3.2808398950131 elseif arg == "INCH" then UnitScale = 39.3700787 elseif arg == "SILENTSAVE" then bSilentSave = true end --lxout("UnitScale: "..UnitScale) --lxout("SilentSave: "..tostring(bSilentSave)) end -- -- -- MAIN -- -- -- lxout("------- ASE conversion started. -------") lxout("("..version..")") 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. -- Process arguments: game units and silent save mode -- ProcessArgument(arg[1]) ProcessArgument(arg[2]) -- 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 file paths -- 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 "/". -- 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) -- Optional file dialog -- if bSilentSave then savedir = contentdir fileOutName = savedir.."/"..MainLayerName..".ase" TempFileName = savedir.."/"..MainLayerName.."_"..TempFileName else lx("dialog.setup fileSave") lx("dialog.title [ASE Export - File name]") lx("dialog.result ["..contentdir.."/]") lx("dialog.fileTypeCustom format:[ase] username:[Model to save] loadPattern:[*.ase] saveExtension:[ase]") if lx("dialog.open") == nil then error "User canceled" end fileOutName = lxq("dialog.result ? ") fileOutName = fileOutName[1] TempFileName = fileOutName.."_"..TempFileName lxout("Filename to save "..fileOutName) end StartTime = os.time() -- We start the timer after the possible file requester. -- Continue to collect layer data -- 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] 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. if (i == 1) then -- If its the first layer... NumOfItems = lxq("query sceneservice item.N ?") for j = 0, NumOfItems[1] - 1 do ItemTypeLabel = lxq("query sceneservice item.typeLabel ? "..j) ItemName = lxq("query sceneservice item.name ? "..j) ItemType = lxq("query sceneservice item.type ? "..j) ItemID = lxq("query sceneservice item.id ? "..j) if (ItemType[1] == "mesh" and ItemName[1] == MainLayerName) then -- ...we make sure it is the main layer. PivotPosition = lxq("query sceneservice item.pivPos ? "..ItemID[1]) -- Aquire pivot position. lxout("Pivot position "..PivotPosition[1].." "..PivotPosition[2].." "..PivotPosition[3]) end end end 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 -- 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") 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") SelectLayer(ActLayer) -- Reselect layer to make sure internal data is updated. lx("select.type vertex") 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") lxmonInit(VertexNum) for j = 0, (VertexNum-1) do -- Iterating through the vertices. Pos = GetPointPosition(j, PivotPosition) fileOut:write("\t\t\t*MESH_VERTEX\t"..j.."\t"..Pos[1].."\t"..Pos[2].."\t"..Pos[3].."\n") if lxmonStep() == 0 then error "User Break" end end fileOut:write("\t\t}\n") -- Geometry - Mesh - Face list -- FaceList = {} fileOut:write("\t\t*MESH_FACE_LIST {\n") lxmonInit(FaceNum) for j = 0, (FaceNum-1) do -- Iterating through the faces. FacePoints = GetFacePoints(j) table.insert(FaceList, FacePoints) 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 if lxmonStep() == 0 then error "User Break" 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") StorePointUV(VertexNum, UV1Name) 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 = FaceList[j + 1] 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") StorePointUV(VertexNum, UV2Name) 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 = FaceList[j + 1] 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(UV2Name) then -- If UV2 exists then we bother with writing it to the file. 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") StorePointUV(VertexNum, UV2Name) 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 = FaceList[j + 1] 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 end 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") StorePointUV(VertexNum, UV3Name) 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 = FaceList[j + 1] 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") StorePointColor(VertexNum) 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 = FaceList[j + 1] 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. -------")