Lab 059 – Extruding a Mesh from a Shape
I was so excited to see this added at WWDC 2024. Too bad it took me a year to try it!
Maybe this year we’ll get some new mesh creation options. I’d love a Lathe.
We can convert a 2D path into an extruded mesh that we can use on a Model Component or Model Entity.
Basics:
let somePath // assume this is set to a Path
// Create some options
var options = MeshResource.ShapeExtrusionOptions()
options.extrusionMethod = .linear(depth: 0.5)
// Create the mesh resource
guard let mesh = try? await MeshResource(extruding: somePath, extrusionOptions: options) else { return }
// Use the mesh to create an Model Entity
let subject = ModelEntity(mesh: mesh, materials: [material])Full Lab Code
struct Lab059: View {
@State private var extrusionDepth: Float = 0.01
var body: some View {
RealityView { content in
// Create the 3D extruded shape
var options = MeshResource.ShapeExtrusionOptions()
options.extrusionMethod = .linear(depth: extrusionDepth)
guard let mesh = try? await MeshResource(extruding: simplePath(), extrusionOptions: options) else { return }
// Set up an entity and add it to the scene.
var material = PhysicallyBasedMaterial()
material.baseColor = .init(tint: .stepGreen)
let subject = ModelEntity(mesh: mesh, materials: [material])
subject.name = "Subject"
subject.orientation = .init(angle: .pi / 4, axis: [0, 1, 0])
content.add(subject)
} update: { content in
// Update the extrusion depth when it changes
if let subject = content.entities.first?.findEntity(named: "Subject") {
var options = MeshResource.ShapeExtrusionOptions()
options.extrusionMethod = .linear(depth: extrusionDepth)
Task {
// Get the existing model component from the subject and replace the mesh with a new one using the
if let newMesh = try? await MeshResource(extruding: simplePath(), extrusionOptions: options) {
if var modelComponent = subject.components[ModelComponent.self] {
modelComponent.mesh = newMesh
subject.components.set(modelComponent)
}
}
}
}
}
.task {
// Animate the value of extrusionDepth over time in a sequence
// Note: it would be great if we could animate values with Timeline in Reality Composer Pro
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 second
let startTime = Date()
let duration: TimeInterval = 2.0
let min: Float = 0.01
let max: Float = 0.5
while true {
let elapsed = Date().timeIntervalSince(startTime)
let cycleTime = elapsed.truncatingRemainder(dividingBy: 7.0) // 7 second cycle
if cycleTime < 1.0 {
extrusionDepth = min
} else if cycleTime < 3.0 {
let progress = (cycleTime - 1.0) / duration
extrusionDepth = min + Float(progress) * (max - 0.01)
} else if cycleTime < 4.0 {
extrusionDepth = max
} else if cycleTime < 6.0 {
let progress = (cycleTime - 4.0) / duration
extrusionDepth = max - Float(progress) * (max - 0.01)
} else {
extrusionDepth = min
}
try? await Task.sleep(nanoseconds: 1_000_000_000 / 60) // 60 FPS
}
}
}
func simplePath() -> Path {
let rect = CGRect(x: -0.1, y: -0.1, width: 0.2, height: 0.2)
var path = Path()
path.move(to: CGPoint(x: rect.midX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
return path
}
}Support our work so we can continue to bring you new examples and articles.

Follow Step Into Vision