Mesh
Mesh is the neutral currency of MeshIO: a welded, indexed triangle mesh. Positions are unique and indices holds three vertex indices per triangle. It is a pure Equatable, Sendable value type with no OCCT dependency.
Topics
- Properties ·
Submesh·init(positions:indices:submeshes:)·triangle(_:)/trianglePositions(_:)·bounds·Mesh.welded(_:epsilon:)·Mesh.indexedSoup(_:)
Properties
public struct Mesh: Equatable, Sendable {
public var positions: [SIMD3<Float>]
public var indices: [UInt32]
public var submeshes: [Submesh]
public var vertexCount: Int { positions.count }
public var triangleCount: Int { indices.count / 3 }
}
submeshes is empty for formats/files with no per-material grouping — currently populated only for PMX (see Submesh).
Submesh
One contiguous run of Mesh.indices belonging to a single source-format material — the source format’s own segmentation of the face buffer, so a single part can be isolated from a whole-model mesh.
public struct Submesh: Equatable, Sendable {
public var indexOffset: Int // start of this run in Mesh.indices
public var indexCount: Int // length of this run (always a multiple of 3)
public var materialIndex: Int // index into the source file's material list (0-based, file order)
}
- Example:
let mesh = try MeshIO.load(contentsOf: pmxURL) for sub in mesh.submeshes { // isolate one material's triangles let range = sub.indexOffset ..< sub.indexOffset + sub.indexCount print("material \(sub.materialIndex): \(sub.indexCount / 3) triangles") }
init(positions:indices:submeshes:)
public init(positions: [SIMD3<Float>] = [], indices: [UInt32] = [], submeshes: [Submesh] = [])
- Parameters:
positions— unique vertex positions;indices— three vertex indices per triangle;submeshes— per-material index ranges. All default to empty.
triangle(_:) / trianglePositions(_:)
public func triangle(_ t: Int) -> (UInt32, UInt32, UInt32)
public func trianglePositions(_ t: Int) -> (SIMD3<Float>, SIMD3<Float>, SIMD3<Float>)
- Returns:
trianglereturns the three vertex indices of trianglet;trianglePositionsreturns the three corner positions. - Example:
for t in 0..<mesh.triangleCount { let (a, b, c) = mesh.trianglePositions(t) // ... use the three corner positions }
bounds
public var bounds: (min: SIMD3<Float>, max: SIMD3<Float>)? { get }
- Returns: the axis-aligned bounding box as
(min, max), ornilfor an empty mesh.
Mesh.welded(_:epsilon:)
Merges coincident vertices by quantizing positions to a grid of size epsilon — restores connectivity in formats that split vertices at seams.
public static func welded(_ soup: [SIMD3<Float>], epsilon: Float) -> Mesh
- Parameters:
soup— a flat triangle soup (3 positions per triangle);epsilon— the weld grid size. - Returns: an indexed
Meshwith coincident corners merged. - Example:
let mesh = Mesh.welded(triangleSoup, epsilon: 1e-4)
Mesh.indexedSoup(_:)
Indexes a triangle soup without welding — each corner becomes its own vertex.
public static func indexedSoup(_ soup: [SIMD3<Float>]) -> Mesh
- Parameters:
soup— a flat triangle soup. - Returns: a
Meshwith one vertex per input corner.