Skip to content

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 nameobj
Extensions.obj
Read / Write✓ / ✓
Extra dependencies—

Reading & writing ​

The native row parser views the live trimmed input row rather than copying it first; result arrays/group names remain owned. See the source-copy evidence, including the retained unfavorable writer observation; no writer speedup is claimed.

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 after v are 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 new g line appears.
  • g <name> — starts a new group and increments a running group-id counter (starting at -1, so faces before any g get 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 any vn lines were seen.
  • point_data["obj:vt"] — texture coordinates, present only if any vt lines were seen.
  • cell_data["obj:group_ids"] — one int array per cell block, the g-index that produced that block (-1 if before the first g).

Quirks & limitations ​

  • The /vt//vn per-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-vertex vn/vt blocks.
  • A new g line 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/python/meshes/obj/elephav.obj — a real triangle-mesh scan (vertex-only v lines plus f triangle lines).
  • Fully handled by the C++ core.

Released under the MIT License.