在 ARKit 和 RealityKit 中使用 Raycast 的真正好处是什么?

What is the real benefit of using Raycast in ARKit and RealityKit?

ARKit 和 RealityKit 中的光线投射是什么?

当我需要使用 makeRaycastQuery 实例方法时:

func makeRaycastQuery(from point: CGPoint, 
                 allowing target: ARRaycastQuery.Target, 
                       alignment: ARRaycastQuery.TargetAlignment) -> ARRaycastQuery?

感谢任何帮助。

简单 Ray-Casting,与 Hit-Testing 相同,通过从屏幕点向检测到的平面投射假想光线,帮助找到 real-world 表面上的 3D 位置。在 Apple 文档 (2019) 中有以下 ray-casting 的定义:

Ray-casting is the preferred method for finding positions on surfaces in the real-world environment, but the hit-testing functions remain present for compatibility. With tracked ray-casting, ARKit and RealityKit continues to refine the results to increase the position accuracy of virtual content you place with a ray-cast.

当用户想要将虚拟内容放置到检测到的表面上时,最好为此提供提示。许多 AR 应用程序绘制一个焦点圆或正方形,让用户视觉确认 ARKit 知道的表面的形状和对齐方式。因此,要找出在现实世界中放置焦点圆圈或正方形的位置,您可以使用 ARRaycastQuery 询问 ARKit 现实世界中存在任何表面的位置。


UIKit 实现

这是一个示例,您可以在其中了解如何实现 raycast(query) 实例方法:

import UIKit
import RealityKit

class ViewController: UIViewController {
    
    @IBOutlet var arView: ARView!
    let model = try! Entity.loadModel(named: "usdzModel")
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.raycasting()
    }

    fileprivate func raycasting() {
            
        guard let query = arView.makeRaycastQuery(from: arView.center,
                                              allowing: .estimatedPlane,
                                             alignment: .horizontal)
        else { return }

        guard let result = arView.session.raycast(query).first
        else { return }

        let raycastAnchor = AnchorEntity(world: result.worldTransform)
        raycastAnchor.addChild(model)
        arView.scene.anchors.append(raycastAnchor)
    }
}

如果您想知道如何在 RealityKit 中使用 Convex-Ray-Casting,请阅读


如果您想知道如何在 RealityKit 中使用 Hit-Testing,请阅读 THIS POST


SwiftUI 实现

这是一个示例代码,您可以在其中了解如何在 SwiftUI 中实现光线投射逻辑:

import SwiftUI
import RealityKit

struct ContentView: View {
    
    @State private var arView = ARView(frame: .zero)
    var model = try! Entity.loadModel(named: "robot")
    
    var body: some View {            
        ARViewContainer(arView: $arView)
            .onTapGesture(count: 1) { self.raycasting() }
            .ignoresSafeArea()
    }
    
    fileprivate func raycasting() {                    
        guard let query = arView.makeRaycastQuery(from: arView.center,
                                              allowing: .estimatedPlane,
                                             alignment: .horizontal)
        else { return }

        guard let result = arView.session.raycast(query).first
        else { return }

        let raycastAnchor = AnchorEntity(world: result.worldTransform)
        raycastAnchor.addChild(model)
        arView.scene.anchors.append(raycastAnchor)
    }
}

然后...

struct ARViewContainer: UIViewRepresentable {
    
    @Binding var arView: ARView
    
    func makeUIView(context: Context) -> ARView { return arView }
    func updateUIView(_ uiView: ARView, context: Context) { }
}

P.S.

如果您要从头构建这两个应用变体中的任何一个(即不使用 Xcode AR 模板),请不要忘记启用 [=20= 中的 Privacy - Camera Usage Description 键] 标签。