如何将3D对象(.scn文件)放置在检测到的垂直平面上,该平面应与ARKIt中的平面平行?

时间:2019-05-24 05:16:06

标签: ios swift 3d arkit

我将在ARKit中检测水平和垂直平面。在检测出水平或垂直表面后,分别在检测到的表面上添加灰色平面。在检测到的平面上点击,我将添加.scn文件的3D对象。

我的代码可以很好地将3D对象(.scn文件)放置在水平面上,但不能在垂直平面上正常工作。

像相框一样的垂直平面的3D对象(.scn文件)在SceneKit编辑器中正对着。因此,我将其EularAngleY更改为-0,并且现在在SceneKit Editor中正对着前面。当我点击检测到的面向前方的垂直平面时,相框也朝右,如果我将设备向右移动并放置相框,那是正确的。

我要放置3D对象.scn文件,该文件应与平面平行(如果垂直平面面向前方,则即使在.scn文件中它面向任何方向也应面向前方).3D对象不平行于检测到的飞机。

我是否还需要相对于检测到的平面角度更改旋转角度,还是需要在SceneKit编辑器中对.scn文件进行任何更改?我该如何实现?

在击中检测到的垂直平面时,请检查以下代码。有什么问题吗?

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

    guard let hitTestResult = hitTestResults.first, let anchor = hitTestResult.anchor as? ARPlaneAnchor else { return }


    let translation = hitTestResult.worldTransform.columns.3

    let x = translation.x
    let y = translation.y
    let z = translation.z

    guard let shipScene = SCNScene(named: "art.scnassets/frame/frame.scn"),
        let shipNode = shipScene.rootNode.childNode(withName: "frame", recursively: true)
        else { return }

    shipNode.position = SCNVector3(x,y,z)

    sceneView.scene.rootNode.addChildNode(shipNode)
}

1 个答案:

答案 0 :(得分:1)

正如我在答案here中提到的那样,最好在ARAnchor上添加ARSession,而不是在完成{命中测试。当前,您发布的代码未考虑检测到的飞机的旋转。为了使代码正常工作,您需要确定检测到的平面的法线,以点积和叉积与模型所需的方向相乘来计算旋转,然后应用旋转。但是,SCNNode将为您完成所有这些工作。通过使用ARSession,旋转编码为锚。因此,您只需要使用模型自己的局部坐标空间来处理变换。

例如:

ARAnchor(transform: hitTestResult.worldTransform)

然后在您的会话委托中回叫:

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

    guard let hitTestResult = hitTestResults.first, let anchor = hitTestResult.anchor as? ARPlaneAnchor else { return }
    // create anchor and add to session and wait for callback
    let anchor = ARAnchor(transform: hitTestResult.worldTransform)
    sceneView.session.add(anchor: anchor)
}

在scn文件中,您需要将模型放置在原点处且没有任何变换。这意味着您可能需要嵌套节点,并将基础模型相对于父级空节点定位。

Xcode SCN editor screenshot

在这里,“帧”是从func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? { if anchor is ARPlaneAnchor { // node for plane anchor let anchorNode = SCNNode() return anchorNode } else { // must be node for most recent hit test guard let frameScene = SCNScene(named: "art.scnassets/frame/frame.scn"), let frameNode = frameScene.rootNode.childNode(withName: "frame", recursively: true) else { return nil } return frameNode } } 返回的无变换的外部节点,“图片”被旋转为平坦状态并缩放到内容的大小。

最终结果:

Screencast of final product