Zeus Eternal
Zeus Eternal

Reputation: 427

Placing an object in front of camera at Touch Location

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

Upvotes: 4

Views: 1191

Answers (1)

jlsiewert
jlsiewert

Reputation: 3574

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.

Upvotes: 2

Related Questions