1

I have an SCNText which I display in AR app, But I'd like certain words to be a different colour.

I've tried doing the following: How to change colour of the certain words in label - Swift 3 but NSString and labels are different to SCN (of course), so that did not work.

Below is my current code showing what I am doing:

func addARWords(_ words: String) {

    let scene = SCNScene()
    var highlightedWords = [String]() 

    textGeometry = SCNText(string: words, extrusionDepth: 1.0)
    textGeometry.font = UIFont(name: "Arial", size: 10)
    textGeometry.flatness = 0.2

    textNode = SCNNode(geometry: textGeometry)
    textNode.position = SCNVector3(myTextPosition.x, myTextPosition.y, myTextPosition.z)
    textNode.scale = SCNVector3(myTextScale,  myTextScale, myTextScale)
    scene.rootNode.addChildNode(textNode)
    sceneView.scene = scene
}
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220

1 Answers1

2

Mono-object Text

SCNText() class helps you create a 3D mono-object-text, hence you cannot separately access each character inside it (at the moment API doesn't allow you have access to each character). Instead you might use a texture to paint a whole object:

let text = scene.rootNode.childNode(withName: "text node", recursively: true)!
text.geometry?.materials.first?.diffuse.contents = UIImage(named: "rainbow.jpg")

enter image description here

enter image description here

But you'll get a texture's artifacts on side faces of SCNText object.

Solution:

So there are two possible approaches to use different textures on different characters in 3D text:

  • Use 3D text created in 3D package (such as Maya, 3dsMax, Cinema4D, Houdini, Blender) with hand-made UV-mapped textures.

  • Or, if you prefer SceneKit, use words, containing separate SCNText characters, each one with a desired texture. So you have to parent several separate SCNText elements to one ParentNode to move, rotate and scale it as a merged group.

Multi-object Text

In case you wanna use simple color mapping (not a texture) – use my code:

func addARWords(_ word01: String, _ word02: String, _ word03: String) {
        
    let textGeometry01 = SCNText(string: word01, extrusionDepth: 1.0)
    textGeometry01.font = NSFont(name: "Arial", size: 10)
    textGeometry01.flatness = 0.2
    textGeometry01.firstMaterial?.diffuse.contents = UIColor.yellow
    let textNode01 = SCNNode(geometry: textGeometry01)
        
    let textGeometry02 = SCNText(string: word02, extrusionDepth: 1.0)
    textGeometry02.font = NSFont(name: "Arial", size: 10)
    textGeometry02.flatness = 0.2
    textGeometry02.firstMaterial?.diffuse.contents = UIColor.brown
    let textNode02 = SCNNode(geometry: textGeometry02)
    textNode02.position.x = 7
        
    let textGeometry03 = SCNText(string: word03, extrusionDepth: 1.0)
    textGeometry03.font = NSFont(name: "Arial", size: 10)
    textGeometry03.flatness = 0.2
    textGeometry03.firstMaterial?.diffuse.contents = UIColor.blue
    let textNode03 = SCNNode(geometry: textGeometry03)
    textNode03.position.x = 14
        
    let groupNode = SCNNode()
    groupNode.addChildNode(textNode01)
    groupNode.addChildNode(textNode02)
    groupNode.addChildNode(textNode03)

    scene.rootNode.addChildNode(groupNode)
        
    groupNode.scale = SCNVector3(x: 2, y: 2, z: 2)
}

addARWords("A", "R", "Kit")

enter image description here

And in case you wanna use Not-UV-mapped texture – add this code:

textGeometry01.firstMaterial?.diffuse.contents = UIImage(named: "rainbow.jpg")
textGeometry02.firstMaterial?.diffuse.contents = UIImage(named: "leopard.jpg")
textGeometry03.firstMaterial?.diffuse.contents = UIImage(named: "zebra.jpg")

enter image description here

Community
  • 1
  • 1
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • 1
    Thank you for the detailed reply! Im going to attempt it soon, you have been a big help! I was looking into the idea of having multiple nodes to do it, but wasn't to sure on how to execute it, your code is simple and a nice explanation on the matter. Thanks again! – Jahan Ulhaque Jun 24 '19 at 16:55