RealityKit Basics: 3D Text
We can generate 3D text from an attributed string and some configuration options.
Overview
When we covered creating shapes there was something we left out. In addition to the preset shapes like cubes and spheres, we can also generate text. This takes a bit more work to set up, but the results can add a little something extra to our apps.
We’ll build this up in a handful of steps. Let’s start with an AttributedString.
var textString = AttributedString("visinoOS")
textString.font = .systemFont(ofSize: 12.0)If needed, we can specify additional attributes to merge in.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
textString.mergeAttributes(AttributeContainer([.paragraphStyle: paragraphStyle]))Next we’ll build a simple 2D layout for the text using MeshResource.GenerateTextOptions. This will create a 100 by 50 layout, with the text offset by -50 and -25. Text draws from the top left corner of this box so this will help to center it in the container.
var textOptions = MeshResource.GenerateTextOptions()
textOptions.containerFrame = CGRect(x: -50, y: -25, width: 100, height: 50)The next piece we need is MeshResource.ShapeExtrusionOptions. This is where we define some 3D attributes like extrusion depth and chamfer. We can also assign materials to each faced of the 3D text mesh that we’ll create. These numbers are index values from the array of materials that we provide to ModelEntity.
var extrusionOptions = MeshResource.ShapeExtrusionOptions()
extrusionOptions.extrusionMethod = .linear(depth: 2)
extrusionOptions.chamferRadius = 0.1
extrusionOptions.materialAssignment = .init(front: 0, back: 0, extrusion: 1, frontChamfer: 2, backChamfer: 2)Bring it all together by creating a Mesh Resource with our string and options.
let textMesh = try! MeshResource(extruding: textString,
textOptions: textOptions,
extrusionOptions: extrusionOptions)Finally, we’ll create an entity using the Mesh Resource and an array of Materials.
let mat1 = SimpleMaterial(color: .stepBackgroundPrimary, roughness: 0.2, isMetallic: false)
let mat2 = SimpleMaterial(color: .stepGreen, roughness: 0.2, isMetallic: false)
let mat3 = SimpleMaterial(color: .black, roughness: 0.2, isMetallic: false)
return ModelEntity(mesh: textMesh, materials: [mat1, mat2, mat3])Spend some time playing with the different options. The three areas we can control are the attributed text, the layout, and the extrusion options.
Video Demo
Example Code
struct Example136: View {
var body: some View {
RealityView { content in
let entity = makeTextEntity(title: "visionOS")
spinSubject(entity: entity)
content.add(entity)
}
.realityViewLayoutBehavior(.centered)
}
func makeTextEntity(title: String) -> ModelEntity {
let mat1 = SimpleMaterial(color: .stepBackgroundPrimary, roughness: 0.2, isMetallic: false)
let mat2 = SimpleMaterial(color: .stepGreen, roughness: 0.2, isMetallic: false)
let mat3 = SimpleMaterial(color: .black, roughness: 0.2, isMetallic: false)
// Create an AttributedString, set the font, and merge any attributes
var textString = AttributedString(title)
textString.font = .systemFont(ofSize: 12.0)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
textString.mergeAttributes(AttributeContainer([.paragraphStyle: paragraphStyle]))
// Generate some Text Options. We'll make a small rectangle
var textOptions = MeshResource.GenerateTextOptions()
textOptions.containerFrame = CGRect(x: -50, y: -25, width: 100, height: 50)
// Set up our extrusion options. Here we'll set a depth and chamfer. We can also assign material indexes to each face.
var extrusionOptions = MeshResource.ShapeExtrusionOptions()
extrusionOptions.extrusionMethod = .linear(depth: 2)
extrusionOptions.chamferRadius = 0.1
// These are the indexes of the materals array that we'll bass to ModelEntity
extrusionOptions.materialAssignment = .init(front: 0, back: 0, extrusion: 1, frontChamfer: 2, backChamfer: 2)
// Bring it all together by creating a Mesh Resource with our string and options.
let textMesh = try! MeshResource(extruding: textString,
textOptions: textOptions,
extrusionOptions: extrusionOptions)
// Create an entity with the mesh resource and an array of materials
return ModelEntity(mesh: textMesh, materials: [mat1, mat2, mat3])
}
func spinSubject(entity: Entity) {
Task {
let action = SpinAction(revolutions: 0.5,
localAxis: [0, 1, 0],
timingFunction: .easeInOut,
isAdditive: false)
let animation = try AnimationResource.makeActionAnimation(for: action,
duration: 3,
bindTarget: .transform
,repeatMode: .autoReverse)
entity.playAnimation(animation)
}
}
}Download the Xcode project with this and many more examples from Step Into Vision.
Some examples are provided as standalone Xcode projects. You can find those here.


Follow Step Into Vision