![](/img/trans.png)
[英]How to use iOS (Swift) SceneKit SCNSceneRenderer unprojectPoint properly
[英]SceneKit unprojectPoint() with custom camera
我正在使用 SceneKit 為 macOS / iPadOS 開發分子可視化工具。 長話短說,我希望當用戶在某個 position 處單擊(或觸摸)屏幕時,會放置一個新原子(在此示例中只是一個 SCNSphere)。
以前,我激活了 SCNView 的 allowCameraControl 屬性,這使我可以自由移動相機,並且使用 unprojectPoint() 方法,我可以成功地將新節點放置在觸摸位置。 默認相機 controller 的限制是它不能縮放。 當您捏住屏幕時,它會更改相機的 FOV 屬性,而不是通過 Z 軸移動它。
因此,我使用 SCNCamera 制作了一個自定義相機節點。 我成功地重新創建了默認的相機行為(移動、旋轉),而且我能夠正確放大場景。 這樣做的缺點是 unprojectPoint() 方法不再像預期的那樣工作,因為新節點放置在非常接近相機節點本身的 position 處。 無論我點擊場景的哪個位置,那個未投影的點總是非常接近 0、0、10
internal func newNodeAt(point: CGPoint) {
let pointVector = SCNVector3(point.x, point.y, 0.8)
let position = self.unprojectPoint(pointVector)
print("x:\(position.x), y: \(position.y), z: \(position.z)")
let newSphere = SCNSphere(radius: 1)
let newNode = SCNNode(geometry: newSphere)
self.scene?.rootNode.addChildNode(newNode)
}
攝像機節點設置如下,並直接附加到場景根節點。
internal func setupCameraNode() -> SCNNode {
let cam = SCNCamera()
cam.name = "camera"
cam.zFar = 200
cam.zNear = 0.1
let camNode = SCNNode()
camNode.camera = cam
camNode.position = SCNVector3(0, 0, 5)
camNode.name = "Camera node"
return camNode
}
這些是單擊場景的隨機位置后的打印位置。
x:-0.1988764852285385, y: -0.05589345842599869, z: 10.920427322387695
x:-0.18989555537700653, y: 0.14564114809036255, z: 10.920427322387695
x: 0.2168566882610321, y: 0.13085339963436127, z: 10.920427322387695
x: 0.24202580749988556, y: -0.15493911504745483, z: 10.920427322387695
x:-0.06516486406326294, y: -0.1781780868768692, z: 10.920427322387695
x:-0.08134553581476212, y: 0.12478446960449219, z: 10.920427322387695
x:-0.25866374373435974, y: 0.1456427276134491, z: 10.920427322387695
x: 0.217658132314682, y: 0.16270162165164948, z: 10.920427322387695
x: 0.2053154855966568, y: -0.12679903209209442, z: 10.920427322387695
我想 unprojectPoint() 與觀點有關嗎? 但我不知道如何解決這個問題。 謝謝。
我認為你在正確的軌道上,你只需要為用戶提供某種深度參考。 這是我的類似代碼,但是當我調用 airStrike 時,我根據面向用戶的平面處理深度,這就是我知道 Z 需要在哪里的方式。
只是沒有視覺的猜測,但似乎有幾個選擇。 在分子中間創建一個參考平面和 ++/-- 以顯示水龍頭將從深度角度降落的位置。
或者只是讓他們把它放在任何地方,然后是 select 它和 depth++/depth——把它放在正確的 position 中。
@objc func handleTap(recognizer: UITapGestureRecognizer)
{
let location: CGPoint = recognizer.location(in: gameScene)
if(data.isAirStrikeModeOn == true)
{
let projectedPoint = gameScene.projectPoint(SCNVector3(0, 0, 0))
let scenePoint = gameScene.unprojectPoint(SCNVector3(location.x, location.y, CGFloat(projectedPoint.z)))
gameControl.airStrike(position: scenePoint)
}
}
經過幾天的測試,我找到了一種解決方法,現在我可以將節點正確放置在它們應該在的位置。
我的節點樹是這樣的:
因此,我所要做的就是將未投影的 position 從 RootNode(我想是相機從中獲取參考的那個)轉換為 atomNodes,因此:
let unprojected = unprojectPoint(SCNVector3(location.x, location.y, 0.99))
let position = atomNodes.convertPosition(unprojected, from: rootNode)
在我看來,0.99 只是一個不錯的 Z position 用於放置球體。 (更多信息在這里)
我的建議是始終檢查節點樹,因為位置是相對的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.