AnchorEntity on Window(Group)?

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.

  • A Model3D may work for you, but it's not an entity.
  • You can add a RealityView to a window or volume.
  • As a last resort, you can use GeometryReader3D to update an entity's position to match the window's, but this approach is laggy. Here's a snippet to position a cube to match the window's origin (top left corner). Use this when you need your entity to exceed the bounds of your window or volume.

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.

AnchorEntity on Window(Group)?
 
 
Q