Contents

LowLevelMesh

A container for vertex data that you can use to create and update meshes using your own format.

Declaration

@MainActor class LowLevelMesh

Mentioned in

Overview

Use LowLevelMesh when you want to bring your own vertex format to RealityKit or update your data frequently. To update your data in LowLevelMesh, you can either use Swift for CPU processing, or Metal Compute Shaders for GPU processing.

Express your vertex by creating a LowLevelMesh.Descriptor that describes your layout, along with the required index and vertex capacities. This descriptor is similar to MTLVertexDescriptor, with additional semantics that make the data available in your shaders.

To use LowLevelMesh, first define your own vertex structure, either in a Metal header or using a Swift structure:

struct MyVertex {
    var position: SIMD3<Float> = .zero
    var color: UInt32 = .zero
}

Next, describe your structure to LowLevelMesh by creating a list of vertex attributes and a vertex layout. This description informs LowLevelMesh how to represent the vertex data in memory:

extension MyVertex {
    static var vertexAttributes: [LowLevelMesh.Attribute] = [
        .init(semantic: .position, format: .float3, offset: MemoryLayout<Self>.offset(of: \.position)!),
        .init(semantic: .color, format: .uchar4Normalized_bgra, offset: MemoryLayout<Self>.offset(of: \.color)!)
    ]

    static var vertexLayouts: [LowLevelMesh.Layout] = [
        .init(bufferIndex: 0, bufferStride: MemoryLayout<Self>.stride)
    ]

    static var descriptor: LowLevelMesh.Descriptor {
        var desc = LowLevelMesh.Descriptor()
        desc.vertexAttributes = MyVertex.vertexAttributes
        desc.vertexLayouts = MyVertex.vertexLayouts
        desc.indexType = .uint32
        return desc
    }
}

Create a LowLevelMesh.Descriptor and LowLevelMesh, and assign your mesh data and parts:

func triangleMesh() throws -> LowLevelMesh {
    var desc = MyVertex.descriptor
    desc.vertexCapacity = 3
    desc.indexCapacity = 3

    let mesh = try LowLevelMesh(descriptor: desc)

    mesh.withUnsafeMutableBytes(bufferIndex: 0) { rawBytes in
        let vertices = rawBytes.bindMemory(to: MyVertex.self)
        vertices[0] = MyVertex(position: [-1, -1, 0], color: 0xFF00FF00)
        vertices[1] = MyVertex(position: [ 1, -1, 0], color: 0xFFFF0000)
        vertices[2] = MyVertex(position: [ 0,  1, 0], color: 0xFF0000FF)
    }

    mesh.withUnsafeMutableIndices { rawIndices in
        let indices = rawIndices.bindMemory(to: UInt32.self)
        indices[0] = 0
        indices[1] = 1
        indices[2] = 2
    }

    let meshBounds = BoundingBox(min: [-1, -1, 0], max: [1, 1, 0])
    mesh.parts.replaceAll([
        LowLevelMesh.Part(
            indexCount: 3,
            topology: .triangle,
            bounds: meshBounds
        )
    ])

    return mesh
}

To finish, create a MeshResource from the LowLevelMesh, and add it to a ModelComponent. You can then add this model to any Entity in your scene:

func triangleEntity() throws -> Entity {
    let lowLevelMesh = try triangleMesh()
    let resource = try MeshResource(from: lowLevelMesh)

    let modelComponent = ModelComponent(mesh: resource, materials: [UnlitMaterial()])

    let entity = Entity()
    entity.name = "Triangle"
    entity.components.set(modelComponent)
    entity.scale *= 0.1
    return entity
}

The low-level mesh creates a triangular shape in your RealityKit scene:

[Image]

The MeshResource retains a reference to the LowLevelMesh, reflecting any changes when the renderer updates.

Topics

Creating a low-level mesh

Describing a low-level mesh

Accessing mesh data on the CPU with Swift

Accessing mesh data on the GPU with Metal

Structures

Enumerations

See Also

Updatable meshes