narner
narner

Reputation: 3221

RealityKit – ARView raycasting returns 0 results

I have a subclass of RealityKit's ARView that has the following function for making a Raycast:

func makeRaycastQuery(alignmentType: ARRaycastQuery.TargetAlignment) -> simd_float4x4? {
    let results = self.raycast(from: self.center,
                           // Better for pinning to planes
                           allowing: .estimatedPlane,
                          alignment: alignmentType)

    // We don't care about changing scale on raycast so keep it the same
    guard var result = results.first?.worldTransform else { return nil }
    result.scale = SCNVector3(1, 1, 1)
    return result
}

However, my results array is always empty. Is there some sort of other configuration I need to do when setting up an ARView to enable raycasting?

Upvotes: 2

Views: 398

Answers (2)

yo1995
yo1995

Reputation: 637

In my experience, some older devices that don't have LiDAR perform far worse than the latest devices. I'm using an iPhone 11 vs an iPad Pro M1 to test the same raycast method. iPad Pro has 100% hit rate, while iPhone 11 only has about 15% due to my testing plane being too reflective (?).

If you are in doubt of the validity of your implementation, test with a LiDAR device first. (💸)

Upvotes: 0

Andy Jazz
Andy Jazz

Reputation: 58113

Try this code (I've written it for iPad's Playgrounds):

import RealityKit
import SwiftUI
import ARKit
import PlaygroundSupport

struct ContentView : View {
    
    @State private var arView = ARView(frame: .zero)
    
    var body: some View {
        return ARContainer(arView: $arView)
            .gesture(
                TapGesture()
                    .onEnded { _ in
                        raycasting(arView: arView)
                    }
            )
    }        
    func raycasting(arView: ARView) {
        guard let query = arView.makeRaycastQuery(from: arView.center, 
                                              allowing: .estimatedPlane, 
                                             alignment: .any)
        else { fatalError() }
            
        guard let result = arView.session.raycast(query).first
        else { fatalError() }
            
        let entity = ModelEntity(mesh: .generateSphere(radius: 0.1))
        let anchor = AnchorEntity(raycastResult: result)
        anchor.addChild(entity)
        arView.scene.anchors.append(anchor)
    }
}

struct ARContainer : UIViewRepresentable {
    
    @Binding var arView: ARView
    
    func makeUIView(context: Context) -> ARView {
        arView.cameraMode = .ar
        return arView
    }   
    func updateUIView(_ view: ARView, context: Context) { }
}

PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.setLiveView(ContentView())

P. S.

This version works in UIKit app.

Upvotes: 1

Related Questions