Hi,
Is there a way to create an AnchorEntity that is attached to the window / WindowGroup of a visionOS app, so that there would be a box that aligns with the window?
Thanks for your help!
Hi,
Is there a way to create an AnchorEntity that is attached to the window / WindowGroup of a visionOS app, so that there would be a box that aligns with the window?
Thanks for your help!
Hi @XWDev
AnchorEntity for windows does not exist, but I have a few options for you. If you provide more details on your use case I can help you decide.
Create a model to share the window's transform with the immersive view.
@Observable
class AppModel {
let immersiveSpaceId = "ImmersiveSpace"
var windowTransform:AffineTransform3D?
}
Create the app, passing the app model to both views.
@main
struct WindowAnchorEntityApp: App {
@State var appModel = AppModel()
var body: some SwiftUI.Scene {
WindowGroup {
ContentView()
.environment(appModel)
}
ImmersiveSpace(id: appModel.immersiveSpaceId) {
ImmersiveView()
.environment(appModel)
}
}
}
Create a view for your window that uses a geometry reader to read the window's transform and store it on the app model so the immersive view can use it to set the entity's transform.
struct ContentView: View {
@Environment(AppModel.self) var appModel
@Environment(\.openImmersiveSpace) var openImmersiveSpace
var body: some View {
GeometryReader3D { proxy in
VStack {
}
.onChange(of: proxy.transform(in: .immersiveSpace), initial: true) {
guard var transform = proxy.transform(in: .immersiveSpace) else {return}
// Uncomment these lines to center the entity relative to the window's bounds.
// let frame = proxy.frame(in: .immersiveSpace)
// transform.translation = Vector3D(frame.center.vector)
appModel.windowTransform = transform
}
.padding()
}
.task {
await openImmersiveSpace(id: appModel.immersiveSpaceId)
}
}
}
Create an immersive space that updates the entity's transform when the transform on the app model changes.
struct ImmersiveView: View {
@Environment(AppModel.self) var appModel
@Environment(\.physicalMetrics) var physicalMetrics
let entityAnchoredToWindow:Entity
init() {
self.entityAnchoredToWindow = ModelEntity(mesh: .generateBox(size: 0.05), materials: [SimpleMaterial(color: .red, isMetallic: true)])
}
var body: some View {
@Bindable var appModel = appModel
RealityView { content in
content.add(entityAnchoredToWindow)
}
update: { content in
guard let windowTransform = appModel.windowTransform else {return}
let sceneFromImmersiveSpaceTransform = content.transform(from: .immersiveSpace, to: .scene)
var transform = Transform(sceneFromImmersiveSpaceTransform * windowTransform)
let windowScale = windowTransform.scale
transform.scale = [Float(windowScale.width), Float(windowScale.height), Float(windowScale.depth)]
entityAnchoredToWindow.move(to: transform, relativeTo: nil)
}
}
}
To learn more about converting between coordinate spaces see Dive deep into volumes and immersive spaces
If you would like to see window anchor entities please file an enhancement request via Feedback Assistant.