7

I am creating a simple app with ARKit in which I add some text to the scene to the tapped position:

@objc func tapped(sender: UITapGestureRecognizer){
    let sceneView = sender.view as! ARSCNView
    let tapLocation = sender.location(in: sceneView)
    let hitTest = sceneView.hitTest(tapLocation, types: .featurePoint)
    if !hitTest.isEmpty{
        self.addTag(tag: "A", hitTestResult: hitTest.first!)
    }
    else{
        print("no match")
    }
}

func addTag(tag: String, hitTestResult: ARHitTestResult){
    let tag = SCNText(string:tag, extrusionDepth: 0.1)
    tag.font = UIFont(name: "Optima", size: 1)
    tag.firstMaterial?.diffuse.contents = UIColor.red

    let tagNode = SCNNode(geometry: tag)

    let transform = hitTestResult.worldTransform
    let thirdColumn = transform.columns.3
    tagNode.position = SCNVector3(thirdColumn.x,thirdColumn.y - tagNode.boundingBox.max.y / 2,thirdColumn.z)
    print("\(thirdColumn.x) \(thirdColumn.y) \(thirdColumn.z)")
    self.sceneView.scene.rootNode.addChildNode(tagNode)
}

It works, but I have problem with the orientation of the text. When I add it with the camera's original position, the text orientation is ok, I can see the text frontwise (Sample 1). But when I turn camera to the left / right, and add the text by tapping, I can see the added text from the side (Sample 2).

Sample 1:

3-D letter from the front

Sample 2:

3-D letter from the side

I know there should be some simple trick to solve it, but as a beginner in this topic I could not find it so far.

jscs
  • 63,694
  • 13
  • 151
  • 195
Tom
  • 3,899
  • 22
  • 78
  • 137
  • What type of behavior are you seeking when placing the text object? Do you want the text to always face the camera as you move around, or do you want it to remain fixed at the orientation when it was first placed? – dbn Nov 02 '17 at 17:10

2 Answers2

7

You want the text to always face the camera? SCNBillboardConstraint is your friend:

tagNode.constraints = [SCNBillboardConstraint()]
rickster
  • 124,678
  • 26
  • 272
  • 326
  • I am facind an issue. I have two SCNNodes that are subchilds of root node from a scene file and when I add a SCNBillboardConstraint programatically to these "text nodes" they just dissapear form the screen. func addBillboardContraintsToText(object: VirtualObject) { guard let storeNode = object.childNodes.first else { return } for node in storeNode.childNodes { if let geometry = node.geometry, geometry.isKind(of: SCNText.self) { node.constraints = [SCNBillboardConstraint()] } } } – Cyupa Mar 07 '18 at 10:31
  • @Cyupa please post a question, not a comment. – rickster Mar 07 '18 at 20:52
  • I've added a question here: https://stackoverflow.com/questions/49194597/adding-a-scnbillboardconstraint-makes-the-node-dissapear – Cyupa Mar 09 '18 at 13:14
4

Am I correct in saying that you want the text to face the camera when you tap (wherever you happen to be facing), but then remain stationary?

There are a number of ways of adjusting the orientation of any node. For this case I would suggest simply setting the eulerAngles of the text node to be equal to those of the camera, at the point in which you instantiate the text.

In your addTag() function you add:

let eulerAngles = self.sceneView.session.currentFrame?.camera.eulerAngles
tagNode.eulerAngles = SCNVector3(eulerAngles.x, eulerAngles.y, eulerAngles.z + .pi / 2)

The additional .pi / 2 is there to ensure the text is in the correct orientation, as the default with ARKit is for a landscape orientation and therefore the text comes out funny. This applies a rotation around the local z axis.

It's also plausible (and some may argue it's better) to use .localRotate() of the node, or to access its transform property, however I like the approach of manipulating both the position and eulerAngles directly.

Hope this helps.

EDIT: replaced Float(1.57) with .pi / 2.

Jordan
  • 481
  • 4
  • 14