将相机移动到点击的 SCNNode [英] Move camera to tapped SCNNode

查看:105
本文介绍了将相机移动到点击的 SCNNode的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 SceneKitSwift 尝试移动相机,使其聚焦"在所选节点上.我知道我启用了 defaultCameraController,但我试图通过 dollyrotatetranslateInCameraSpaceBy 调整相机的位置,但没有动画过渡 -它只是跳到了新的位置.

I'm using SceneKit and Swift to try and move the camera so it's 'focused' on the selected node. I understand I have the defaultCameraController enabled but I was trying to adjust the camera's position via dolly, rotate and translateInCameraSpaceBy but there was no animated transition - it just jumped to the new position.

相机是否可以像 Google 地图滑动/然后放大到搜索位置那样滑动到位?

Is there anyway for the camera to glide into position like how Google Maps slides/then zooms over to a searched location?

任何帮助将不胜感激:)

Any help would be greatly appreciated :)

这是我的代码:

import UIKit
import SceneKit

class ViewController: UIViewController {

var gameView: SCNView!
var scene: SCNScene!
var cameraNode: SCNNode!

override func viewDidLoad() {
    super.viewDidLoad()

    // Scene
    scene = SCNScene()

    // Camera
    cameraNode = SCNNode()
    cameraNode.camera = SCNCamera()
    cameraNode.position = SCNVector3(0, 0, 10)
    scene.rootNode.addChildNode(cameraNode)

    // Light


    /*
    let lightNode = SCNNode()
    lightNode.light = SCNLight()
    lightNode.light?.type = .omni
    lightNode.position = SCNVector3(0, 10, 2)
    scene.rootNode.addChildNode(lightNode)
    */
    // Stars
    //let stars = SCNParticleSystem(named: "starsParticles.scnp", inDirectory: nil)!
    //scene.rootNode.addParticleSystem(stars)

    // Earth
    let earthNode = itemPlate()
    earthNode.position = SCNVector3(0, 0, 0)
    scene.rootNode.addChildNode(earthNode)

    // Create orbiting moonOne
    let moonNodeOne = itemPlate()
    moonNodeOne.position = SCNVector3(3, 0, 0)
    earthNode.addChildNode(moonNodeOne)

    // Create orbiting moonOne
    let moonNodeTwo = itemPlate()
    moonNodeTwo.position = SCNVector3(5, 3, 2)
    earthNode.addChildNode(moonNodeTwo)

    // Create orbiting moonOne
    let moonNodeThree = itemPlate()
    moonNodeThree.position = SCNVector3(-4, -3, 5)
    earthNode.addChildNode(moonNodeThree)

    // Scene formation
    gameView = self.view as! SCNView
    gameView.scene = scene
    gameView.showsStatistics = true
    gameView.allowsCameraControl = true
    gameView.autoenablesDefaultLighting = true
    gameView.defaultCameraController.interactionMode = .fly
    gameView.defaultCameraController.inertiaEnabled = true
    gameView.defaultCameraController.maximumVerticalAngle = 89
    gameView.defaultCameraController.minimumVerticalAngle = -89
    scene.background.contents = UIImage(named: "orangeBg.jpg")

}

override var prefersStatusBarHidden: Bool {
    return true
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first!
    let location = touch.location(in: gameView)
    let hitList = gameView.hitTest(location, options: nil)

    if let hitObject = hitList.first {
        let node = hitObject.node

        // Update camera position
        //gameView.defaultCameraController.translateInCameraSpaceBy(x: node.position.x, y: node.position.y, z: node.position.z + 5)
        let onScreenPoint:CGPoint = CGPoint(x: 1.0, y: 1.0)
        let viewport:CGSize = CGSize(width: 50, height: 50)

        gameView.defaultCameraController.dolly(by: 1.0, onScreenPoint: onScreenPoint, viewport: viewport)


        //let newCameraPosition = SCNVector3Make(node.position.x, node.position.y, node.position.z + 10)
        print("NODE_HIT_OBJECT_COORDS: \(node.position.x), \(node.position.y) \(node.position.y)")

        //let moveToAction = SCNAction.move(by: newCameraPosition, duration: 1.0)


    }
}

}

推荐答案

你可以在你的代码中实现这样的方法(抱歉,我用的是 macOS 项目而不是 iOS,但它几乎是一样的):

You can implement in your code a methodology like this (sorry, I used macOS project instead iOS, but it's almost the same):

func handleClick(_ gestureRecognizer: NSGestureRecognizer) {

    let scnView = self.view as! SCNView       
    let p = gestureRecognizer.location(in: scnView)
    let hitResults = scnView.hitTest(p, options: [:])

    if hitResults.count > 0 {

        let result = hitResults[0]
        let nodePosition = result.node.position.z
        var matrix = matrix_identity_float4x4

        SCNTransaction.begin()
        SCNTransaction.animationDuration = 1.5       // duration in seconds
        matrix.columns.3.z = Float(nodePosition + 5.0)
        scnView.pointOfView?.position.z = CGFloat(matrix.columns.3.z)
        SCNTransaction.commit()
    }
} 

或者,作为第二个逻辑选项,您可以使用 SceneKit 的约束:

Or, as a second logical option, you can use SceneKit's constraints:

func handleClick(_ gestureRecognizer: NSGestureRecognizer) {

    let scnView = self.view as! SCNView
    let p = gestureRecognizer.location(in: scnView)
    let hitResults = scnView.hitTest(p, options: [:])

    if hitResults.count > 0 {

        let result = hitResults[0]
        let nodePosition = result.node
        let constraint1 = SCNLookAtConstraint(target: nodePosition)
        let constraint2 = SCNDistanceConstraint(target: nodePosition)
        constraint2.minimumDistance = 5
        constraint2.maximumDistance = 9

        SCNTransaction.begin()
        SCNTransaction.animationDuration = 1.5
        scnView.pointOfView?.constraints = [constraint2, constraint1]
        SCNTransaction.commit()
    }
}

附言这两种方法不是开箱即用的解决方案,而是提示如何实现您想要的.

P.S. These two approaches ain't out-of-the-box solutions but rather hints on how to implement what you want to.

这篇关于将相机移动到点击的 SCNNode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆