Swift:ARKit 基于 2 个节点放置一个矩形

标签 swift arkit scnnode

我的想法是我想在选定的位置放置 2 个球体节点。从那时起,我基本上想画一个矩形,用 slider 调整高度。基本上这意味着 2 个球体将代表开始时的所有 4 个角。但是在测试代码时,我使用 1 米的高度作为测试。

我遇到的问题是我似乎无法将矩形放置在正确的位置,如下图所示:

image

图像中的矩形具有比点更高的 y 点,它稍微旋转并且其中心点在节点 2 上方而不是在节点之间。我不想使用 node.rotation,因为它不会动态工作。

这是我用来放置 2 个节点并绘制 + 添加矩形的代码。

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let location =  touches.first?.location(in: sceneView) else {return}
        let hitTest = sceneView.hitTest(location, types: [ARHitTestResult.ResultType.featurePoint])
        guard let result = hitTest.last else {return}

        // Converts the matrix_float4x4 to an SCNMatrix4 to be used with SceneKit
        let transform = SCNMatrix4.init(result.worldTransform)

        // Creates an SCNVector3 with certain indexes in the matrix
        let vector = SCNVector3Make(transform.m41, transform.m42, transform.m43)
        let node = addSphere(withPosition: vector)
        nodeArray.append(node)
        sceneView.scene.rootNode.addChildNode(node)

        if nodeArray.count == 2 {
            let node1 = sceneView.scene.rootNode.childNodes[0]
            let node2 = sceneView.scene.rootNode.childNodes[1]

            let bezeierPath = UIBezierPath()
            bezeierPath.lineWidth = 0.01
            bezeierPath.move(to: CGPoint(x: CGFloat(node1.position.x), y: CGFloat(node1.position.y)))
            bezeierPath.addLine(to: CGPoint(x: CGFloat(node2.position.x), y: CGFloat(node2.position.y)))
            bezeierPath.addLine(to: CGPoint(x: CGFloat(node2.position.x), y: CGFloat(node2.position.y+1.0)))
            bezeierPath.addLine(to: CGPoint(x: CGFloat(node1.position.x), y: CGFloat(node1.position.y+1.0)))
            bezeierPath.close()
            bezeierPath.fill()
            let shape = SCNShape(path: bezeierPath, extrusionDepth: 0.02)
            shape.firstMaterial?.diffuse.contents = UIColor.red.withAlphaComponent(0.8)
            let node = SCNNode.init(geometry: shape)
            node.position = SCNVector3(CGFloat(abs(node1.position.x-node2.position.x)/2), CGFloat(abs((node1.position.y)-(node2.position.y))/2), CGFloat(node1.position.z))
            sceneView.scene.rootNode.addChildNode(node)
        }

    }

另请注意,这不是我的最终代码。一旦一切正常,它将被重构 :)。

最佳答案

目前正在运行。我使用错误的计算将其设置在 2 个点的中间。

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // Check if a window is placed already and fetch location in sceneView
    guard debugMode, let location = touches.first?.location(in: sceneView) else {return}
    // Fetch targets at the current location
    let hitTest = sceneView.hitTest(location, types: [ARHitTestResult.ResultType.featurePoint])
    guard let result = hitTest.last else {return}

    // Create sphere are position. getPosition() is an extension
    createSphere(withPosition: result.getPosition())

    // When 2 nodes has been placed, create a window and hide the spheres
    if nodeArray.count == 2 {
        let firstNode = nodeArray[nodeArray.count-1]
        let secondNode = nodeArray[nodeArray.count-2]
        firstNode.isHidden = true
        secondNode.isHidden = true
        createWindow(firstNode: firstNode, secondNode: secondNode)
        sceneView.debugOptions = []
    }
}

func createSphere(withPosition position: SCNVector3) {
    // Create an geometry which you will apply materials to and convert to a node
    let object = SCNSphere(radius: 0.01)
    let material = SCNMaterial()
    material.diffuse.contents = UIColor.red
    object.materials = [material]
    let node = SCNNode(geometry: object)
    node.position = position
    nodeArray.append(node)
    sceneView.scene.rootNode.addChildNode(node)
}

func createWindow(firstNode: SCNNode, secondNode: SCNNode) {
    // Create an geometry which you will apply materials to and convert to a node
    let shape = SCNBox(width: CGFloat(abs(firstNode.worldPosition.x-secondNode.worldPosition.x)), height: 0.01, length: 0.02, chamferRadius: 0)
    let material = SCNMaterial()
    material.diffuse.contents = UIColor.red.withAlphaComponent(0.8)
    // Each side of a cube can have different materials
    // https://stackoverflow.com/questions/27509092/scnbox-different-colour-or-texture-on-each-face
    shape.materials = [material]
    let node = SCNNode(geometry: shape)
    let minX = min(firstNode.worldPosition.x, secondNode.worldPosition.x)
    let maxX = max(firstNode.worldPosition.x, secondNode.worldPosition.x)

    // The nodes pivot Y-axis should be split in half of the nodes height, this will cause the node to
    // only scale in one direction, when scaling it
    // https://stackoverflow.com/questions/42568420/scenekit-understanding-the-pivot-property-of-scnnode/42613002#42613002
    node.position = SCNVector3(((maxX-minX)/2)+minX, firstNode.worldPosition.y, firstNode.worldPosition.z)
    node.pivot = SCNMatrix4MakeTranslation(0, 0.005, 0)
    node.scale = SCNVector3Make(1, -50, 1)
    node.name = "window"

    sceneView.scene.rootNode.addChildNode(node)
}

还添加了:

 @objc func resetSceneView() {
    // Clear all the nodes
    sceneView.scene.rootNode.enumerateHierarchy { (node, stop) in
        node.childNodes.forEach({
            $0.removeFromParentNode()
        })
        node.removeFromParentNode()
    }

    // Reset the session
    sceneView.session.pause()
    sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
    sceneView.session.run(configuration, options: .resetTracking)
    let matrix = sceneView.session.currentFrame!.camera.transform
    sceneView.session.setWorldOrigin(relativeTransform: matrix)
    nodeArray = []
}

确保世界对齐重置为您的相机位置

关于Swift:ARKit 基于 2 个节点放置一个矩形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49850591/

相关文章:

ios - 如何从我的 iPhone 向 Apple 电视应用程序发送数据

augmented-reality - 包含 2 个场景的 Reality Composer 项目文件可以在 Xcode 中播放吗?

ios - 使用 ARKit 中的 ARCamera 信息定位/旋转平面节点

swift - dae 文件中节点的几何形状为零

ios - 如何以紧凑的形式编辑 Swift 数组

IOS Swift,如何检测文件上传点击UIWebView内部打开照片上传对话框

python - 在 swift 和 python 中从相同的返回类型获得不同的结果

swift - 是否可以使用 CoreML 模型检测对象并找到该对象的测量值?

ios - SceneKit 中的土星环节点

ios - 如何在 ARKit 中使用手势 Action 在 SCNNode 中添加标签节点和用户图像?