Search code examples
macosscenekit

Center multi-line SCNtext on macOS SceneKit


This code, on macOS Catalina

    scnView.scene = SCNScene()
    scnView.allowsCameraControl = true
    let root = scnView.scene!.rootNode
    let txt = SCNText(string: "This\nis\ncentered", extrusionDepth: 0)
    txt.font = NSFont.init(name: "Helvetica", size: 35)
    txt.string = NSAttributedString(string: "This\nis\ncentered", attributes: [.foregroundColor : NSColor.black])
    txt.flatness = 0.1
    txt.containerFrame = CGRect(origin: .zero, size: CGSize(width: 800, height: 200))
    txt.alignmentMode = CATextLayerAlignmentMode.right.rawValue
    txt.firstMaterial?.diffuse.contents = NSColor.black
    let txtNode = SCNNode(geometry: txt)
    root.addChildNode(txtNode)

Produces this output

enter image description here

Which does not center the lines within the container rectangle.

I looked at this and a few others, and it seems around 2015 this didn't work on iOS, but did work on macOS.

One thing that has changed since 2015 is that the string constant is no longer kCAAlignmentCenterbut CATextLayerAlignmentMode.center.rawValue. I tried right and justified, which are also ignored.


Solution

  • It seems that it's the use of NSAttributedString that breaks the alignment. Removing the following line works as a workaround.

    txt.string = NSAttributedString(string: "This\nis\ncentered", attributes: [.foregroundColor : NSColor.black])
    

    Note that in any case SceneKit will use the SCNMaterial of the geometry to shade the object and won't take NSAttributedString.Key.foregroundColor into account.