【问题标题】:ARKIT - How to stick two objectsARKIT - 如何粘贴两个物体
【发布时间】:2018-04-03 14:52:43
【问题描述】:

我有两个对象(两个立方体)。首先,我将第一个立方体添加到场景中。然后我想添加第二个,我希望它粘在第一个上,在第一个的一侧 - 我将通过单击它来选择哪一侧(如下图所示)。是否可以只单击第一个立方体的一个面,第二个立方体自动出现在场景中并粘在第一个立方体上?我无法弄清楚如何做到这一点。

Photo

【问题讨论】:

    标签: swift swift4 arkit


    【解决方案1】:

    当您创建 SCNBoxGeometry 时:

    SCNBox 类自动创建 SCNGeometryElement 对象为 需要处理的材料数量。

    因此,为了访问这些元素,您需要为 Box 的每个面创建一个 SCNMaterial。然后可以执行SCNHitTest 来检测检测到了哪张脸:

    当您执行命中测试搜索时,SceneKit 会查找 SCNGeometry 沿您指定的射线的对象。对于之间的每个交点 射线和几何,SceneKit 创建一个命中测试结果以提供 有关包含几何的 SCNNode 对象和 几何表面上的交点位置。

    那么我们该如何处理呢?

    假设您已经创建了名为 SCNNodes:

    var cubeOne = SCNNode()
    var cubeTwo = SCNNode()
    

    它们都被分配了 6 个不同的 SCNMaterials(每个面一个),如下所示:

    override func viewDidLoad() {
        super.viewDidLoad()
    
        cubeOne.geometry = cubeGeometry()
        cubeOne.position = SCNVector3(0, -0.5, -1.5)
        cubeOne.name = "Cube One"
    
        cubeTwo.geometry = cubeGeometry2()
        cubeTwo.position = SCNVector3(30, 0, -1.5)
        cubeTwo.name = "Cube Two"
    
        self.augmentedRealityView.scene.rootNode.addChildNode(cubeOne)
        self.augmentedRealityView.scene.rootNode.addChildNode(cubeTwo)
    
    }
    
    /// Returns The 6 Faces Of An SCNBox
    ///
    /// - Returns: SCNGeometry
    func cubeGeometry() -> SCNGeometry{
    
        var colours: [UIColor] = [.red, .green, .cyan, .yellow, .purple, .blue]
        var faces = [SCNMaterial] ()
        let cubeGeometry = SCNBox(width: 0.2, height: 0.2, length: 0.2, chamferRadius: 0)
    
        for faceIndex in 0..<5{
    
            let material = SCNMaterial()
            material.diffuse.contents = colours[faceIndex]
            faces.append(material)
    
        }
    
        cubeGeometry.materials = faces
    
        return cubeGeometry
    }
    

    现在您已经为面分配了 6 种材质,您将拥有六个几何元素,它们对应于 SCNBox 的每一侧。

    现在,我们可以快速创建一个与人脸顺序相对应的枚举:

    enum BoxFaces: Int{
    
        case Front, Right, Back, Left, Top, Botton
    }
    

    现在,当我们执行 hitTest 时,我们可以记录命中的位置,例如:

    /// Detects Which Cube Was Detected & Logs The Geometry Index
    ///
    /// - Parameter gesture: UITapGestureRecognizer
    @IBAction func cubeTapped(_ gesture: UITapGestureRecognizer){
    
        //1. Get The Current Touch Location
        let currentTouchLocation = gesture.location(in: self.augmentedRealityView)
    
        //2. Perform An SCNHitTest
        guard let hitTest = self.augmentedRealityView.hitTest(currentTouchLocation, options: nil).first else { return }
    
        //3. If The Node In Cube One Then Get The Index Of The Touched Material
        if let namedNode = hitTest.node.name{
    
            if namedNode == "Cube One"{
    
                //4. Get The Geometry Index
                if let faceIndex = BoxFaces(rawValue:  hitTest.geometryIndex){
                    print("User Has Hit \(faceIndex)")
    
                    //5. Position The Second Cube
                    positionStickyNode(faceIndex)
                }
    
            }
    
        }
    }
    

    在第 5 部分中,您会注意到对函数 positionStickyNode 的调用,它将第二个立方体放置在第一个立方体的相应位置:

    /// Position The Second Cube Based On The Face Tapped
    ///
    /// - Parameter index: BoxFaces
    func positionStickyNode(_ index: BoxFaces){
    
        let (min, max) = cubeTwo.boundingBox
    
        let cubeTwoWidth = max.x - min.x
        let cubeTwoHeight = max.y - min.y
    
        switch index {
    
        case .Front:
            cubeTwo.simdPosition = float3(cubeOne.position.x, cubeOne.position.y, cubeOne.position.z + cubeTwoWidth)
        case .Right:
            cubeTwo.simdPosition = float3(cubeOne.position.x + cubeTwoWidth, cubeOne.position.y, cubeOne.position.z)
        case .Back:
            cubeTwo.simdPosition = float3(cubeOne.position.x, cubeOne.position.y, cubeOne.position.z - cubeTwoWidth)
        case .Left:
            cubeTwo.simdPosition = float3(cubeOne.position.x - cubeTwoWidth, cubeOne.position.y, cubeOne.position.z)
        case .Top:
            cubeTwo.simdPosition = float3(cubeOne.position.x, cubeOne.position.y + cubeTwoHeight, cubeOne.position.z)
        case .Botton:
            cubeTwo.simdPosition = float3(cubeOne.position.x, cubeOne.position.y - cubeTwoHeight, cubeOne.position.z)
        }
    

    这是一个非常粗略的例子,当你的立方体大小相同时会起作用......但是你有足够的东西,现在要弄清楚这将如何适用于不同的尺寸等。

    希望对你有帮助...

    【讨论】:

    • 非常感谢!!唯一的问题是我收到此错误:“'ViewController' 类型的值没有成员'augmentedRealityView'”。
    • augmentedRealityView 是一个 SCNView,所以只需将其更改为您的名称 :)
    • 我明白了。您知道是否可以自动测量相机与出现在相机前面的垂直表面/物体之间的距离?例如,假设像门一样的垂直物体出现在摄像头前,应用程序应该检测到它并显示到它的距离。你会如何处理这个问题?我目前正在使用 ARKit 1.5 和 .vertical 检测来解决这个问题,但我卡住了......谢谢罗宾斯
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-23
    • 1970-01-01
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多