SceneKit: unprojectPoint возвращает одну и ту же / похожую точку независимо от того, где вы касаетесь экрана

Приведенный ниже код должен переводить сенсорные координаты в мировые координаты для сцены SceneKit.

Однако, как показано в выходных данных ниже, точка, возвращаемая unprojectPoint эффективно возвращает одну и ту же точку независимо от того, где вы касаетесь экрана (iPhone 5s).

Класс документов для unprojectPoint предложить использовать значения Z в диапазоне от 0 до 1, но использование других значений, таких как 0,5, не изменило вывод для unprojectPoint,

Этот пост SO обсуждает, как установить значение глубины для unprojectPoint, но установка значения Z на значения больше 1 (например, 15, 20) также не изменила выходной сигнал.

В обоих случаях значения X и Y возвращаются из unprojectPoint фактически остался прежним.

1) Как правильно использовать unprojectPoint?

2) Как работает unprojectPoint учитывать повороты камеры? Например, если вы переместили камеру в положение (0, 20, 0) и повернули камеру вниз на 90 градусов, чтобы она была обращена к земле, как вы обеспечиваете учет вращения? Если вы установили глубину 20 и нажали на начало координат, желаемое возвращаемое значение из unprojectPoint должно быть (0, 0, 0).

3) Как вы получаете unprojectPoint возвращать значения перед камерой (например, значения Z ниже значения Z камеры)

Код:

cameraNode.position = SCNVector3(x: 0, y: Float(0), z: Float(8))

func sceneViewTapped(recognizer: UITapGestureRecognizer) {
    let point = recognizer.locationInView(sceneView)
    let unprojectPoint = SCNVector3(x: Float(point.x), y: Float(point.y), z: 0.0)
    let scenePos = sceneView.unprojectPoint(unprojectPoint)
    print("2D point: \(point). 3D point: \(scenePos)")
}

Выход:

2D точка: (154,5, 169,5). 3D-точка: SCNVector3(x: -0.00111810782, y: 0.0232769605, z: 7.9000001)

2D точка: (280,5, 252,0). 3D-точка: SCNVector3(x: 0,0244967155, y: 0,00650534919, z: 7,9000001)

2D точка: (32,0, 181,0). 3D-точка: SCNVector3(x: -0.0260214079, y: 0.0209390987, z: 7.9000001)

2D точка: (12,0, 505,0). 3D-точка: SCNVector3(x: -0.0300872531, y: -0.0449275821, z: 7.9000001)

2D точка: (311,5, 12,5). 3D-точка: SCNVector3(x: 0,0307987742, y: 0,0551938377, z: 7,9000001)

2D точка: (22,5, 88,0). 3D точка: SCNVector3(x: -0,0279526841, y: 0,0398452766, z: 7,9000001)

2D точка: (313,5, 358,0). 3D-точка: SCNVector3(x: 0,0312053617, y: -0,0150436237, z: 7,9000001)

2D точка: (314,0, 507,0). 3D-точка: SCNVector3(x: 0,0313070044, y: -0,0453341678, z: 7,9000001)

2D точка: (155,0, 360,5). 3D-точка: SCNVector3(x: -0.00101646129, y: -0.0155518558, z: 7.9000001)

1 ответ

Решение

Пока вы используете 0 и 1, значения меняются для unprojectPoint. Использование 0 для значения Z представляет точку на ближней плоскости, а использование 1 дает точку на дальней плоскости.

Таким образом, чтобы вернуть точку сцены, которая находится на произвольном расстоянии от камеры, мы разработали следующую функцию. Мы новички в SceneKit, поэтому, пожалуйста, предлагайте любые изменения или исправления!

По сути, вы определяете луч / линию между ближними и дальними точками, а затем выбираете некоторую точку вдоль линии.

private func touchPointToScenePoint(recognizer: UIGestureRecognizer) -> SCNVector3 {
    // Get touch point
    let touchPoint = recognizer.locationInView(sceneView)

    // Compute near & far points
    let nearVector = SCNVector3(x: Float(touchPoint.x), y: Float(touchPoint.y), z: 0)
    let nearScenePoint = sceneView.unprojectPoint(nearVector)
    let farVector = SCNVector3(x: Float(touchPoint.x), y: Float(touchPoint.y), z: 1)
    let farScenePoint = sceneView.unprojectPoint(farVector)

    // Compute view vector
    let viewVector = SCNVector3(x: Float(farScenePoint.x - nearScenePoint.x), y: Float(farScenePoint.y - nearScenePoint.y), z: Float(farScenePoint.z - nearScenePoint.z))

    // Normalize view vector
    let vectorLength = sqrt(viewVector.x*viewVector.x + viewVector.y*viewVector.y + viewVector.z*viewVector.z)
    let normalizedViewVector = SCNVector3(x: viewVector.x/vectorLength, y: viewVector.y/vectorLength, z: viewVector.z/vectorLength)

    // Scale normalized vector to find scene point
    let scale = Float(15)
    let scenePoint = SCNVector3(x: normalizedViewVector.x*scale, y: normalizedViewVector.y*scale, z: normalizedViewVector.z*scale)

    print("2D point: \(touchPoint). 3D point: \(nearScenePoint). Far point: \(farScenePoint). scene point: \(scenePoint)")

    // Return <scenePoint>
    return scenePoint
}
Другие вопросы по тегам