Wavefront OBJ (.obj)
The Wavefront OBJ geometry format: a line-oriented ASCII format with v (vertices), vt/vn (texture/normal coordinates), f (faces) and g (groups).
| Format name | obj |
| Extensions | .obj |
| Read / Write | ✓ / ✓ |
| Extra dependencies | — |
Reading & writing
python
import meshioplusplus
mesh = meshioplusplus.read("model.obj")
meshioplusplus.obj.write("out.obj", mesh)write takes no keyword arguments.
File structure
Blank/#-comment lines are skipped.
v x y z— a point row (all tokens aftervare parsed as floats; extra columns are simply appended, not rejected).vn .../vt ...— vertex normal / texture-coordinate rows (arbitrary column count, stored raw).s 1/s off— smooth-shading toggle, ignored.f i1[/t1[/n1]] i2/... ...— a face; only the part before the first/of each token is used as the vertex index (1-based). All faces in a "run" must have the same vertex count; the run breaks (opening a new cell block) as soon as the count changes, or a newgline appears.g <name>— starts a new group and increments a running group-id counter (starting at -1, so faces before anygget group id -1). Only the group's running id is kept — the name string itself is not stored.- Any other keyword is silently ignored.
Empty trailing groups (e.g. a g line with no faces after it) are dropped after the full file is scanned.
Cell types
Faces are grouped by vertex count into triangle (3), quad (4), or polygon (else).
Data mapping
point_data["obj:vn"]— vertex normals, present only if anyvnlines were seen.point_data["obj:vt"]— texture coordinates, present only if anyvtlines were seen.cell_data["obj:group_ids"]— one int array per cell block, theg-index that produced that block (-1if before the firstg).
Quirks & limitations
- The
/vt//vnper-face index references (e.g.f 1/2/3) are discarded entirely — only the leading vertex index survives; there is no per-face UV/normal index array, only the flat per-vertexvn/vtblocks. - A new
gline always starts a fresh cell block, even if the vertex count is unchanged from the previous group — group boundaries and vertex- count changes both independently trigger a new block.
Notes
tests/meshes/obj/elephav.obj— a real triangle-mesh scan (vertex-onlyvlines plusftriangle lines).- Fully handled by the C++ core.