- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobj_parser.py
More file actions
Latest commit
125 lines (116 loc) · 4.91 KB
/
Copy pathobj_parser.py
File metadata and controls
125 lines (116 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
importos
defload_obj(filepath):
"""
Load a Wavefront OBJ file.
Returns a dict with keys:
vertices: list of (x, y, z) tuples
texcoords: list of (u, v) tuples
normals: list of (nx, ny, nz) tuples
faces: list of dict with keys "verts": tuple of vertex indices (0-based),
"vt": tuple of texcoord indices or None,
"vn": tuple of normal indices or None,
"material": material name string
materials: set of material names used
material_textures: dict mapping material name -> texture file path (or None)
"""
vertices= []
texcoords= []
normals= []
faces= []
materials=set()
material_textures= {}
current_material=None
# Determine directory of obj file for resolving relative paths
obj_dir=os.path.dirname(os.path.abspath(filepath))
defparse_face_vertex(v):
# v is a string like "1", "1/1", "1//1", "1/1/1"
parts=v.split('/')
v_idx=int(parts[0]) -1ifparts[0] elseNone
vt_idx=int(parts[1]) -1iflen(parts) >1andparts[1] elseNone
vn_idx=int(parts[2]) -1iflen(parts) >2andparts[2] elseNone
return (v_idx, vt_idx, vn_idx)
withopen(filepath, 'r', encoding='utf-8') asf:
forlineinf:
line=line.strip()
ifnotlineorline.startswith('#'):
continue
parts=line.split()
ifnotparts:
continue
ifparts[0] =='v': # vertex
vertices.append(tuple(map(float, parts[1:4])))
elifparts[0] =='vt': # texture coordinate
texcoords.append(tuple(map(float, parts[1:3])))
elifparts[0] =='vn': # normal
normals.append(tuple(map(float, parts[1:4])))
elifparts[0] =='f': # face
# Expect at least 3 vertices
verts= []
vts= []
vns= []
forcompinparts[1:]:
v_idx, vt_idx, vn_idx=parse_face_vertex(comp)
verts.append(v_idx)
vts.append(vt_idx)
vns.append(vn_idx)
# Triangulate by fan (first vertex)
iflen(verts) >=3:
base_v, base_vt, base_vn=verts[0], vts[0], vns[0]
foriinrange(1, len(verts)-1):
faces.append({
"verts": (base_v, verts[i], verts[i+1]),
"vt": (base_vt, vts[i], vts[i+1]) ifany(visnotNoneforvin (base_vt, vts[i], vts[i+1])) elseNone,
"vn": (base_vn, vns[i], vns[i+1]) ifany(visnotNoneforvin (base_vn, vns[i], vns[i+1])) elseNone,
"material": current_material
})
# If less than 3 vertices, ignore
elifparts[0] =='usemtl':
current_material=parts[1]
materials.add(current_material)
elifparts[0] =='mtllib':
mtl_file=parts[1]
mtl_path=os.path.join(obj_dir, mtl_file)
ifos.path.isfile(mtl_path):
parse_mtl(mtl_path, material_textures)
# ignore other lines
return {
'vertices': vertices,
'texcoords': texcoords,
'normals': normals,
'faces': faces,
'materials': materials,
'material_textures': material_textures
}
defparse_feature(v):
parts=v.split('/')
v_idx=int(parts[0]) -1ifparts[0] elseNone
vt_idx=int(parts[1]) -1iflen(parts) >1andparts[1] elseNone
vn_idx=int(parts[2]) -1iflen(parts) >2andparts[2] elseNone
return (v_idx, vt_idx, vn_idx)
defparse_mtl(mtl_path, material_textures):
"""
Parse an MTL file to extract texture maps (map_Kd) for each material.
Updates material_textures dict in-place.
"""
current_material=None
withopen(mtl_path, 'r', encoding='utf-8') asf:
forlineinf:
line=line.strip()
ifnotlineorline.startswith('#'):
continue
parts=line.split()
ifnotparts:
continue
ifparts[0] =='newmtl':
current_material=parts[1]
# Ensure entry exists
ifcurrent_materialnotinmaterial_textures:
material_textures[current_material] =None
elifparts[0] =='map_Kd'andcurrent_materialisnotNone:
# texture filename (may have options like -bm etc.)
# Assume last token is the filename
tex_name=parts[-1]
# Build absolute path
tex_path=os.path.join(os.path.dirname(os.path.abspath(mtl_path)), tex_name)
material_textures[current_material] =tex_path
# ignore other properties