Skip to content

obj

stable

Parse and export Wavefront OBJ and MTL files, providing access to vertices, normals, texture coordinates, faces, and material definitions.

use plugin obj::{parse_obj, parse_obj_file, vertex_count, …}
10 functions Graphics
/ filter jk navigate Esc clear
Functions (10)
  1. parse_obj Parse OBJ text into a mesh data table
  2. parse_obj_file Parse an OBJ file from disk
  3. vertex_count Count vertices in a parsed mesh
  4. face_count Count faces in a parsed mesh
  5. parse_mtl Parse MTL material text into a table
  6. normal_count Count normals in a parsed mesh
  7. texcoord_count Count texture coordinates in a parsed mesh
  8. bounding_box Compute axis-aligned bounding box of a mesh
  9. export_obj Serialize mesh data to OBJ text
  10. export_obj_file Write mesh data to an OBJ file on disk

Overview

obj is a self-contained reader and writer for the Wavefront OBJ geometry format and its companion MTL material format, with no external dependencies. Parsing a model returns a plain mesh table with four sections — vertices, normals, texcoords, and faces — so the geometry is ordinary Zolo data you can index, count, transform, and feed back to the exporter. Faces store index triples {v, vt, vn} exactly as written in the file, where -1 marks a component (texture or normal) that was omitted.

Reach for it whenever you need to load a .obj mesh, inspect its size or bounds, read material colors out of a .mtl file, or generate and round-trip OBJ text programmatically. The mental model is: parse with parse_obj / parse_obj_file (or parse_mtl for materials), inspect with the *_count and bounding_box queries, then serialize with export_obj / export_obj_file.

Common patterns

Load a mesh and report its size and extents:

use plugin obj::{parse_obj_file, vertex_count, face_count, bounding_box}

let mesh = parse_obj_file("models/cube.obj")
let bb = bounding_box(mesh)
print("{vertex_count(mesh)} verts, {face_count(mesh)} faces")
print("height: {bb["max_y"] - bb["min_y"]}")

Round-trip a mesh: parse OBJ text, then serialize it straight back out:

use plugin obj::{parse_obj, export_obj}

let mesh = parse_obj("v 0 0 0\nv 1 0 0\nv 0 1 0\nf 1 2 3")
print(export_obj(mesh))

Read a material's diffuse color from MTL text:

use plugin obj::{parse_mtl}

let mats = parse_mtl("newmtl red\nKd 1.0 0.0 0.0\nKs 0.5 0.5 0.5")
let red = mats["red"]
print("diffuse: {red["diffuse_r"]}, {red["diffuse_g"]}, {red["diffuse_b"]}")

Parse OBJ text into a mesh data table

Parses Wavefront OBJ text and returns a table with four sections: vertices (list of {x, y, z}), normals (list of {x, y, z}), texcoords (list of {u, v}), and faces (list of face vertex index triples {v, vt, vn}, where -1 means absent).

use plugin obj::{parse_obj}

let mesh = parse_obj("v 0 0 0\nv 1 0 0\nv 0 1 0\nf 1 2 3")
print("vertices: {mesh["vertices"][0]["x"]}")

Faces preserve the full v/vt/vn index triple; absent components read as -1:

use plugin obj::{parse_obj}

let mesh = parse_obj("v 0 0 0\nvt 0 0\nvn 0 1 0\nf 1/1/1 1/1/1 1/1/1")
let corner = mesh["faces"][0][0]
print("v={corner["v"]} vt={corner["vt"]} vn={corner["vn"]}")

Parse an OBJ file from disk

Reads an OBJ file from the given path and returns the same structure as parse_obj. Errors if the file cannot be read.

use plugin obj::{parse_obj_file, vertex_count, face_count}

let mesh = parse_obj_file("models/cube.obj")
print("verts: {vertex_count(mesh)}, faces: {face_count(mesh)}")

Count vertices in a parsed mesh

Returns the number of vertices in a parsed mesh table. Equivalent to reading the length of data["vertices"].

use plugin obj::{parse_obj_file, vertex_count}

let mesh = parse_obj_file("scene.obj")
print("{vertex_count(mesh)} vertices")

Count faces in a parsed mesh

Returns the number of polygon faces in a parsed mesh table.

use plugin obj::{parse_obj_file, face_count}

let mesh = parse_obj_file("scene.obj")
print("{face_count(mesh)} faces")

Parse MTL material text into a table

Parses Wavefront MTL material text and returns a table keyed by material name. Each entry contains name, diffuse_r/g/b, and specular_r/g/b fields from the Kd and Ks directives.

use plugin obj::{parse_mtl}

let mtl_text = "newmtl red\nKd 1.0 0.0 0.0\nKs 0.5 0.5 0.5"
let mats = parse_mtl(mtl_text)
let red = mats["red"]
print("diffuse r: {red["diffuse_r"]}")

A library can contain several materials; each is keyed by its newmtl name:

use plugin obj::{parse_mtl}

let mats = parse_mtl("newmtl gold\nKd 1.0 0.84 0.0\nnewmtl steel\nKd 0.6 0.6 0.65")
print("gold diffuse_g: {mats["gold"]["diffuse_g"]}")
print("steel diffuse_b: {mats["steel"]["diffuse_b"]}")

Count normals in a parsed mesh

Returns the number of vertex normals in a parsed mesh table.

use plugin obj::{parse_obj_file, normal_count}

let mesh = parse_obj_file("scene.obj")
print("{normal_count(mesh)} normals")

Count texture coordinates in a parsed mesh

Returns the number of texture coordinate pairs (UV) in a parsed mesh table.

use plugin obj::{parse_obj_file, texcoord_count}

let mesh = parse_obj_file("scene.obj")
print("{texcoord_count(mesh)} uvs")

Compute axis-aligned bounding box of a mesh

Computes the axis-aligned bounding box of all vertices in the mesh. Returns {min_x, min_y, min_z, max_x, max_y, max_z}. Useful for centering or scaling a model.

use plugin obj::{parse_obj_file, bounding_box}

let mesh = parse_obj_file("character.obj")
let bb = bounding_box(mesh)
let height = bb["max_y"] - bb["min_y"]
print("model height: {height}")

Use the min/max corners to find the model's center point:

use plugin obj::{parse_obj, bounding_box}

let mesh = parse_obj("v -1 -1 -1\nv 1 1 1")
let bb = bounding_box(mesh)
let cx = (bb["min_x"] + bb["max_x"]) / 2
let cy = (bb["min_y"] + bb["max_y"]) / 2
let cz = (bb["min_z"] + bb["max_z"]) / 2
print("center: {cx}, {cy}, {cz}")

Serialize mesh data to OBJ text

Serializes a mesh data table back to Wavefront OBJ text format. The output includes v, vt, vn, and f lines in the correct order. Use this to generate or modify OBJ files programmatically.

use plugin obj::{parse_obj_file, export_obj}

let mesh = parse_obj_file("input.obj")
let text = export_obj(mesh)
print(text)

Because the exporter consumes the same table shape parse_obj produces, you can build a mesh from text and serialize it back in one pass:

use plugin obj::{parse_obj, export_obj}

let triangle = parse_obj("v 0 0 0\nv 1 0 0\nv 0 1 0\nf 1 2 3")
print(export_obj(triangle))

Write mesh data to an OBJ file on disk

Serializes a mesh data table to OBJ format and writes it directly to the given file path. Errors if the file cannot be written.

use plugin obj::{parse_obj_file, export_obj_file}

let mesh = parse_obj_file("original.obj")
export_obj_file(mesh, "output/copy.obj")
print("exported")
enespt-br