I would like to load a .reality
file exported from Reality Composer (containing an object anchor and a model) into RealityKit.
As per my current understanding, it should be enough to load the root level AnchorEntity
from the .reality
file and add it to the scene by calling view.scene.addAnchor()
(see // 1:
in the code below). This way, however, object detection is not set up correctly, hence the scene does not appear.
If I, however, explicitly add the AR reference object (using the .arobject
file used for creating the scene in RealityComposer) to ARWorldTrackingConfiguration.detectionObjects
(see // 2.
in the code), and then, in a callback for the event when the corresponding object anchor gets added to the scene, manually attach the contents of the scene to this anchor, the scene gets displayed correctly (see // 3.
in the code).
Why do I need these extra steps? What am I missing for importing the RealityComposer scene in a way that properly sets up object tracking for the AnchorEntity contained therein?
P.s. for the sake of brevity, I am loading all files synchronously in this example.
Here is the code:
struct RealityKitView: UIViewRepresentable {
private static let logger = Logger(
subsystem: Bundle.main.bundleIdentifier!,
category: String(describing: RealityKitView.self)
)
func makeUIView(context: Context) -> ARView {
let view = ARView()
let session = view.session
let config = ARWorldTrackingConfiguration()
// 1: Try to load the .reality file (nothing appears in the ARView):
let realityFileSceneURL = Self.createRealityURL(filename: "ImpactHub_Sign", sceneName: "Scene")
if let realityFileSceneURL {
do {
let anchorEntity = try Entity.loadAnchor(contentsOf: realityFileSceneURL)
view.scene.addAnchor(anchorEntity)
} catch {
debugPrint(error.localizedDescription)
}
}
// 2: Add detection reference objects:
config.detectionObjects = ARReferenceObject.referenceObjects(inGroupNamed: "AR", bundle: Bundle.main)!
session.run(config, options: [.resetTracking])
context.coordinator.view = view
session.delegate = context.coordinator
return view
}
func updateUIView(_ view: ARView, context: Context) {
}
static func createRealityURL(filename: String,
sceneName:String) -> URL? {
guard let realityFileURL = Bundle.main.url(forResource: filename, withExtension: "reality")
else {
print("Error finding Reality file (filename)")
return nil
}
let realityFileSceneURL = realityFileURL.appendingPathComponent(sceneName,
isDirectory: false)
return realityFileSceneURL
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
class Coordinator: NSObject, ARSessionDelegate {
private static let logger = Logger(
subsystem: Bundle.main.bundleIdentifier!,
category: String(describing: Coordinator.self)
)
weak var view: ARView?
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
guard let view = self.view else { return }
debugPrint("Anchors added to the scene: ", anchors)
anchors.compactMap { $0 as? ARObjectAnchor }.forEach { anchor in
debugPrint("Object anchor added")
// 3: Load .reality file and manually create an AnchorEntity bound to the object
// anchor that has just been detected. This way, the scene appears.
let realityFileSceneURL = RealityKitView.createRealityURL(filename: "ImpactHub_Sign", sceneName: "Scene")
if let realityFileSceneURL {
do {
let anchorEntity = try Entity.loadAnchor(contentsOf: realityFileSceneURL)
anchorEntity.children.forEach { childEntity in
let anchorEntity = AnchorEntity(anchor: anchor)
anchorEntity.addChild(childEntity)
view.scene.addAnchor(anchorEntity)
}
} catch {
print(error)
}
}
}
}
}
}