4
votes

The following code places the node in front of the camera but always at the center 10cm away from the camera position. I want to place the node 10cm away in z-direction but at the x and y co-ordinates of where I touch the screen. So touching on different parts of the screen should result in a node being placed 10cm away in front of the camera but at the x and y location of the touch and not always at the center.

    var cameraRelativePosition = SCNVector3(0,0,-0.1)
    let sphere = SCNNode()
    sphere.geometry = SCNSphere(radius: 0.0025)
    sphere.geometry?.firstMaterial?.diffuse.contents = UIColor.white      
    Service.addChildNode(sphere, toNode: self.sceneView.scene.rootNode,    
    inView: self.sceneView, cameraRelativePosition:  
    cameraRelativePosition)

Service.swift

class Service: NSObject {

  static func addChildNode(_ node: SCNNode, toNode: SCNNode, inView:     
  ARSCNView, cameraRelativePosition: SCNVector3) {

    guard let currentFrame = inView.session.currentFrame else { return }
    let camera = currentFrame.camera
    let transform = camera.transform
    var translationMatrix = matrix_identity_float4x4
    translationMatrix.columns.3.x = cameraRelativePosition.x
    translationMatrix.columns.3.y = cameraRelativePosition.y
    translationMatrix.columns.3.z = cameraRelativePosition.z
    let modifiedMatrix = simd_mul(transform, translationMatrix)
    node.simdTransform = modifiedMatrix
    toNode.addChildNode(node)
  }
}

The result should look exactly like this : https://justaline.withgoogle.com

1

1 Answers

2
votes

We can use the unprojectPoint(_:) method of SCNSceneRenderer (SCNView and ARSCNView both conform to this protocol) to convert a point on the screen to a 3D point. When tapping the screen we can calculate a ray this way:

func getRay(for point: CGPoint, in view: SCNSceneRenderer) -> SCNVector3 {
    let farPoint  = view.unprojectPoint(SCNVector3(Float(point.x), Float(point.y), 1))
    let nearPoint = view.unprojectPoint(SCNVector3(Float(point.x), Float(point.y), 0))

    let ray = SCNVector3Make(farPoint.x - nearPoint.x, farPoint.y - nearPoint.y, farPoint.z - nearPoint.z)

    // Normalize the ray
    let length = sqrt(ray.x*ray.x + ray.y*ray.y + ray.z*ray.z)

    return SCNVector3Make(ray.x/length, ray.y/length, ray.z/length)
}

The ray has a length of 1, so by multiplying it by 0.1 and adding the camera location we get the point you were searching for.