Link Search Menu Expand Document

Reading & writing meshes

MeshIO is pure Swift — no OCCT. It reads STL / OBJ / PLY / glTF / GLB / 3MF / PMX / .x and writes everything except the two source-only formats (PMX, .x), all through the neutral Mesh value type.

Load and inspect

import MeshIO

let mesh = try MeshIO.load(contentsOf: url)        // reader chosen by extension
print(mesh.vertexCount, mesh.triangleCount)
if let (lo, hi) = mesh.bounds { print("bbox:", lo, hi) }

let (a, b, c) = mesh.trianglePositions(0)          // first triangle's three corner positions

MeshIO.load welds coincident vertices on read (default weldEpsilon: 1e-4, restoring connectivity for formats that split vertices at seams). Pass weldEpsilon: 0 to skip welding:

let raw = try MeshIO.load(contentsOf: objURL, weldEpsilon: 0)

glTF / GLB load from the URL (so external .bin buffers resolve relative to it); all other formats read from in-memory Data.

Write

try MeshIO.write(mesh, to: outURL)                       // writer inferred from extension
try MeshIO.write(mesh, to: stlURL, format: .stl, asciiSTL: true)   // ASCII STL (default is binary)

asciiSTL only affects STL output. Writing PMX or .x throws MeshError.unsupported — they are read-only source formats. You can check up front:

if let fmt = MeshFormat(fileExtension: ext), fmt.canWrite {
    try MeshIO.write(mesh, to: outURL, format: fmt)
}
print(MeshIO.readableExtensions)   // ["stl", "obj", "ply", "pmx", "x", "3mf", "gltf", "glb"]

The Mesh value type

public struct Mesh: Equatable, Sendable {
    public var positions: [SIMD3<Float>]
    public var indices: [UInt32]
}

Build one directly, or from a triangle soup:

let welded = Mesh.welded(triangleSoup, epsilon: 1e-4)   // merge coincident corners
let soup   = Mesh.indexedSoup(triangleSoup)             // each corner its own vertex

Calling the format readers directly

The per-format types are public if you have the bytes in hand and want to skip extension dispatch:

let m1 = try STL.read(data: stlData)
let m2 = try OBJ.read(data: objData)
let m3 = try PLY.read(data: plyData)

let stlBytes  = STL.binaryData(mesh)
let stlAscii  = STL.asciiString(mesh)
let objString = OBJ.string(mesh)
let plyString = PLY.string(mesh)