2

When you create an Augmented Reality Project using the standard Xcode template, Xcode adds this swift file to your project:

//
// Experience.swift
// GENERATED CONTENT. DO NOT EDIT.
//

import Foundation
import RealityKit
import simd
import Combine

public enum Experience {

    public enum LoadRealityFileError: Error {
        case fileNotFound(String)
    }

    private static var streams = [Combine.AnyCancellable]()

    public static func loadBox() throws -> Experience.Box {
        guard let realityFileURL = Foundation.Bundle(for: Experience.Box.self).url(forResource: "Experience", withExtension: "reality") else {
            throw Experience.LoadRealityFileError.fileNotFound("Experience.reality")
        }

        let realityFileSceneURL = realityFileURL.appendingPathComponent("Box", isDirectory: false)
        let anchorEntity = try Experience.Box.loadAnchor(contentsOf: realityFileSceneURL)
        return createBox(from: anchorEntity)
    }

    public static func loadBoxAsync(completion: @escaping (Swift.Result<Experience.Box, Swift.Error>) -> Void) {
        guard let realityFileURL = Foundation.Bundle(for: Experience.Box.self).url(forResource: "Experience", withExtension: "reality") else {
            completion(.failure(Experience.LoadRealityFileError.fileNotFound("Experience.reality")))
            return
        }

        var cancellable: Combine.AnyCancellable?
        let realityFileSceneURL = realityFileURL.appendingPathComponent("Box", isDirectory: false)
        let loadRequest = Experience.Box.loadAnchorAsync(contentsOf: realityFileSceneURL)
        cancellable = loadRequest.sink(receiveCompletion: { loadCompletion in
            if case let .failure(error) = loadCompletion {
                completion(.failure(error))
            }
            streams.removeAll { $0 === cancellable }
        }, receiveValue: { entity in
            completion(.success(Experience.createBox(from: entity)))
        })
        cancellable?.store(in: &streams)
    }

    private static func createBox(from anchorEntity: RealityKit.AnchorEntity) -> Experience.Box {
        let box = Experience.Box()
        box.anchoring = anchorEntity.anchoring
        box.addChild(anchorEntity)
        return box
    }

    public class Box: RealityKit.Entity, RealityKit.HasAnchoring {

        public var steelBox: RealityKit.Entity? {
            return self.findEntity(named: "Steel Box")
        }

    }

}

let's focus on the last part of the code

public class Box: RealityKit.Entity, RealityKit.HasAnchoring {
    public var steelBox: RealityKit.Entity? {
        return self.findEntity(named: "Steel Box")
    }
}

this part is apparently loading the cube, named "Steel Box" from the standard Experience.rcproject. But If I rename this string to any random name that is not on the scene, the cube still loads fine and so does the project... and this method is called during initialization!

Why is that? What is this really loading, or not?

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
Duck
  • 34,902
  • 47
  • 248
  • 470

1 Answers1

4

A generated content in Experience.swift file is directly linked to scenes coming from Reality Composer. steelBox property is a "key" to model entity inside RC scene. It's made for developer's convenience to get a quick access to a desired model.

The string "Steel Box" is not compulsory, it's rather optional. You can name your model whatever you want. However, you can even keep this string field empty (in that case Xcode assigns to it a long string of letters and digits or simply an empty string instead of a modified name "Steel Box" – and there will be no steelBox property for you).

"Steel Box" name was automatically used to create `steelBox` property

So, for instance, if you named a model in Reality Composer scene "Plastic Sphere", it automatically creates a variable called plasticSphere:

public var plasticSphere: Entity? { get }


In RealityKit you can access your cube entity this way:

 let boxAnchor = try! Experience.loadBox()
 arView.scene.anchors.append(boxAnchor)

 print(boxAnchor.steelBox!)

or using a subscript for its hierarchy:

 let boxAnchor = try! Experience.loadBox()
 arView.scene.anchors.append(boxAnchor)

 print(boxAnchor.children[0].children[0].children[0])

This results in printing Entity's hierarchy:

enter image description here

As we can see from Console "Steel Box" is just a steelBox's entity name.

print(boxAnchor.steelBox!.name as Any)

// "Steel Box"


However, as I said before, when you leave this field for model's name empty in Reality Composer...

enter image description here

...you can't retrieve your entity by its property name from scene.

You can retrieve it only using children's hierarchy:

let boxAnchor = try! Experience.loadBox()
arView.scene.anchors.append(boxAnchor)

print(boxAnchor.children[0].children[0].children[0])

enter image description here

So, as we can see there's no entity's name (string is empty) in Console now.

But you can assign it at any time:

boxAnchor.steelBox!.name = "My favorite box"
Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
  • ok but how can the scene still load if I change the string there? Apparently that line is the one loading the scene, isn't it? – Duck Jun 24 '20 at 06:17
  • 1
    More brilliant as before. Why Apple documentation is so crappy is a mystery to me. If it was not the brilliance of some here on Stack Overflow, most of us would be finished. Thanks again. – Duck Jun 24 '20 at 09:27
  • 1
    one thing I do not understand is why the model is a subitem of boxAnchor. Working centuries with 3D apps, it makes more sense, model.boxAnchor, instead of boxAnchor.model... anyway... Thanks for explaining that empty model name thing. – Duck Jun 24 '20 at 09:29
  • 1
    In RealityKit an `anchor` is more important thing than models. One anchor may hold a hundred of models and this anchor must be very stable for this purpose. RealityKit's AR app is automatically tracking anchors (not the same way like it happens in ARKit via renderer() methods), not models. So all anchors are located in ARView's scene. Thus you can transform any model thru its anchor (move, rotate, scale), and if you wanna delete a model from a scene, you're removing its anchor, not a model itself. That's why anchors are standing at the top of hierarchy in RealityKit and in Reality Composer. – Andy Jazz Jun 24 '20 at 09:40
  • [another question](https://stackoverflow.com/questions/62554339/which-goal-should-be-chosen-for-arcoachingoverlayview-when-detecting-faces-or-im) about Reality Kit if you want to increase your score.... – Duck Jun 24 '20 at 11:55