SceneKit:无论您在何处触摸屏幕,unprojectPoint 都会返回相同/相似的点 [英] SceneKit: unprojectPoint returns same/similar point no matter where you touch screen

查看:137
本文介绍了SceneKit:无论您在何处触摸屏幕,unprojectPoint 都会返回相同/相似的点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码应该将触摸坐标转换为 SceneKit 场景的世界坐标.

The code below should translate touch coordinates into world coordinates for a SceneKit scene.

但是,如下面的输出所示,unprojectPoint 返回的点实际上返回相同的点,无论您在屏幕上的哪个位置(iPhone 5s)触摸.

However, as illustrated by the output below, the point returned by unprojectPoint returns effectively the same point no matter where you touch on the screen (iPhone 5s).

unprojectPoint 的类文档建议使用介于 0 和 1 之间的 Z 值,但使用不同的值(如 0.5)不会改变 unprojectPoint 的输出.

The class docs for unprojectPoint suggest using Z values between 0 and 1, but using different values like 0.5 did not change the output for unprojectPoint.

这篇SO帖子讨论了如何设置unprojectPoint 的深度值,但将 Z 值设置为大于 1 的值(例如,15、20)也不会改变输出.

This SO post discusses how to set the depth value for unprojectPoint, but setting the Z value to values greater than 1 (e.g., 15, 20) also did not change the output.

在这两种情况下,从 unprojectPoint 返回的 X 和 Y 值实际上也保持不变.

In both cases, the X and Y values return from unprojectPoint effectively remained the same as well.

1) 使用 unprojectPoint 的正确方法是什么?

1) What is the right way to use unprojectPoint?

2) unprojectPoint 如何解释相机旋转?例如,如果您将相机移动到 (0, 20, 0) 并将相机向下旋转 90 度使其面向地面,您如何确保考虑到旋转?如果您将深度设置为 20 并点击原点,则 unprojectPoint 所需的返回值应为 (0, 0, 0).

2) How does unprojectPoint account for camera rotations? For instance, if you moved the camera to (0, 20, 0) and rotated the camera down 90 degrees so it's facing the ground, how do you ensure the rotation is accounted for? If you set a depth of 20 and tapped on the origin, the desired return value from unprojectPoint should be (0, 0, 0).

3) 如何让 unprojectPoint 返回相机前的值(例如,Z 值低于相机的 Z 值)

3) How do you get unprojectPoint to return values in front of the camera (e.g., Z values are lower than the camera's Z value)

代码:

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)")
}

输出:

二维点:(154.5, 169.5).3D 点:SCNVector3(x: -0.00111810782, y:0.0232769605, z: 7.9000001)

2D point: (154.5, 169.5). 3D point: SCNVector3(x: -0.00111810782, y: 0.0232769605, z: 7.9000001)

二维点:(280.5, 252.0).3D点:SCNVector3(x: 0.0244967155, y: 0.00650534919, z: 7.9000001)

2D point: (280.5, 252.0). 3D point: 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 point: (32.0, 181.0). 3D point: 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 point: (12.0, 505.0). 3D point: SCNVector3(x: -0.0300872531, y: -0.0449275821, z: 7.9000001)

二维点:(311.5, 12.5).3D 点:SCNVector3(x: 0.0307987742, y: 0.0551938377, z: 7.9000001)

2D point: (311.5, 12.5). 3D point: 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 point: (22.5, 88.0). 3D point: SCNVector3(x: -0.0279526841, y: 0.0398452766, z: 7.9000001)

二维点:(313.5, 358.0).3D 点:SCNVector3(x: 0.0312053617, y: -0.0150436237, z: 7.9000001)

2D point: (313.5, 358.0). 3D point: SCNVector3(x: 0.0312053617, y: -0.0150436237, z: 7.9000001)

二维点:(314.0, 507.0).3D点:SCNVector3(x: 0.0313070044, y: -0.0453341678, z: 7.9000001)

2D point: (314.0, 507.0). 3D point: 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)

2D point: (155.0, 360.5). 3D point: SCNVector3(x: -0.00101646129, y: -0.0155518558, z: 7.9000001)

推荐答案

只要您使用 0 和 1,unprojectPoint 的值就会发生变化. 使用 0 作为 Z 值表示近平面同时使用 1 产生远平面上的点.

As long as you use 0 and 1 the values do change for unprojectPoint. Using 0 for the Z value represents the point on the near plane while using 1 yields the point on the far plane.

因此,为了返回距相机任意距离的场景点,我们开发了以下函数.我们是 SceneKit 的新手,所以请提供任何编辑或更正!

So to return a scene point that is an arbitrary distance from the camera, we developed the following function. We are new to SceneKit so please offer any edits or corrections!

实际上,您可以定义近点和远点之间的射线/线,然后沿线选取一些点.

Effectively, you define the ray/line between the near and far points then pick some point along the line.

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
}

这篇关于SceneKit:无论您在何处触摸屏幕,unprojectPoint 都会返回相同/相似的点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆