Adapt distance/depth of view relative to user

Hi,

I'm currently working on some messages that should appear in front of the user depending on the system's state of my visionOS app. How am I able to change the distance of the appearing message relative to the user if the message is displayed as a View. Or is this only possible if I would create an enitity for that message, and then set apply .setPosition() and .relativeTo() e.g. the head anchor? Currently I can change the x and y coordinates of the view as it works within a 2D space, but as I'm intending to display that view in my immersive space, it would be cool if I can display my message a little bit further away in the user's UI, as it currently is a little bit to close in the user's view. If there is a solution without the use of entities I would prefer that one.

Thank you for your help!

Below an example:

Feedback.swift

import SwiftUI

struct Feedback: View {
    let message: String
    
    var body: some View {
        VStack {
                Text(message)
            }
        }
        .position(x: 0, y: -850) // how to adapt distance/depth relative to user in UI?
    }
}

ImmersiveView.swift


import SwiftUI
import RealityKit

struct ImmersiveView: View {

    @State private var feedbackMessage = "Hello World"

    public var body: some View {
        VStack {}
        .overlay(
            Feedback(message: feedbackMessage)
        )
        
        RealityView { content in
            
            let configuration = SpatialTrackingSession.Configuration(tracking: [.hand])
            let spatialTrackingSession = SpatialTrackingSession.init()
            _ = await spatialTrackingSession.run(configuration)
            
            // Head
            let headEntity = AnchorEntity(.head)
            content.add(headEntity)
        }
    }
}
Answered by Vision Pro Engineer in 803783022

Hi @XWDev

It sounds like you want to position a SwiftUI view, in 3D space, relative to the user. RealityView attachments is the appropriate API to use for this use case.

Enhance your spatial computing app with RealityKit contains a good overview of the API.

If you use a HeadAnchor the attachment will be head locked to the user (like a HUD). If that's undesired, you can use queryDeviceAnchor(atTimestamp:) to obtain the position of the device; you can use that position to initialize the position of the attachment.

Accepted Answer

Hi @XWDev

It sounds like you want to position a SwiftUI view, in 3D space, relative to the user. RealityView attachments is the appropriate API to use for this use case.

Enhance your spatial computing app with RealityKit contains a good overview of the API.

If you use a HeadAnchor the attachment will be head locked to the user (like a HUD). If that's undesired, you can use queryDeviceAnchor(atTimestamp:) to obtain the position of the device; you can use that position to initialize the position of the attachment.

Thank you for your answer!

Maybe as a follow-up question. To me, it does not seem to be entirely clear why, when I'm trying to display my attachment, no matter the positioning, it will always be hidden/covered by the window. I'm trying to achieve displaying the attachment one layer above/in front of the window.

Thank you for your help!

ContentView.swift

import SwiftUI
import RealityKit

struct ContentView: View {
    
    @Environment(\.openImmersiveSpace) private var openImmersiveSpace
    
    public var body: some View {
        VStack {
            Text("Hello World")
                .font(.largeTitle)
            Button("Start") {
                Task {
                    await openImmersiveSpace(id: "AppSpace")
                }
            }
        }
    }
}

ImmersiveView.swift

import SwiftUI
import RealityKit

struct ImmersiveView: View {
    var loader: EnvironmentLoader
    
    public var body: some View {
        
        RealityView { content, attachments in
            content.add(try! await loader.getEntity())
           
            let headEntity = AnchorEntity(.head)
            content.add(headEntity)
            
            if let text = attachments.entity(for: "at01") {
                text.position = [0, 0, -0.25]
                headEntity.addChild(text)
            }
                       
        }
        attachments: {
            Attachment(id: "at01") {
                Text("Hello World!")
                    .font(.extraLargeTitle)
                    .padding()              
            }     
        }
    }
}

App.swift

import SwiftUI

@main
private struct App: App {    
    @State var loader = EnvironmentLoader()
    
    public var body: some Scene {
        WindowGroup {
            ContentView()
    }
        
    ImmersiveSpace(id: "AppSpace") { 
        ImmersiveView(loader: loader)
                
    }
    .immersionStyle(selection: .constant(.progressive), in: .progressive)
    }
}
Adapt distance/depth of view relative to user
 
 
Q