为了账号安全,请及时绑定邮箱和手机立即绑定

如何正确使用iOS(Swift)SceneKit SCNSceneRenderer

如何正确使用iOS(Swift)SceneKit SCNSceneRenderer

iOS
繁花如伊 2019-11-29 15:39:49
我正在iOS上使用SceneKit开发一些代码,在我的代码中,我想确定全局z平面上的x和y坐标,其中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}如你看到的。我有一个三角形,该三角形的高度为4个单位,宽为4个单位,并设置在以x,y(0.0,0.0)为中心的z平面(z = 0)上。相机是默认的SCNCamera,它沿负z方向看,我将其放置在(0,0,15)处。zNear和zFar的默认值分别为1.0和100.0。在我的handleTap方法中,我获取水龙头的x和y屏幕坐标,并尝试在z = 0.0的情况下查找x和y全局场景坐标。我正在使用unprojectPoint的电话。unprojectPoint的文档指示取消投影z坐标为0.0的点将返回近裁剪平面上的点;取消投影z坐标为1.0的点将返回远裁剪平面上的点。尽管并没有特别说明,对于两者之间的点,近平面和远平面之间存在线性关系,但我做出了这一假设,并将screenZ的值计算为z =的近平面和远平面之间的距离百分比。 0平面位于。要查看答案,我可以单击三角形的角附近,因为我知道它们在全局坐标中的位置。我的问题是,当我开始更改相机上的zNear和zFar剪切平面时,我没有获得正确的值,也没有获得一致的值。所以我的问题是,我该怎么做?最后,我将创建一个新的几何并将其放置在与用户单击位置相对应的z平面上。在此先感谢您的帮助。
查看完整描述

3 回答

?
白衣染霜花

TA贡献1796条经验 获得超10个赞

3D图形管线中的典型深度缓冲区不是线性的。透视划分导致归一化设备坐标中的深度处于不同的比例。(另请参见此处。)


因此,您要输入的z坐标unprojectPoint实际上并不是您想要的。


那么,如何找到与世界空间中的平面匹配的归一化深度坐标呢?好吧,如果该平面与相机正交(这就是您的相机)是有帮助的。然后,您要做的就是在该平面上投影一个点:


let projectedOrigin = gameView.projectPoint(SCNVector3Zero)

现在,您可以在3D视图+归一化深度空间中找到世界原点的位置。要将2D视图空间中的其他点映射到该平面上,请使用此向量的z坐标:


let vp = gestureRecognizer.locationInView(scnView)

let vpWithZ = SCNVector3(x: vp.x, y: vp.y, z: projectedOrigin.z)

let worldPoint = gameView.unprojectPoint(vpWithZ)

这样可以在世界空间中获得一个点,该点将单击/点击位置映射到z = 0平面,position如果要向用户显示该位置,则适合用作节点的位置。


(请注意,此方法仅在映射到垂直于相机视线方向的平面上才有效。如果要将视线坐标映射到不同方向的表面上,则in中的归一化深度值vpWithZ将不会恒定)


查看完整回答
反对 回复 2019-11-29
?
30秒到达战场

TA贡献1828条经验 获得超6个赞

经过一些实验后,我们开发出了将触摸点投影到场景中给定点任意深度的工具。


您需要进行的修改是计算Z = 0平面与此线的交点,这就是您的观点。


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

}


查看完整回答
反对 回复 2019-11-29
  • 3 回答
  • 0 关注
  • 840 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信