如何在Lua中读取并解析OBJ文件数据?
Lua 读取OBJ文件并解析顶点与面
以下是实现需求的Lua代码,直接处理OBJ文件的顶点(v行)和面(f行),支持f行的/分割格式:
1. 定义基础数据结构
用Lua table模拟Vector3和Polygon对象:
-- 模拟Vector3结构,存储x/y/z坐标 local function Vector3(x, y, z) return {x = tonumber(x), y = tonumber(y), z = tonumber(z)} end -- 模拟Polygon结构,存储组成面的Vector3列表 local function Polygon(vertices) return {vertices = vertices or {}} end
2. 核心解析逻辑
local function parseObjFile(filePath) local vertices = {} -- 存储所有顶点,索引从1开始(匹配OBJ的编号规则) local polygons = {} -- 存储所有面 -- 打开文件 local file = io.open(filePath, "r") if not file then error("无法打开文件: " .. filePath) end -- 逐行读取处理 for line in file:lines() do -- 去掉首尾空白 line = line:gsub("^%s+", ""):gsub("%s+$", "") if line == "" then goto continue end -- 跳过空行 -- 拆分行为单词列表 local words = {} for word in line:gmatch("%S+") do table.insert(words, word) end local firstWord = words[1] -- 处理顶点行(v开头) if firstWord == "v" then -- 提取x/y/z三个数值,创建Vector3存入vertices local vec = Vector3(words[2], words[3], words[4]) table.insert(vertices, vec) -- 处理面行(f开头) elseif firstWord == "f" then local polyVertices = {} -- 遍历每个顶点引用(从第二个单词开始) for i = 2, #words do local vertexRef = words[i] -- 提取/分割前的顶点编号(OBJ编号从1开始) local vertexIndex = tonumber(vertexRef:match("^%d+")) -- 从vertices中取出对应的Vector3,加入当前面的顶点列表 table.insert(polyVertices, vertices[vertexIndex]) end -- 创建Polygon对象存入polygons table.insert(polygons, Polygon(polyVertices)) end ::continue:: end file:close() return vertices, polygons end
3. 测试示例
假设你的OBJ文件内容如下:
v 4.0 7.0 5.0 v 1.0 5.0 1.0 v 5.0 4.0 2.0 v 6.0 1.0 7.0 f 1 4 f 3 2 f 1/1/1 2/4/1 4/9/1 3/7/1
调用解析函数并输出结果:
local vertices, polygons = parseObjFile("test.obj") -- 打印所有顶点 print("顶点列表:") for i, vec in ipairs(vertices) do print(string.format("Vector%d: (%.1f, %.1f, %.1f)", i, vec.x, vec.y, vec.z)) end -- 打印所有面 print("\n面列表:") for i, poly in ipairs(polygons) do io.write(string.format("第%d个面: ", i)) for j, vec in ipairs(poly.vertices) do io.write(string.format("(%.1f,%.1f,%.1f) ", vec.x, vec.y, vec.z)) end io.write("\n") end
输出结果:
顶点列表: Vector1: (4.0, 7.0, 5.0) Vector2: (1.0, 5.0, 1.0) Vector3: (5.0, 4.0, 2.0) Vector4: (6.0, 1.0, 7.0) 面列表: 第1个面: (4.0,7.0,5.0) (6.0,1.0,7.0) 第2个面: (5.0,4.0,2.0) (1.0,5.0,1.0) 第3个面: (4.0,7.0,5.0) (1.0,5.0,1.0) (6.0,1.0,7.0) (5.0,4.0,2.0)
关键细节说明
- OBJ文件的顶点编号是1-based,所以我们直接用Lua数组的1索引存储,匹配编号规则。
- 处理
f行时,通过^%d+正则提取/之前的顶点编号,忽略纹理坐标、法向量等额外信息(如果需要这些信息,可以扩展正则匹配)。 - 代码包含了空行跳过、文件打开失败的错误处理,保证基本鲁棒性。
内容的提问来源于stack exchange,提问作者TheJalfireKnight
相关产品推荐
相关产品推荐

