【问题标题】:SceneKit SCNLookAtConstraint not impacting orientationSceneKit SCNLookAtConstraint 不影响方向
【发布时间】:2021-08-29 15:04:33
【问题描述】:

我正在尝试将 SCNNode 指向另一个目标节点。我觉得我错过了一些东西,因为无论我给目标节点提供什么位置,查看器都会保持相同的方向。粘贴到情节提要中的以下代码始终如一地生成此控制台日志:

SCNVector4(x: 0.0, y: 0.0, z: 0.0, w: 1.0) SCNVector4(x: 0.0, y: 0.0, z: 0.0, w: 1.0)
func lookAtNode() {
    
    let sceneView = SCNView()
    let scene = SCNScene()
    sceneView.scene = scene
    
    let target = SCNNode()
    target.position = SCNVector3(x: 5, y: 0, z: -5)
    sceneView.scene?.rootNode.addChildNode(target)
    
    let viewer = SCNNode()
    viewer.position = SCNVector3(x: 0, y: 5, z: 0)
    let lookAt = SCNLookAtConstraint(target: target)
    //lookAt.isGimbalLockEnabled = true
    viewer.constraints = [lookAt]
    sceneView.scene?.rootNode.addChildNode(viewer)

    print(viewer.presentation.orientation, viewer.orientation)
    
}

lookAtNode()

我使用它而不是简单的lookAt(节点)的主要原因是因为我需要防止滚动,如果我可以让它工作,isGimbalLockEnabled 属性提供了这个功能。

【问题讨论】:

  • 您正在创建一个新的SCNView,而不是使用您的 viewController 的视图?
  • 这只是故事板中的一个例子。我不确定为什么会有所作为。一个简单的 .lookAt(node: 工作只是在这个上下文中找到。它也只是围绕 Z 旋转。
  • 这是因为lookAt(node: 会立即更新节点,但在渲染循环期间会评估约束。由于您的场景从未渲染,因此不会应用约束。
  • @JamesP 好吧,这就解释了。太感谢了。这真的很有帮助。刚刚把它移到了一个 VC 中,正如你所说,它现在可以工作了。谢谢!

标签: swift scenekit


【解决方案1】:

这就是我让它工作的方式。我通过查看方向值来完成整个过程,试图找出它为什么不旋转。

首先,创建您的查看器节点,然后将任何材质添加到 viewerNode(又名 displayNode)的子节点。当查看器节点看向目标时,所有子节点材质都会随之旋转。一个快速的测试方法是添加一个 SCNBox 作为子节点,然后你可以得到一个视觉效果。

类 GameType...

    func add(vGameType: gameTypes, vCount: Int, vPanelName: String)
    {
      name = "\(vGameType):\(vCount)"
      gameType = vGameType
      displayNode = gNodes.loadDefenseNode(vGameType: vGameType)
      node.name = "\(vGameType):\(vCount)"
      node.addChildNode(displayNode!)
      gNodes.gameNodes.addChildNode(node)
      node.isHidden = false
    }
    func setTarget()
    {
      node.constraints = []
      let vConstraint = SCNLookAtConstraint(target: targetNode)
      vConstraint.isGimbalLockEnabled = true
      node.constraints = [vConstraint]
}

我知道这至少在以前的版本中有效,所以如果不这样做,那么它可能是你初始化场景的方式。将其作为 viewDidLoad() 的一部分放入 var 中,然后您就知道所有内容都已初始化。

class GameViewController: UIViewController {

    var SoundAction = SCNAction()
    var SoundNode = SCNNode()
    var scene = SCNScene()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Change this
        scene = SCNScene(named: "art.scnassets/ship.scn")!

        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)

        let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
        ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))

        let audioSource = SCNAudioSource(named: "MenuWinner.caf")!
        audioSource.volume = 1.0
        SoundAction = SCNAction.playAudio(audioSource, waitForCompletion: false)

        let scnView = self.view as! SCNView
        scnView.scene = scene
        scnView.allowsCameraControl = true
        scnView.showsStatistics = true
        scnView.backgroundColor = UIColor.black

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        scnView.addGestureRecognizer(tapGesture)
    }

    @objc
    func handleTap(_ gestureRecognize: UIGestureRecognizer) {
        scene.rootNode.addChildNode(SoundNode)
        SoundNode.runAction(SoundAction)
    }

【讨论】:

  • 谢谢。我会试一试,看看它是否有所作为。主要问题是我实际上并不关心渲染视图的样子。我正在使用 SceneKit 来检索其他地方使用的值。遗憾的是 simd 不提供此 API。
猜你喜欢
  • 2015-01-03
  • 2015-05-08
  • 2016-02-09
  • 2014-12-03
  • 2014-09-18
  • 1970-01-01
  • 2015-10-14
  • 2023-04-04
相关资源
最近更新 更多