【问题标题】:Align 3D object parallel to vertical plane detected by estametedVerticalPlane将 3D 对象与 estametedVerticalPlane 检测到的垂直平面平行对齐
【发布时间】:2019-10-08 07:36:31
【问题描述】:

我有这本书,但我目前正在从 AR/VR 周免费的视频教程中重新混合家具应用程序。

我想要一个与检测到的墙壁/垂直平面对齐的 3D 墙壁画布。

事实证明这比我想象的要难。定位不是问题。就像家具放置应用程序一样,您只需获取 hittest.worldtransform 的 column3 并为此 vector3 提供位置的新几何。

但我不知道我必须做什么才能让我的 3D 对象旋转到在对齐的检测平面上面向前方。因为我有一个画布对象,所以照片位于画布的一侧。放置时,照片总是背对着。

我曾考虑对画布进行任意旋转以使其面向前方,但只有当我向北看并将画布放在我右侧的墙上时,这才是正确的。

我在网上尝试了很多解决方案,但一个总是使用 .existingPlaneUsingExtent。用于垂直平面检测。这允许您从 hittest.anchor? as ARPlaneAnchor。 如果您在使用.estimatedVerticalPlane 时尝试这个anchor?是nil

我也没有继续沿着这条路线走下去,因为我的水平 3D 对象开始被放置在空中。这可能归结为控制流逻辑,但在垂直画布放置正常工作之前我会忽略它。

我目前的思路是获取画布的正面矢量,并将其旋转到检测到的垂直平面的正面矢量UIImage 或命中点。

如何从 3D 点获得前向矢量。或者从网格图像中获取正面矢量,即UIImage,当ARKit 检测到垂直墙时作为叠加层放置?

这是一个例子。画布显示画布的背面,并且与作为列的检测到的垂直平面不平行。但是有一个“在此处放置海报”网格,我希望画布与之对齐,并且我可以看到照片。

我尝试过的事情。 使用.estimatedVerticalPlane ARKit estimatedVerticalPlane hit test get plane rotation

我不知道如何正确应用这个矩阵和来自 SO 答案的 eular 角度结果。

我的添加图片功能。

func addPicture(hitTestResult: ARHitTestResult) {
    // I would like to convert estimate hitTest to a anchorpoint
    // it is easier to rotate a node to a anchorpoint over calculating eularAngles
    // we have all detected anchors in the _Renderer SCNNode. however there are

    // Get the current furniture item, correct its position if necessary,
    // and add it to the scene.
    let picture = pictureSettings.currentPicturePiece()

    //look for the vertical node geometry in verticalAnchors
    if let hitPlaneAnchor = hitTestResult.anchor as? ARPlaneAnchor {
      if let anchoredNode = verticalAnchors[hitPlaneAnchor]{
        //code removed as a .estimatedVerticalPlane hittestResult doesn't get here
      }
    }else{
      // Transform hitresult to world coords
      let worldTransform = hitTestResult.worldTransform
      let anchoredNodeOrientation = worldTransform.eulerAngles
        picture.rotation.y =
          -.pi * anchoredNodeOrientation.y
        //set the transform matirs
        let positionMatris = worldTransform.columns.3
        let position = SCNVector3 (
          positionMatris.x,
          positionMatris.y,
          positionMatris.z
        )
        picture.position = position + pictureSettings.currentPictureOffset();

    }
    //parented to rootNode of the scene
    sceneView.scene.rootNode.addChildNode(picture)
  }

感谢您提供的任何帮助。

编辑: 我注意到“手性”或 3D 模型不正确/相反? 正 Z 指向左侧,正 X 面向相机,因为我期望的是模型的正面。这是个问题吗?

【问题讨论】:

    标签: ios scenekit arkit


    【解决方案1】:

    您应该尽量避免使用世界坐标将节点直接添加到场景中。相反,您应该通过添加ARAnchor 来通知感兴趣区域的ARSession,然后使用会话回调为添加的锚点提供SCNNode

    例如,您的命中测试可能类似于:

    @objc func tapped(_ sender: UITapGestureRecognizer) {
        let location = sender.location(in: sender.view)
        guard let hitTestResult = sceneView.hitTest(location, types: [.existingPlaneUsingGeometry, .estimatedVerticalPlane]).first,
              let planeAnchor = hitTestResult.anchor as? ARPlaneAnchor,
              planeAnchor.alignment == .vertical else { return }
        let anchor = ARAnchor(transform: hitTestResult.worldTransform)
        sceneView.session.add(anchor: anchor)
    }
    

    此处识别的点击手势用于检测ARSCNView 内的点击。当检测到敲击时,执行命中测试以寻找现有和估计的平面。如果平面是垂直的,我们添加一个ARAnchor 和命中测试结果的worldTransform,我们将该锚点添加到ARSession。这会将那个点注册为ARSession 的感兴趣区域,因此在我们将内容添加到那里后,我们将获得更好的跟踪和更少的漂移。

    接下来,我们需要为新添加的ARAnchor 出售我们的SCNNode。例如

    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        if anchor is ARPlaneAnchor {
            let anchorNode = SCNNode()
            anchorNode.name = "anchor"
            return anchorNode
        } else {
            let plane = SCNPlane(width: 0.67, height: 1.0)
            plane.firstMaterial?.diffuse.contents = UIImage(named: "monaLisa")
            let planeNode = SCNNode(geometry: plane)
            planeNode.eulerAngles = SCNVector3(CGFloat.pi * -0.5, 0.0, 0.0)
            let node = SCNNode()
            node.addChildNode(planeNode)
            return node
        }
    }
    

    这里我们首先检查锚点是否为ARPlaneAnchor。如果是,我们会提供一个空节点用于调试目的。如果不是,则它是作为命中测试结果添加的锚点。因此,我们为最近的点击创建几何和节点。因为它是一个垂直平面并且我们的内容是平放的,所以需要围绕 x 轴旋转它。所以我们将其调整为eulerAngles 使其保持直立。如果我们直接返回planeNode,调整为eulerAngles会被移除,所以我们将其添加为空节点的子节点并返回。

    应该会产生如下结果。

    【讨论】:

    • 您好,感谢您的回复。好的,我将尝试添加到会话节点并报告我的发现。接下来要运行的是,您的放置逻辑是否适用于从 .scn 文件中抓取的 3D 对象?在您的示例中,您正在创建一个基本的 scn 平面。我注意到我的 3D 对象 X 和 Z 从估计的平面 X 和 Z 切换。即平面的 Z 面向相机,X 向右。在 3d 对象上,X 朝向相机,Z(pos) 朝向左侧。
    • 在 hitTestResult 锚上添加节点工作正常,但我想在检测到的垂直平面上添加场景 (.scn) 文件。首先,我正在检测垂直平面并添加垂直平面,在检测到的垂直平面上点击后,我想添加该 .scn 文件。该 3D 对象与检测到的平面不平行。我怎样才能实现它?
    • @mushcraft 也许您可以发布您正在使用的模型。但是,如果您按照上述步骤操作,现在只需在其局部坐标空间内调整模型即可,我认为这更容易推理。
    • @Bhakti 你在 Stack Overflow 上发布过问题吗?
    • @beyowulf 现在我已经发布了问题。请查看链接stackoverflow.com/questions/56286246/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-10
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 2014-12-05
    • 1970-01-01
    相关资源
    最近更新 更多