如何在 ARSCNView 中移动多个节点 [英] How to move multiple nodes in ARSCNView

查看:33
本文介绍了如何在 ARSCNView 中移动多个节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是能够使用gestureRecognizer 移动/旋转AR 对象.虽然我让它适用于单个 AR 立方体,但我无法让它适用于多个立方体/对象.

My goal is to be able to move/rotate AR objects using the gestureRecognizer. While I got it working for a single AR cube, I cannot get it work for multiple cubes/objects.

viewDidLoad 的主要部分:

Main part of the viewDidLoad:

        let boxNode1 = addCube(position: SCNVector3(0,0,0), name: "box")
        let boxNode2 = addCube(position: SCNVector3(0,-0.1,-0.1), name: "box2")

        sceneView.scene.rootNode.addChildNode(boxNode1)
        sceneView.scene.rootNode.addChildNode(boxNode2)
        
        var nodes: [SCNNode] = getMyNodes()

        var parentNode = SCNNode()
        parentNode.name = "motherNode"

        for node in nodes {
            parentNode.addChildNode(node)
        }
        sceneView.scene.rootNode.addChildNode(parentNode)

//        sceneView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:))))
        sceneView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(ViewController.handleMove(_:))))
        sceneView.addGestureRecognizer(UIRotationGestureRecognizer(target: self, action: #selector(ViewController.handleRotate(_:))))
        
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration)

panGesture 的一部分(适用于每个立方体,但如果我更改为 nodeHit.Parent 则不起作用!)正确检测到父节点,但没有对其进行任何更改:

Part of panGesture (works for each cube, but does not work if I change to nodeHit.Parent!) The parent node is detected correctly, but no change is made to it:

    @objc func handleMove(_ gesture: UIPanGestureRecognizer) {

    //1. Get The Current Touch Point
    let location = gesture.location(in: self.sceneView)

    //2. Get The Next Feature Point Etc
    guard let nodeHitTest = self.sceneView.hitTest(location, options: nil).first else { print("no node"); return }

    var nodeHit = nodeHitTest.node

//    nodeHit = nodeHit.parent!
    //3. Convert To World Coordinates
    let worldTransform = nodeHitTest.simdWorldCoordinates
    //4. Apply To The Node
        nodeHit.position = SCNVector3(worldTransform.x, worldTransform.y, 0)
        
    }

我想要做的是能够同时移动两个立方体(因此它们都经过相同的平移).从这篇文章听起来可能:如何在iOS中将多个节点加入一个节点场景但是,同时这篇文章也说我不能这样做,因为我还不明白:SceneKit 节点不随场景根节点改变位置在最坏的情况下,我认为可以手动将转换应用于每个子节点,但是将转换应用于一个父节点似乎是一种非常优雅的方式.

What I want to do is to be able to move both cube at once (so they all undergoes the same translation). It sounds possible from this post: How to join multiple nodes to one node in iOS scene However, at the same time this post also says I cannot do that for reason I do not understand yet: SceneKit nodes aren't changing position with scene's root node In the worst case I think it is possible to manually apply the transformation to every child node, however applying translation to one parent Node seems to be a much elegant way for doing this.

我尝试过这种方式,可以让两个移动节点都移动,但有时位置会颠倒(有时立方体在不应该的情况下位于另一个之上):

I tried this way and can get both moving nodes moving, however sometimes the position is reversed (sometimes the cube comes on top of the other when they should not):

    @objc func handleMove(_ gesture: UIPanGestureRecognizer) {

    //1. Get The Current Touch Point
    let location = gesture.location(in: self.sceneView)

    //2. Get The Next Feature Point Etc
    guard let nodeHitTest = self.sceneView.hitTest(location, options: nil).first else { print("no node"); return }

//    var nodeHit = nodeHitTest.node

    let nodeHit = nodeHitTest.node
    let original_x = nodeHitTest.node.position.x
    let original_y = nodeHitTest.node.position.y
    print(original_x, original_y)
//    let nodeHit = sceneView.scene.rootNode.childNode(withName: "motherNode2", recursively: true)
    //3. Convert To World Coordinates
    let worldTransform = nodeHitTest.simdWorldCoordinates
    //4. Apply To The Node
////    nodeHit.position = SCNVector3(worldTransform.x, worldTransform.y, 0)
    nodeHit.position = SCNVector3(worldTransform.x, worldTransform.y, 0)

    for node in nodeHit.parent!.childNodes {
        if node.name != nil{
            if node.name != nodeHit.name {
                let old_x = node.position.x
                let old_y = node.position.y
                print(old_x, old_y)
                node.position = SCNVector3((nodeHit.simdPosition.x + original_x - old_x), (nodeHit.simdPosition.y + original_y - old_y), 0)
            }
        }
    }

有什么想法吗?

推荐答案

我换了加减号,现在它可以正常工作了.代码如下:

I swapped the plus minus sign and now it is working correctly. Here is the code:

    /// - Parameter gesture: UIPanGestureRecognizer
    @objc func handleMove(_ gesture: UIPanGestureRecognizer) {

    //1. Get The Current Touch Point
    let location = gesture.location(in: self.sceneView)

    //2. Get The Next Feature Point Etc
    guard let nodeHitTest = self.sceneView.hitTest(location, options: nil).first else { print("no node"); return }

//    var nodeHit = nodeHitTest.node

    let nodeHit = nodeHitTest.node
    let original_x = nodeHitTest.node.position.x
    let original_y = nodeHitTest.node.position.y
//    let nodeHit = sceneView.scene.rootNode.childNode(withName: "motherNode2", recursively: true)
    //3. Convert To World Coordinates
    let worldTransform = nodeHitTest.simdWorldCoordinates
    //4. Apply To The Node
////    nodeHit.position = SCNVector3(worldTransform.x, worldTransform.y, 0)
    nodeHit.position = SCNVector3(worldTransform.x, worldTransform.y, 0)

    for node in nodeHit.parent!.childNodes {
        if node.name != nil{
            if node.name != nodeHit.name {
                let old_x = node.position.x
                let old_y = node.position.y
                node.position = SCNVector3((nodeHit.simdPosition.x - original_x + old_x), (nodeHit.simdPosition.y - original_y + old_y), 0)
            }
        }
    }

这个想法是即使没有将所有内容分组到一个新节点中,我也可以使用 nodeHit.parent!.childNodes 访问所有节点.这还包含默认创建的其他节点,例如相机或光源,因此我添加了条件以确保它仅选择具有我创建的名称的节点.理想情况下,您只需要使用一些内置方法来移动场景中的所有节点,但我找不到这样的方法.

The idea is even without grouping everything into a new node, I can access all the nodes using nodeHit.parent!.childNodes. This also contains other nodes created by default such as camera or light source so I added the condition to make sure it only selects the nodes with the names I have created. Ideally you just need to use some built in methods to move all the nodes in the scene but I cannot find such method.

所以我的方法首先在移动之前跟踪旧位置,然后如果它是命中测试命中的节点,则像以前一样移动它.但是,如果它不是命中测试命中的节点,则通过 2 个节点之间的差异重新定位它.无论您将节点移动到何处,相对位置差异都应该相同.

So my method first keep track of the old position before moving, then if it is node hit by hit test, move it as before. However, if it is not the node hit by hit test, reposition it by the difference between the the 2 nodes. The relative position difference should be the same regardless of where you move the nodes.

这篇关于如何在 ARSCNView 中移动多个节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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