-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobj_loader.py
More file actions
87 lines (64 loc) · 2.92 KB
/
obj_loader.py
File metadata and controls
87 lines (64 loc) · 2.92 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
# obj_loader.py
from typing import List, Tuple
import struct
def load_obj(filepath: str) -> Tuple[bytes, bytes, int]:
"""
Load a .obj file and return vertex/index data for rendering.
Returns:
(vertices_bytes, indices_bytes, vertex_count)
Vertices format: xyzwuv (24 bytes per vertex)
Indices format: u32
"""
vertices: List[Tuple[float, float, float]] = []
uvs: List[Tuple[float, float]] = []
final_vertices: List[Tuple[float, float, float, float, float, float]] = []
indices: List[int] = []
vertex_cache: dict[Tuple, int] = {}
with open(filepath, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split()
if not parts:
continue
if parts[0] == 'v':
x, y, z = float(parts[1]), float(parts[2]), float(parts[3])
vertices.append((x, y, z))
elif parts[0] == 'vt':
u = float(parts[1])
v = float(parts[2]) if len(parts) > 2 else 0.0
uvs.append((u, v))
elif parts[0] == 'vn':
pass # Ignore normals for now
elif parts[0] == 'f':
face_indices = []
for i in range(1, len(parts)):
vertex_data = parts[i].split('/')
v_idx = int(vertex_data[0]) - 1
vt_idx = int(vertex_data[1]) - 1 if len(vertex_data) > 1 and vertex_data[1] else 0
pos = vertices[v_idx]
uv = uvs[vt_idx] if vt_idx < len(uvs) else (0.0, 0.0)
vertex_key = (pos, uv)
if vertex_key not in vertex_cache:
vertex_cache[vertex_key] = len(final_vertices)
final_vertices.append((pos[0], pos[1], pos[2], 1.0, uv[0], uv[1]))
face_indices.append(vertex_cache[vertex_key])
if len(face_indices) == 3:
indices.extend(face_indices)
elif len(face_indices) == 4:
indices.extend([face_indices[0], face_indices[1], face_indices[2]])
indices.extend([face_indices[0], face_indices[2], face_indices[3]])
vertex_bytes = _pack_vertices_xyzwuv(final_vertices)
index_bytes = _pack_indices(indices)
print(f"[OBJ] Loaded {filepath}: {len(final_vertices)} verts, {len(indices) // 3} tris")
return vertex_bytes, index_bytes, len(final_vertices)
def _pack_vertices_xyzwuv(vertices: List[Tuple[float, float, float, float, float, float]]) -> bytes:
blob = bytearray(24 * len(vertices))
offset = 0
for x, y, z, w, u, v in vertices:
struct.pack_into("<6f", blob, offset, x, y, z, w, u, v)
offset += 24
return bytes(blob)
def _pack_indices(indices: List[int]) -> bytes:
return struct.pack(f"<{len(indices)}I", *indices)