This was very rapidly written to provide a simple interface for loading .obj
files in zig.
At this time I make no garauntees on correctness or performance, will eventually support all .obj and .mtl directives.
To load an obj,
const obj_loader = @import("path/to/obj_loader.zig");
var contents: ObjContents = obj_loader.loadObj("suzanne.obj", your.favorite.allocator);
defer contents.deinit();
Transforming a mesh into your vertex/model format should be quite easy.
const mesh = fileContents.meshes.items[0];
try vertices.ensureTotalCapacity(mesh.v_faces.items.len * 4);
for (mesh.v_faces.items) |face| {
var i: u32 = 0;
while (i < face.count) : (i += 1) {
const p = mesh.v_positions.items[face.vertex[i] - 1];
const n = mesh.v_normals.items[face.normal[i] - 1];
const v = Vertex{
.position = .{ .x = p.x, .y = p.y, .z = p.z },
.normal = .{ .x = n.x, .y = n.y, .z = n.z },
.color = .{ .r = n.x, .g = n.y, .b = n.z, .a = 1.0 },
};
try vertices.append(v);
}
}
The ObjContents contains a list of ObjMesh objects.
std.debug.print("obj: {s}, Vertices count = {d} Normals count = {d}, faces = {d}\n", .{
contents.meshes.items[0].object_name,
contents.meshes.items[0].v_positions.items.len,
contents.meshes.items[0].v_normals.items.len,
contents.meshes.items[0].v_faces.items.len,
});
pub const ObjMesh = struct {
object_name: []u8,
v_positions: ArrayListUnmanaged(ObjVec) = .{},
v_colors: ArrayListUnmanaged(ObjColor) = .{},
v_normals: ArrayListUnmanaged(ObjVec) = .{},
v_textures: ArrayListUnmanaged(ObjVec2) = .{},
v_faces: ArrayListUnmanaged(ObjFace) = .{},
...
}
The faces produced by this library are currently coded to a maximum of 4. If you want more advanced
n-gon triangulation, give zmesh
a try.
pub const ObjFace = struct {
vertex: [4]u32,
texture: [4]u32,
normal: [4]u32,
count: u32,
};