简体   繁体   English

如何通过在屏幕上拖动手指来更改相机位置 - Swift

[英]How to change camera position by dragging finger on the screen - Swift

I'm trying to learn ARKIT and make a small demo app to draw in 3D.我正在尝试学习 ARKIT 并制作一个小型演示应用程序来绘制 3D。 The following is the code I wrote and so far there are no problems:以下是我写的代码,目前没有问题:

import UIKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet weak var sceneView: ARSCNView!

    @IBOutlet weak var DRAW: UIButton!
    @IBOutlet weak var DEL: UIButton!

    let config = ARWorldTrackingConfiguration()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.sceneView.session.run(config)
        self.sceneView.delegate = self
    }

    func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {

        guard let pointOfView = sceneView.pointOfView else {return}
        let transform = pointOfView.transform
        let cameraOrientation = SCNVector3(-transform.m31,-transform.m32,-transform.m33)
        let cameraLocation = SCNVector3(transform.m41,transform.m42,transform.m43)
        let cameraCurrentPosition = cameraOrientation + cameraLocation

        DispatchQueue.main.async {

            if (self.DRAW.isTouchInside){
                let sphereNode  = SCNNode(geometry: SCNSphere(radius: 0.02))
                    sphereNode.position = cameraCurrentPosition
                    self.sceneView.scene.rootNode.addChildNode(sphereNode)
                    sphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red
                    print("RED Button is Pressed")
                }else if (self.DEL.isTouchInside){
                    self.sceneView.scene.rootNode.enumerateChildNodes{
                    (node, stop) in
                    node.removeFromParentNode()
                    }
                }else{
                    let pointer = SCNNode(geometry: SCNSphere(radius: 0.01))
                    pointer.name = "pointer"
                    pointer.position = cameraCurrentPosition
                    self.sceneView.scene.rootNode.enumerateChildNodes({(node,_) in
                        if node.name == "pointer"{
                            node.removeFromParentNode()
                        }
                    })
                     self.sceneView.scene.rootNode.addChildNode(pointer)
                    pointer.geometry?.firstMaterial?.diffuse.contents = UIColor.purple
                }
        }
    }
}

func +(left:SCNVector3,right:SCNVector3) -> SCNVector3 {
    return SCNVector3Make(left.x + right.x, left.y + right.y, left.z + right.z)
}

As you can see, I set the scene and configure it, I create a button to draw when pressed, a pointer (or viewfinder) that takes the center of the scene and a button to delete the nodes inserted.如您所见,我设置了场景并对其进行了配置,我创建了一个在按下时进行绘制的按钮、一个位于场景中心的指针(或取景器)以及一个用于删除插入节点的按钮。

Now I would like to be able to move the cameraCurrentPosition to a different point from the center: I would like to move it if possible with a touch on the screen taking the position of the finger.现在我希望能够将 cameraCurrentPosition 移动到与中心不同的点:如果可能,我想通过在屏幕上触摸手指的位置来移动它。 If possible, could someone help me with the code?如果可能的话,有人可以帮我写代码吗?

Generally speaking, you can't programmatically move the Camera within an ARSCN, the camera transform is the physical position of the device relative to the virtual scene.一般来说,您不能以编程方式在 ARSCN 内移动相机,相机变换是设备相对于虚拟场景的物理位置。

With that being said, one way you could draw the user touches to the screen is using the touchesMoved method within your View Controller.话虽如此,您可以将用户触摸绘制到屏幕的一种方法是在您的视图控制器中使用touchesMoved方法。

var touchRoots: [SCNNode] = [] // list of root nodes for each set of touches drawn

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // get the initial touch event
    if let touch = touches.first {
        guard let pointOfView = self.sceneView.pointOfView else { return }
        let transform = pointOfView.transform // transformation matrix
        let orientation = SCNVector3(-transform.m31, -transform.m32, -transform.m33) // camera rotation
        let location = SCNVector3(transform.m41, transform.m42, transform.m43) // location of camera frustum
        let currentPostionOfCamera = orientation + location // center of frustum in world space
        DispatchQueue.main.async {
            let touchRootNode : SCNNode = SCNNode() // create an empty node to serve as our root for the incoming points
            touchRootNode.position = currentPostionOfCamera // place the root node ad the center of the camera's frustum
            touchRootNode.scale = SCNVector3(1.25, 1.25, 1.25)// touches projected in Z will appear smaller than expected - increase scale of root node to compensate
            guard let sceneView = self.sceneView else { return }
            sceneView.scene.rootNode.addChildNode(touchRootNode) // add the root node to the scene
            let constraint = SCNLookAtConstraint(target: self.sceneView.pointOfView) // force root node to always face the camera
            constraint.isGimbalLockEnabled = true // enable gimbal locking to avoid issues with rotations from LookAtConstraint
            touchRootNode.constraints = [constraint] // apply LookAtConstraint

            self.touchRoots.append(touchRootNode)
        }
    }
}

override func func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        let translation = touch.location(in: self.view)
        let translationFromCenter = CGPoint(x: translation.x - (0.5 * self.view.frame.width), y: translation.y - (0.5 * self.view.frame.height))

        // add nodes using the main thread
        DispatchQueue.main.async {
            guard let touchRootNode = self.touchRoots.last else { return }
            let sphereNode : SCNNode = SCNNode(geometry: SCNSphere(radius: 0.015))
            sphereNode.position = SCNVector3(-1*Float(translationFromCenter.x/1000), -1*Float(translationFromCenter.y/1000), 0)
            sphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.white
            touchRootNode.addChildNode(sphereNode)  // add point to the active root
        }
    }
}

Note: solution only handles a single touch, but it is simple enough to extend the example to add multi-touch support.注意:解决方案仅处理单点触控,但扩展示例以添加多点触控支持很简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM