I want to do the followings automatically:
(1)
asynchronously load a 3D model, for example a vase 50 cm tall(2)
detect the point P on the floor that is vertically down from the world origin (initial location of the device) and set P as the new world origin(3)
place the 3D model from (1) at P acquired in (2).So, in effect, I'd see a vase standing at where I was if I were to step aside.
The fact that I need to wait on both (1) and (2) before I can perform (3), and that I want to perform all of them automatically got me really lost.
How should I approach this problem?
I tried to generate an AnchorEntity with the following:
let floorAnchorEntity = AnchorEntity(plane: [.horizontal],
classification: [.floor],
minimumBounds: [0.5, 0.5])
floorAnchorEntity.name = "floor anchor entity"
arView.scene.addAnchor(floorAnchorEntity)
And load a model 'synchronously' and tether to the anchor entity:
do {
let modelEntity = try Entity.load(named: modelName)
floorAnchorEntity.addChild(modelEntity)
} catch {
assertionFailure("could not load assets.")
}
I was expecting to see the model on the floor but I do not see any thing on the screen. Additionally, 'isActive' flag of the anchor entity is 'false'.
The following approach helps you asynchronously load a Reality Composer scene, extract a model, then create and track a horizontal plane anchor (with a tethered model), and finally set a new World Origin with the help of Combine's subscriber.
However, there will be some discrepancy between the pose of the anchor and the brand-new World Origin if your tracking is bad. So, after 4 seconds, we rectify model's transform.
import RealityKit
import UIKit
import Combine
class ViewController: UIViewController {
@IBOutlet var arView = ARView(frame: .zero)
var subs: [Cancellable] = []
override func viewDidLoad() {
super.viewDidLoad()
arView.debugOptions = [.showWorldOrigin]
Experience.loadBoxAsync { result in
switch result {
case let .success(scene):
guard let model = scene.steelBox else { return }
let anchor = AnchorEntity(.plane(.horizontal,
classification: .floor,
minimumBounds: [0.5, 0.5]))
anchor.addChild(model)
var sub = arView.scene.subscribe(to: SceneEvents.DidAddEntity.self) { _ in
self.arView.session.setWorldOrigin(relativeTransform:
model.transformMatrix(relativeTo: nil))
}
if subs.count == 0 { subs.append(sub) }
arView.scene.anchors.append(anchor)
DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
print(model.position(relativeTo: nil)) // 1
model.setTransformMatrix(matrix_identity_float4x4, relativeTo: nil)
print(model.position(relativeTo: nil)) // 2
}
case let .failure(error):
print("Failed to asynchronously load scene due to \(error)")
}
}
}
}
// 1st print result: SIMD3<Float>(-0.011, 0.018, -0.005)
// 2nd print result: SIMD3<Float>(0.0, 0.0, 0.0)
P. S.
For more info, read this post.