Как правильно использовать iOS (Swift) SceneKit SCNSceneRenderer unprojectPoint

Я разрабатываю некоторый код, используя SceneKit для iOS, и в своем коде я хочу определить координаты x и y на глобальной плоскости z, где z равно 0.0, а x и y определяются из жеста касания. МОИ настройки следующие:

    override func viewDidLoad() {
    super.viewDidLoad()

    // create a new scene
    let scene = SCNScene()

    // create and add a camera to the scene
    let cameraNode = SCNNode()
    let camera = SCNCamera()
    cameraNode.camera = camera
    scene.rootNode.addChildNode(cameraNode)
    // place the camera
    cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

    // create and add an ambient light to the scene
    let ambientLightNode = SCNNode()
    ambientLightNode.light = SCNLight()
    ambientLightNode.light.type = SCNLightTypeAmbient
    ambientLightNode.light.color = UIColor.darkGrayColor()
    scene.rootNode.addChildNode(ambientLightNode)

    let triangleNode = SCNNode()
    triangleNode.geometry = defineTriangle();
    scene.rootNode.addChildNode(triangleNode)

    // retrieve the SCNView
    let scnView = self.view as SCNView

    // set the scene to the view
    scnView.scene = scene

    // configure the view
    scnView.backgroundColor = UIColor.blackColor()
    // add a tap gesture recognizer
    let tapGesture = UITapGestureRecognizer(target: self, action: "handleTap:")
    let gestureRecognizers = NSMutableArray()
    gestureRecognizers.addObject(tapGesture)
    scnView.gestureRecognizers = gestureRecognizers
}

func handleTap(gestureRecognize: UIGestureRecognizer) {
    // retrieve the SCNView
    let scnView = self.view as SCNView
    // check what nodes are tapped
    let p = gestureRecognize.locationInView(scnView)
    // get the camera
    var camera = scnView.pointOfView.camera

    // screenZ is percentage between z near and far
    var screenZ = Float((15.0 - camera.zNear) / (camera.zFar - camera.zNear))
    var scenePoint = scnView.unprojectPoint(SCNVector3Make(Float(p.x), Float(p.y), screenZ))
    println("tapPoint: (\(p.x), \(p.y)) scenePoint: (\(scenePoint.x), \(scenePoint.y), \(scenePoint.z))")
}

func defineTriangle() -> SCNGeometry {

    // Vertices
    var vertices:[SCNVector3] = [
        SCNVector3Make(-2.0, -2.0, 0.0),
        SCNVector3Make(2.0, -2.0, 0.0),
        SCNVector3Make(0.0, 2.0, 0.0)
    ]

    let vertexData = NSData(bytes: vertices, length: vertices.count * sizeof(SCNVector3))
    var vertexSource = SCNGeometrySource(data: vertexData,
        semantic: SCNGeometrySourceSemanticVertex,
        vectorCount: vertices.count,
        floatComponents: true,
        componentsPerVector: 3,
        bytesPerComponent: sizeof(Float),
        dataOffset: 0,
        dataStride: sizeof(SCNVector3))

    // Normals
    var normals:[SCNVector3] = [
        SCNVector3Make(0.0, 0.0, 1.0),
        SCNVector3Make(0.0, 0.0, 1.0),
        SCNVector3Make(0.0, 0.0, 1.0)
    ]

    let normalData = NSData(bytes: normals, length: normals.count * sizeof(SCNVector3))
    var normalSource = SCNGeometrySource(data: normalData,
        semantic: SCNGeometrySourceSemanticNormal,
        vectorCount: normals.count,
        floatComponents: true,
        componentsPerVector: 3,
        bytesPerComponent: sizeof(Float),
        dataOffset: 0,
        dataStride: sizeof(SCNVector3))

    // Indexes
    var indices:[CInt] = [0, 1, 2]
    var indexData  = NSData(bytes: indices, length: sizeof(CInt) * indices.count)
    var indexElement = SCNGeometryElement(
        data: indexData,
        primitiveType: .Triangles,
        primitiveCount: 1,
        bytesPerIndex: sizeof(CInt)
    )

    var geo = SCNGeometry(sources: [vertexSource, normalSource], elements: [indexElement])

    // material
    var material = SCNMaterial()
    material.diffuse.contents  = UIColor.redColor()
    material.doubleSided = true
    material.shininess = 1.0;
    geo.materials = [material];

    return geo
}

Как вы видете. У меня есть треугольник, который составляет 4 единицы в высоту и 4 единицы в ширину и установлен на плоскости z (z = 0) с центром в x, y (0.0, 0.0). Камера по умолчанию - SCNCamera, которая смотрит в отрицательном направлении z, и я поместил ее в (0, 0, 15). Значения по умолчанию для zNear и zFar составляют 1,0 и 100,0 соответственно. В моем методе handleTap я беру экранные координаты x и y касания и пытаюсь найти глобальные координаты сцены x и y, где z = 0.0. Я использую вызов unprojectPoint.

Документы для unprojectPoint указывают

Отказ от проекции точки, координата которой равна 0,0, возвращает точку на ближней плоскости отсечения; Отказ от проекции точки, координата которой равна 1,0, возвращает точку на дальней плоскости отсечения.

Хотя в нем конкретно не говорится, что для промежуточных точек существует линейная зависимость между ближней и дальней плоскостями, я сделал это предположение и вычислил значение screenZ как процентное расстояние между ближней и дальней плоскостями, что z = 0 самолет находится. Чтобы проверить мой ответ, я могу щелкнуть около углов треугольника, потому что я знаю, где они находятся в глобальных координатах.

Моя проблема в том, что я не получаю правильные значения и не получаю непротиворечивые значения, когда начинаю изменять плоскости отсечения zNear и zFar на камере. Итак, мой вопрос, как я могу это сделать? В конце я собираюсь создать новый фрагмент геометрии и поместить его в z-плоскость, соответствующую тому, где пользователь щелкнул.

Заранее спасибо за помощь.

Ответы на вопрос(3)

Ваш ответ на вопрос