【问题标题】:Is it possible to detect floor with objects placed on it using ARKit?是否可以使用 ARKit 检测放置在其上的物体的地板?
【发布时间】:2018-02-14 20:47:29
【问题描述】:

我想使用 ARkit 检测地板,当存在诸如桌子等物体并且想要为检测到的表面着色时,这是否可以使用 ARkit,我是 ARKit 世界的新手,不确定这是否可行以及在哪里开始。

【问题讨论】:

  • 我也是新手。但是您可以检测水平表面。并且还可以用不同的颜色将 3d 对象说 SCNode 给它
  • @PrashantTukadiya 是的,知道了,谢谢,但我怀疑 ARKit 是否检测到物体下方的表面
  • 尝试 Apple 的交互和平面检测示例项目,我们能够在我们的应用程序中使用相同的项目来生成带有 ARKit 的平面图生​​成器
  • 我不确定我是否收到了您的问题 - 您想检测桌子、地板等平面,还是想知道是否可以检测 UNDERNEATH 物体下的平面 - 例如: 检测一个表,即使它充满了不同的对象?
  • @JushKillaB 检测地板上有物体时

标签: ios swift arkit


【解决方案1】:

你的会话配置函数应该是这样的,你在viewWillAppear上调用它

func setUpSceneView() {
        let configuration = ARWorldTrackingConfiguration()
        configuration.planeDetection = .horizontal

        sceneView.session.run(configuration)

        sceneView.delegate = self
        sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
    }

您也可以将 .vertical 用于墙壁或其他任何东西..

在视图上确实加载了一个 tapGestureRecognizer 到场景中,这样你就可以将你点击的 SCNNode 添加到检测到的表面

viewDidLoad 中的 addTapGestureToSceneView()

func addTapGestureToSceneView() {
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(placeOnSurface.addNodeToSceneView(withGestureRecognizer:)))
        sceneView.addGestureRecognizer(tapGestureRecognizer)
    }

addNodeToSceneView 方法在检测到平面时会将 SNNode 放置在表面上..

@objc func addShipToSceneView(withGestureRecognizer recognizer: UIGestureRecognizer) {
        let tapLocation = recognizer.location(in: sceneView)
        let hitTestResults = sceneView.hitTest(tapLocation, types: .existingPlaneUsingExtent)

        guard let hitTestResult = hitTestResults.first else { return }
        let translation = hitTestResult.worldTransform.translation
        let x = translation.x
        let y = translation.y
        let z = translation.z

        var name:String = "YourModel.obj" //you can add node whatever


        let group = DispatchGroup()
        group.enter()
        DispatchQueue.global(qos: .background).async {
            print("This is run on the background queue")

            let tempScene = SCNScene(named: name)!
            var geom:SCNGeometry = tempScene.rootNode.childNodes[0].geometry!
            var boxNode:SCNNode = SCNNode(geometry: geom)
            boxNode.position = SCNVector3(x,y,z)
            self.sceneView.scene.rootNode.addChildNode(boxNode)
            group.leave()

        }
        group.notify(queue: .main){
            //Here you know that the node is has been put
        }
    }

and you need some functions for render



    extension float4x4 {
    var translation: float3 {
        let translation = self.columns.3
        return float3(translation.x, translation.y, translation.z)
    }
}



    extension placeOnSurface: ARSCNViewDelegate {
        func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
            // 1
            guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

            // 2
            let width = CGFloat(planeAnchor.extent.x)
            let height = CGFloat(planeAnchor.extent.z)
            let plane = SCNPlane(width: width, height: height)

            // 3
            plane.materials.first?.diffuse.contents = UIColor.transparentLightBlue

            // 4
            let planeNode = SCNNode(geometry: plane)

            // 5
            let x = CGFloat(planeAnchor.center.x)
            let y = CGFloat(planeAnchor.center.y)
            let z = CGFloat(planeAnchor.center.z)
            planeNode.position = SCNVector3(x,y,z)
            planeNode.eulerAngles.x = -.pi / 2

            // 6
            node.addChildNode(planeNode)
        }

        func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
            // 1
            guard let planeAnchor = anchor as?  ARPlaneAnchor,
                let planeNode = node.childNodes.first,
                let plane = planeNode.geometry as? SCNPlane
                else { return }

            // 2
            let width = CGFloat(planeAnchor.extent.x)
            let height = CGFloat(planeAnchor.extent.z)
            plane.width = width
            plane.height = height

            // 3
            let x = CGFloat(planeAnchor.center.x)
            let y = CGFloat(planeAnchor.center.y)
            let z = CGFloat(planeAnchor.center.z)
            planeNode.position = SCNVector3(x, y, z)
        }
    }

我还建议你在 viewDidLoad 中调用函数 configureLighting() 以获得更好的用户体验

func configureLighting() {
        sceneView.autoenablesDefaultLighting = true
        sceneView.automaticallyUpdatesLighting = true
    }

【讨论】:

  • 谢谢,我为得到答案付出了很多努力 :),我认为有可能检测到物体后面和之外的表面,我当然会尝试这段代码。
  • 是的,如果它没有检测到你不能做某事的表面,这就像编写你自己的库一样,有时它在更多的光照下效果更好
  • guard let hitTestResult = hitTestResults.first else { return } 总是处于 else 条件(总是返回)你能检查一下它是否同样适合你。谢谢。
  • 它必须首先检测到一个平面然后它才会通过条件,尝试启用调试选项以查看场景中正在创建的平面以确保已检测到一个平面并点击飞机。然后它将通过条件,您将获得平面内的位置
  • func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) 没调用过可能是这个原因。
猜你喜欢
  • 2018-02-15
  • 2012-02-29
  • 1970-01-01
  • 2018-04-03
  • 1970-01-01
  • 2019-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多