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

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

问题描述

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



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



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



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



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



请在检查命中垂直平面时检查以下代码。有什么问题吗?

  @objc func addObjectToSceneView1(withGestureRecognizer识别器:UIGestureRecognizer){
让tapLocation = Recognir.location (在:sceneView中)
让hitTestResults = sceneView.hitTest(tapLocation,类型:.existingPlaneUsingExtent)

守卫让hitTestResult = hitTestResults.first,让anchor = hitTestResult.anchor为? ARPlaneAnchor else {return}


让翻译= hitTestResult.worldTransform.columns.3

让x =翻译。x
让y =翻译。 y
let z = translation.z

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

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天全站免登陆