簡體   English   中英

帶有自定義相機的 SceneKit unprojectPoint()

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM