You’re now watching this thread. If you’ve opted in to email or web notifications, you’ll be notified when there’s activity. Click again to stop watching or visit your profile to manage watched threads and notifications.
You’ve stopped watching this thread and will no longer receive emails or web notifications when there’s activity. Click again to start watching.
There is a flickering occurring on 3D assets when switching immersive spaces, which is not the nicest user experience. The flickering does occur either when loading the scenes directly from the RealityKitContent package, or from memory (pre-loaded assets).
Since we cannot upload a video illustrating the undesirable behaviour, I have to describe how to setup the project for you to observe it.
To replicate the issue, follow these steps:
Create a new visionOS app using Xcode template, see image.
Configure the project to launch directly into an immersive space (set Preferred Default Scene Session Role to Immersive Space Application Session Role in Info.plist), see image.
Replace all swift files with those you will find in the attached texts.
In the RealityKitContent package, create a scene named YellowSpheres as illustrated below.
In the RealityKitContent package, create a scene named RedSpheres as illustrated below.
Launch the app in debug mode via Xcode and onto the AVP device or simulator
Continuously switch immersive spaces by pressing on buttons Show RedSpheres and Show YellowSpheres.
Observe the 3d assets flicker upon opening of the immersive spaces.
//
// AppModel.swift
// TestFlickeringBetweenImmersiveSpaces
//
import SwiftUI
/// Maintains app-wide state
@MainActor
@Observable
class AppModel {
var immersiveSpaceID = "ImmersiveSpace"
enum ImmersiveSpaceState {
case closed
case inTransition
case open
}
var immersiveSpaceState = ImmersiveSpaceState.closed
}
//
// RedSpheresImmersiveView.swift
// TestFlickeringBetweenImmersiveSpaces
//
import SwiftUI
import RealityKit
import RealityKitContent
struct RedSpheresImmersiveView: View {
@Environment(AppModel.self) var appModel
var body: some View {
RealityView { content, attachments in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "RedSpheres", in: realityKitContentBundle) {
immersiveContentEntity.position = [0.0, 0.1, -2.5]
content.add(immersiveContentEntity)
guard let showYellowSpheresButton = attachments.entity(for: "ShowYellowSpheres") else {
assertionFailure("missing attachment")
return
}
showYellowSpheresButton.position = [0.0, 1, -2.5]
showYellowSpheresButton.scale = scaleForAttachements
content.add(showYellowSpheresButton)
}
} update: { content, attachments in
} placeholder: {
ProgressView()
} attachments: {
Attachment(id: "ShowYellowSpheres") {
Button {
// dismissCurrnt and open next immersive space
appModel.immersiveSpaceID = "YellowSpheres"
} label: {
Text("Show YellowSpheres")
}
}
}
}
}
#Preview(immersionStyle: .mixed) {
RedSpheresImmersiveView()
.environment(AppModel())
}
//
// YellowSpheresImmersiveView.swift
// TestFlickeringBetweenImmersiveSpaces
//
import SwiftUI
import RealityKit
import RealityKitContent
struct YellowSpheresImmersiveView: View {
@Environment(AppModel.self) var appModel
var body: some View {
RealityView { content, attachments in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "YellowSpheres", in: realityKitContentBundle) {
immersiveContentEntity.position = [0.0, 0.1, -2.5]
content.add(immersiveContentEntity)
guard let showRedSpheresButton = attachments.entity(for: "ShowRedSpheres") else {
assertionFailure("missing attachment")
return
}
showRedSpheresButton.position = [0.0, 1, -2.5]
showRedSpheresButton.scale = scaleForAttachements
content.add(showRedSpheresButton)
}
} update: { content, attachments in
} placeholder: {
ProgressView()
} attachments: {
Attachment(id: "ShowRedSpheres") {
Button {
// dismissCurrnt and open next immersive space
appModel.immersiveSpaceID = "RedSpheres"
} label: {
Text("Show RedSpheres")
}
}
}
}
}
#Preview(immersionStyle: .mixed) {
YellowSpheresImmersiveView()
.environment(AppModel())
}
//
// TestFlickeringBetweenImmersiveSpacesApp.swift
// TestFlickeringBetweenImmersiveSpaces
//
import SwiftUI
let scaleForAttachements = SIMD3(2.5, 2.5, 2.5)
@main
struct TestFlickeringBetweenImmersiveSpacesApp: App {
@Environment(\.openImmersiveSpace) var openImmersiveSpace
@Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
@State private var appModel = AppModel()
var body: some Scene {
Group{
ImmersiveSpace(id: "YellowSpheres") {
YellowSpheresImmersiveView()
.environment(appModel)
.onAppear {
appModel.immersiveSpaceState = .open
}
.onDisappear {
appModel.immersiveSpaceState = .closed
}
}
.immersionStyle(selection: .constant(.mixed), in: .mixed)
ImmersiveSpace(id: "RedSpheres") {
RedSpheresImmersiveView()
.environment(appModel)
.onAppear {
appModel.immersiveSpaceState = .open
}
.onDisappear {
appModel.immersiveSpaceState = .closed
}
}
.immersionStyle(selection: .constant(.mixed), in: .mixed)
}
.onChange(of: appModel.immersiveSpaceID) { oldValue, newValue in
Task {
await dismissImmersiveSpace()
let result = await openImmersiveSpace(id: appModel.immersiveSpaceID)
switch result {
case .opened:
print("ImmersiveSpace openned")
case .error:
assertionFailure("could not open ImmersiveSpace")
case .userCancelled:
fallthrough
@unknown default:
assertionFailure("could not open ImmersiveSpace")
}
}
}
}
}