如何将 3D 对象(.scn 文件)放置在检测到的垂直平面上,该平面应与 ARKIt 中的平面平行? [英] How to place 3D object (.scn file) on detected vertical plane which should be parallel to plane in ARKIt?

查看:30
本文介绍了如何将 3D 对象(.scn 文件)放置在检测到的垂直平面上,该平面应与 ARKIt 中的平面平行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

垂直平面(如相框)的 3D 对象(.scn 文件)在 SceneKit 编辑器中面向右侧.所以我将它的 EularAngleY 更改为 -0,现在它在 SceneKit 编辑器中面向前方.当我点击检测到的面向前方的垂直平面时,相框也面向右侧,如果我将设备向右移动并放置相框,则它是正确的.

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

我是否还需要根据检测到的平面角度更改旋转或需要在 SceneKit 编辑器中的 .scn 文件中进行任何更改?我怎样才能实现它?

请检查下面的代码是否命中检测到的垂直平面.有什么问题吗?

@objc func addObjectToSceneView1(withGestureRecognizer 识别器:UIGestureRecognizer){让 tapLocation = 识别器.位置(输入:场景视图)让 hitTestResults = sceneView.hitTest(tapLocation, 类型:.existingPlaneUsingExtent)守卫让hitTestResult = hitTestResults.first,让anchor = hitTestResult.anchor as?ARPlaneAnchor else { return }让翻译 = hitTestResult.worldTransform.columns.3让 x = translation.x让 y = translation.y让 z = translation.z守卫让 shipScene = SCNScene(named: "art.scnassets/frame/frame.scn"),let shipNode = shipScene.rootNode.childNode(withName: "frame", recursively: true)否则{返回}shipNode.position = SCNVector3(x,y,z)sceneView.scene.rootNode.addChildNode(shipNode)}

.scn 文件如下所示.这个 .scn 文件是否正确?或者 x 应该与框架的深度?每次我点击飞机时,它只会显示这样的图像.

解决方案

正如我在回答

这里的frame"是从 nodeForAnchor 返回的没有变换的外部节点,并且图片"被旋转成平面并缩放到内容的大小.

最终结果:

I am going to detect horizontal and vertical plane in ARKit. After detecting whether it is horizontal or vertical surface, respectively add plane of gray color on detected surface.On tap on detected plane I am going to add 3D object of .scn file.

My code is working fine for placing 3D object (.scn file) on horizontal plane but not working correctly with vertical plane.

3D object (.scn file) for vertical plane like photo frame is facing right in SceneKit editor. So I changed it’s EularAngleY to -0 and it’s facing front now in SceneKit Editor. When I tap on detected vertical plane which is facing to front then also photo frame is facing to right and If I move device facing right and place photo frame then it’s correct.

I want to place 3D object .scn file which should be parallel to plane (If vertical plane is facing front then it should be face front even in .scn file it faces to any direction).That 3D object is not parallel to detected plane.

Have I needed to change rotation also with respect to detected plane’s angle or need to do any changes in .scn file in SceneKit editor? How can I achieve it?

Please check below code on hitting detected vertical plane. Is there anything wrong?

@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)
}

.scn file is like below. Is this .scn file correct? Or x should be with frame's depth? Everytime whenever I tap on plane it will show image like this only.

解决方案

As I mentioned in the answer here, it is better to add an ARAnchor to the ARSession rather than directly adding an SCNNode into the scene graph after doing a hit test. Currently the code you posted doesn't take into account the rotation of the detected plane. For the code to work you would need to determine the normal of the detected plane take the dot product and cross product with the desired orientation of the model calculate the rotation, then apply the rotation. However, the ARSession will do all of that for you. By using ARAnchor(transform: hitTestResult.worldTransform) the rotation is encoded into the anchor. So you will only need to deal with transformations with the models own local coordinate space.

For example:

@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)
}

Then in your session delegate call back:

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
    }
}

In you're scn file you'll want the model to be located at the origin laying flat without any transforms. This means you'll likely need to nest nodes and position the underlying model relative to a parent empty node.

Here "frame" is the outer node with no transform that is returned from nodeForAnchor and "picture" is rotated to be flat and scaled to the size of the content.

Final result:

这篇关于如何将 3D 对象(.scn 文件)放置在检测到的垂直平面上,该平面应与 ARKIt 中的平面平行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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