Skip to content

Instantly share code, notes, and snippets.

@hhrhhr
Last active February 16, 2019 21:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hhrhhr/0969a85afce034015b8cd02ac2544477 to your computer and use it in GitHub Desktop.
Save hhrhhr/0969a85afce034015b8cd02ac2544477 to your computer and use it in GitHub Desktop.
Subnautica Below Zero: map export
@echo off
rem edit paths (input and output)
set MESH_DIR=b:\sub
set WORK_DIR=d:\tmp\subnautica\zero_work
set LUA=E:\devel\lua_x64\lua.exe
set LUA_DIR=%~dp0%
:convert
if exist %WORK_DIR%\obj rmdir /q /s %WORK_DIR%\obj
mkdir %WORK_DIR%\obj
pushd %WORK_DIR%\obj
for /r %MESH_DIR% %%i in (*.dat) do (
%LUA% "%LUA_DIR%\mesh2obj.lua" "%%i"
)
popd
:merge
if exist %WORK_DIR%\level rmdir /q /s %WORK_DIR%\level
mkdir %WORK_DIR%\level
pushd %WORK_DIR%\level
for /l %%i in (0 1 24) do (
echo %%i
copy /y "%WORK_DIR%\obj\*-%%i-*.obj" level-%%i.obj
)
popd
:eof
pause
assert(_VERSION == "Lua 5.3")
local function convert(fn)
local r
local su = string.unpack
local function uint16()
local res, _ = su("H", r:read(2))
return res
end
local function uint32()
local res, _ = su("I4", r:read(4))
return res
end
local function str(len)
return r:read(len)
end
local function float()
local res, _ = su("f", r:read(4))
if res ~= res then res = 0.0 end
return res
end
r = assert(io.open(fn, "rb"))
local point = {}
local normal = {}
local face = {}
local sz = uint32()
local name = str(sz)
local tail = sz % 4
if tail > 0 then r:read(4 - tail) end
r:read(8) -- 1, 0
local idxs = uint32()
r:read(12) -- 0, 0, 0
local points = uint32()
-- local center = { float(), float(), float() }
-- local extent = { float(), float(), float() }
r:read(60)
print(("%s\t%d indices, %d points"):format(name, idxs, points))
-- print(("center: %s\nextent: %s"):format(table.concat(center, ", "), table.concat(extent, ", ")))
sz = uint32()
local faces = sz // 6
-- print(("%d faces"):format(faces))
for i = 1, faces do
local f1, f2, f3 = points-uint16(), points-uint16(), points-uint16()
table.insert(face, { f1, f3, f2 })
end
r:read(64)
sz = uint32()
assert(points == sz // 24, "\n\n" .. points .. " != " .. sz // 24 .. "\n\n")
local X, Y, Z
for _x, _y, _z in name:gmatch("-(.+)-(.+)-(.+)") do
X = _x * 32.0
Y = _y * 32.0
Z = _z * -32.0
end
for i = 1, points do
local x, y, z = float() + X, float() + Y, Z - float()
table.insert(point, { x, y, z })
table.insert(normal, { float(), float(), -float() })
end
r:read(16*10+4)
local center2 = { float(), float(), float() }
local extent2 = { float(), float(), float() }
--print(("center: %s\nextent: %s"):format(table.concat(center2, ", "), table.concat(extent2, ", ")))
r:read(4*3)
r:close()
--[[ write OBJ ]]--
fn = name:sub(7) .. ".obj"
local w = assert(io.open(fn, "w+b"))
local fmt = {
head = "#o n_%s\n# %d points, %d faces\n",
point = "v %f %f %f\n",
normal = "vn %f %f %f\n",
group = "g g_%s\ns 1\n",
face = "f -%d//-%d -%d//-%d -%d//-%d\n"
}
w:write(fmt.head:format(name, points, faces))
for i = 1, points do
local p = point[i]
w:write(fmt.point:format(p[1], p[2], p[3]))
end
-- don't export normals, recalculate it the Meshlab
--[[
for i = 1, points do
local n = normal[i]
w:write(fmt.normal:format(n[1], n[2], n[3]))
end
]]
w:write(fmt.group:format(name))
for i = 1, #face do
local f = face[i]
w:write(fmt.face:format(f[1], f[1], f[2], f[2], f[3], f[3]))
end
w:close()
end
convert(arg[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment