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將不會恒定)

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
}
- 3 回答
- 0 關注
- 886 瀏覽
添加回答
舉報