了解SCNCamera的非投影坐标

时间:2018-12-27 15:42:21

标签: ios swift 3d opengl-es scenekit

我正在尝试确定SCNCamera的不同Z深度处的世界坐标空间的宽度。据我了解,Z值为0是近平面,而1则是远平面。

再次,我的理解是截头锥体是一个倒置的方形金字塔,其顶点位于SCNCamera。

让我失望的是,我获得的宽度不是线性的,而是随着我接近Z = 1而呈指数形式。对我来说,这与我将视锥作为正方形的心理形状相反金字塔。

这是示例操场代码:

import UIKit
import SceneKit
import PlaygroundSupport

let scene = SCNScene()
let leftCamera = SCNCamera()
let leftCameraNode = SCNNode()

let boxGeometry = SCNBox(width: 10, height: 10, length: 10, chamferRadius: 1.0)
let box = SCNNode(geometry: boxGeometry)
box.position = SCNVector3(0,0,0)
scene.rootNode.addChildNode(box)

scene.rootNode.addChildNode(leftCameraNode)
leftCameraNode.position = SCNVector3(0, 0, 50)
leftCameraNode.eulerAngles = SCNVector3(0, 0, 0)
leftCameraNode.camera = leftCamera

let leftCameraView = SCNView(frame: CGRect(x: 0, y: 0, width: 700, height: 500))
PlaygroundPage.current.liveView = leftCameraView

leftCameraView.scene = scene
leftCameraView.autoenablesDefaultLighting = true
leftCameraView.pointOfView = leftCameraNode

var widths = [CGFloat : Float]()

func widthForDepth(_ depth: CGFloat) {
    let topLeftUnprojectedPoint = leftCameraView.unprojectPoint(SCNVector3(0, 0, depth))
    let topRightUnprojectedPoint = leftCameraView.unprojectPoint(SCNVector3(leftCameraView.bounds.width, 0, depth))
    let width = topRightUnprojectedPoint.x - topLeftUnprojectedPoint.x

    widths[depth] = width
}

widthForDepth(0)
widthForDepth(0.5)
widthForDepth(0.75)
widthForDepth(0.9)
widthForDepth(0.95)
widthForDepth(1)

这使我在不同深度获得了以下值: Z = 0-> 1.61

Z = 0.5-> 3.2

Z = 0.75-> 6.2

Z = 0.9-> 14.8

Z = 0.95-> 27.1

Z = 1-> 161.6

我的理解是Z = 1的这个值是正确的,但是其他值对我来说似乎没有意义。

“我的盒子”的大小为10个单位,适合相机深度值为0.5的屏幕(对于zFar为100且zNear为1的相机,距离为50个单位)。但是,当非投影计算显示屏幕为3.2单位宽(0.5)时,它在屏幕上完全可见。

我知道这是一个简单的问题,但我已经研究了几天,无法解决。

1 个答案:

答案 0 :(得分:0)

好吧,原来我的前提有缺陷。

相机深度(在远平面Z = 1和近平面Z = 0之间测量)与世界Z值不是线性比例。

因此,我发现我需要首先使用projectPoint从摄像机深度确定世界Z值。