Discuss Spatial Computing on Apple Platforms.

Post

Replies

Boosts

Views

Activity

How to control the position of windows and volumes in immersive space
My app has a window and a volume. I am trying to display the volume on the right side of the window. I know .defaultWindowPlacement can achieve that, but I want more control over the exact position of my volume in relation to my window. I need the volume to move as I move the window so that it always stays in the same position relative to the window. I think I need a way to track the positions of both the window and the volume. If this can be achieved without immersive space, it would be great. If not, how do I do that in immersive space? Current code: import SwiftUI @main struct tiktokForSpacialModelingApp: App { @State private var appModel: AppModel = AppModel() var body: some Scene { WindowGroup(id: appModel.launchWindowID) { LaunchWindow() .environment(appModel) } .windowResizability(.contentSize) WindowGroup(id: appModel.mainViewWindowID) { MainView() .frame(minWidth: 500, maxWidth: 600, minHeight: 1200, maxHeight: 1440) .environment(appModel) } .windowResizability(.contentSize) WindowGroup(id: appModel.postVolumeID) { let initialSize = Size3D(width: 900, height: 500, depth: 900) PostVolume() .frame(minWidth: initialSize.width, maxWidth: initialSize.width * 4, minHeight: initialSize.height, maxHeight: initialSize.height * 4) .frame(minDepth: initialSize.depth, maxDepth: initialSize.depth * 4) } .windowStyle(.volumetric) .windowResizability(.contentSize) .defaultWindowPlacement { content, context in // Get WindowProxy from context based on id if let mainViewWindow = context.windows.first(where: { $0.id == appModel.mainViewWindowID }) { return WindowPlacement(.trailing(mainViewWindow)) } else { return WindowPlacement() } } ImmersiveSpace(id: appModel.immersiveSpaceID) { ImmersiveView() .onAppear { appModel.immersiveSpaceState = .open } .onDisappear { appModel.immersiveSpaceState = .closed } } .immersionStyle(selection: .constant(.progressive), in: .progressive) } }
1
0
77
2d
Can’t Figure Out How to Get My Earth Entity to Rotate on its Axis
I can‘t Figure Out How to Get My Earth Entity to Rotate on its Axis. This is a follow up post from a previous Apple Developer forum post. How would I have the earth (parent) entity rotate CCW underneath the orbiting starship child? I tried adding the following code block to the RealityView but it is not working: if let rotatingEarth = starshipEntity.findEntity(named: "Earth") { rotatingEarth.transform.rotation = simd_quatf.init(angle: 360, axis: SIMD3(x: 0, y: 1, z: 0)) if let animation = try? AnimationResource.generate(with: rotatingEarth as! AnimationDefinition) { rotatingEarth.playAnimation(animation) } } Any advice on getting the earth to rotate? I tried reviewing the Hello World WWDC23 project code, but I was unable to understand the complexity and how that sample project got the earth to rotate. i want to do this for visionOS 1.2. I realize there are some new animation and possible other capabilities coming up in vision 2.0 but I want to try to address this issue in the current released visionOS version.
3
0
170
6d
RealityKit Subdivide
In the Discover RealityKit APIs for iOS, macOS, and visionOS presentation, there was a slide at the end highlighting new features not covered in the video. One of them was surface subdivision, but I have not been able to find any documentation or APIs that support this feature. Does anyone have any further details or how this works in RealityKit?
3
1
178
1w
Understanding the Topology of LowLevelMesh in RealityKitDrawingApp Sample Code
I have recently developed an interest in the shader effects commonly found in Apple's UI and have been studying them. Additionally, as I own a Vision Pro, I have a strong desire to understand LowLevelMesh and am currently analyzing the sample code after watching the related session. The part where I am completely stuck and unable to understand is the initializer section of CurveExtruder. /// Initializes the `CurveExtruder` with the shape to sweep along the curve. /// /// - Parameters: /// - shape: The 2D shape to sweep along the curve. init(shape: [SIMD2<Float>]) { self.shape = shape // Compute topology // // Triangle fan lists each vertex in `shape` once for each ring, except for vertex `0` of `shape` which // is listed twice. Plus one extra index for the end-index (0xFFFFFFFF). let indexCountPerFan = 2 * (shape.count + 1) + 1 var topology: [UInt32] = [] topology.reserveCapacity(indexCountPerFan) // Build triangle fan. for vertexIndex in shape.indices.reversed() { topology.append(UInt32(vertexIndex)) topology.append(UInt32(shape.count + vertexIndex)) } // Wrap around to the first vertex. topology.append(UInt32(shape.count - 1)) topology.append(UInt32(2 * shape.count - 1)) // Add end-index. topology.append(UInt32.max) assert(topology.count == indexCountPerFan) I have tried to understand why the capacity reserved for the topology array is 2 * (shape.count + 1) + 1, but I am struggling to figure it out. I do not understand the principle behind the order in which vertexIndex is added to the topology. The confusion is even greater because, while the comment mentions trianglefan, the actual creation of the LowLevelMesh.Part object uses the topology: .triangleStrip argument. (Did I misunderstand? I know that the topology option includes triangle, but this uses duplicated vertices.) I am feeling very stuck. It's hard to find answers even through search options or LLMs. Maybe this requires specialized knowledge in computer graphics, which makes me feel embarrassed to ask. However, personally, I have tried various directions without external help but still cannot find a clear path, so I am desperately seeking assistance! P.S. As Korean is my primary language, I apologize in advance if there are any awkward or rude expressions.
0
0
107
1d
Content inside volume gets clipped
I am using the Xcode visionOS debugging tool to visualize the bounds of all the containers, but it shows my Entity is inside the Volume. Then why does it get clipped? Is there something wrong with the debugger, or am I missing something? import SwiftUI @main struct RealityViewAttachmentApp: App { var body: some Scene { WindowGroup { ContentView() } .windowStyle(.volumetric) .defaultSize(Size3D(width: 1, height: 1, depth: 1), in: .meters) } } import SwiftUI import RealityKit import RealityKitContent struct ContentView: View { var body: some View { RealityView { content, attachments in if let earth = try? await Entity(named: "Scene", in: realityKitContentBundle) { content.add(earth) if let earthAttachment = attachments.entity(for: "earth_label") { earthAttachment.position = [0, -0.15, 0] earth.addChild(earthAttachment) } if let textAttachment = attachments.entity(for: "text_label") { textAttachment.position = [-0.5, 0, 0] earth.addChild(textAttachment) } } } attachments: { Attachment(id: "earth_label") { Text("Earth") } Attachment(id: "text_label") { VStack { Text("This is just an example") .font(.title) .padding(.bottom, 20) Text("This is just some random content") .font(.caption) } .frame(minWidth: 100, maxWidth: 300, minHeight: 100, maxHeight: 300) .glassBackgroundEffect() } } } }
0
0
48
2d
PreviewApplication open Spatial Video issue
Hi, I have a Spatial Video that I am trying to load in a visionOS app with PreviewApplication API let url = URL(string: "https://mauiman.azureedge.net/videos/SpatialJourney/watermelon_cat.MOV") let item = PreviewItem(url: url!) _ = PreviewApplication.open(items: [item]) When I run the application, I am getting the following error. Did I miss anything? QLUbiquitousItemFetcher: <QLUbiquitousItemFetcher: 0x6000022edfe0> could not create sandbox wrapper. Error: Error Domain=NSPOSIXErrorDomain Code=2 "couldn't issue sandbox extension com.apple.quicklook.readonly for '/videos/SpatialJourney/watermelon_cat.MOV': No such file or directory" UserInfo={NSDescription=couldn't issue sandbox extension com.apple.quicklook.readonly for '/videos/SpatialJourney/watermelon_cat.MOV': No such file or directory} #PreviewItem The screen shows up as: Putting the spatial video locally, I get the following error: let url = URL(fileURLWithPath: "watermelon_cat.MOV") let item = PreviewItem(url: url) _ = PreviewApplication.open(items: [item]) Error getting the size of file(watermelon_cat.MOV -- file:///) with error (Error Domain=NSCocoaErrorDomain Code=260 "The file “watermelon_cat.MOV” couldn’t be opened because there is no such file." UserInfo={NSURL=watermelon_cat.MOV -- file:///, NSFilePath=/watermelon_cat.MOV, NSUnderlyingError=0x600000ea1650 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}) #Generic Any help is greatly appreciated. Thank you in advance.
3
1
111
3d
Are PhysicsJoints supported?
I am trying to add joints via code in my visionOS app. My scenario requires me to combine models from Reality Composer Pro with entities and components from code to generate the dynamic result. I am using the latest visionOS beta and Xcode versions and there is no documentation about joints. I tried to add them via the available API but regardless of how I combine pins, joints and various component, my entities will not get restricted or stay fixated like they are when they are in a child/parent relationship. I am using RealityKit and RealityView in mixed mode. I also searched the whole internet for related information without finding anything. Any insights or pointers appreciated!
0
0
90
2d
visionOS console warning: Trying to convert coordinates between views that are in different UIWindows
Hello, I have an iOS app that is using SwiftUI but the gesture code is written using UIGestureRecognizer. When I run this app on visionOS using the "Designed for iPad" destination and try to use any of my gestures I see this warning in the console: Trying to convert coordinates between views that are in different UIWindows, which isn't supported. Use convertPoint:fromCoordinateSpace: instead. But I don't see any visible problems with the gestures. I see this warning printed out after the gesture takes place but before any of our gesture methods get kicked off. So now I am wondering if this is something we need to deal with or some internal work that needs to happen in UIKit. Does anyone have any thoughts on this?
0
0
115
2d
Not being able to set maximum window size for Views under different tabs
On TikTok on Vision Pro, the home page has different minimum and maximum window heights and widths compared to the search page. Now I am able to set minimum window size for different tab views but maximum size doesn't seem to work Code: // WindowSizeModel.swift import Foundation import SwiftUI enum TabType { case home case search case profile } @Observable class WindowSizeModel { var minWidth: CGFloat = 400 var maxWidth: CGFloat = 500 var minHeight: CGFloat = 400 var maxHeight: CGFloat = 500 func setWindowSize(for tab: TabType) { switch tab { case .home: configureWindowSize(minWidth: 400, maxWidth: 500, minHeight: 400, maxHeight: 500) case .search: configureWindowSize(minWidth: 300, maxWidth: 800, minHeight: 300, maxHeight: 800) case .profile: configureWindowSize(minWidth: 800, maxWidth: 1000, minHeight: 800, maxHeight: 1000) } } private func configureWindowSize(minWidth: CGFloat, maxWidth: CGFloat, minHeight: CGFloat, maxHeight: CGFloat) { self.minWidth = minWidth self.maxWidth = maxWidth self.minHeight = minHeight self.maxHeight = maxHeight } } // tiktokForSpacialModelingApp.swift import SwiftUI @main struct tiktokForSpacialModelingApp: App { @State private var windowSizeModel: WindowSizeModel = WindowSizeModel() var body: some Scene { WindowGroup { MainView() .frame( minWidth: windowSizeModel.minWidth, maxWidth: windowSizeModel.maxWidth, minHeight: windowSizeModel.minHeight, maxHeight: windowSizeModel.maxHeight) .environment(windowSizeModel) } .windowResizability(.contentSize) } } // MainView.swift import SwiftUI import RealityKit struct MainView: View { @State private var selectedTab: TabType = TabType.home @Environment(WindowSizeModel.self) var windowSizeModel; var body: some View { @Bindable var windowSizeModel = windowSizeModel TabView(selection: $selectedTab) { Tab("Home", systemImage: "play.house", value: TabType.home) { HomeView() } Tab("Search", systemImage: "magnifyingglass", value: TabType.search) { SearchView() } Tab("Profile", systemImage: "person.crop.circle", value: TabType.profile) { ProfileView() } } .onAppear { windowSizeModel.setWindowSize(for: TabType.home) } .onChange(of: selectedTab) { oldTab, newTab in if oldTab == newTab { return } else if newTab == TabType.home { windowSizeModel.setWindowSize(for: TabType.home) } else if newTab == TabType.search { windowSizeModel.setWindowSize(for: TabType.search) } else if newTab == TabType.profile { windowSizeModel.setWindowSize(for: TabType.profile) } } } }
1
0
72
5d
What is the difference between an entity Action and Animation
What’s the difference between an action and an animation eg.: FromToByAnimation vs FromToByAction. The documentation on them is pretty similar and I'm not understanding the differences exactly... : S FromToByAnimation → https://developer.apple.com/documentation/realitykit/fromtobyanimation?changes=__2_2 FromToByAction → https://developer.apple.com/documentation/realitykit/fromtobyaction?changes=__2_2 As developer, when should we reach out to use an animation vs action ? 🤔
0
1
86
3d
How Does Update Closure Work in RealityView
I have looked here: Reality View Documentation Found this thread: RealityView Update Closure Thread I am not able to find documentation on how the update closure works. I am loading attachments using reality view's attachment feature (really helpful). I want to remove them programmatically from another file. I found that @State variables can be used. But I am not able to modify them from out side of the ImmersiveView swift file. The second problem I faced was even if I update them inside the file. My debugging statements don't execute. So exactly when does update function run. I know it get's executed at the start (twice for some reason). It also get's executed when I add a window using: openWindow?(id: "ButtonView") I need to use the update closure because I am also not able to get the reference to RealityViewAttachment outside the RealityView struct. My Code(only shown the code necessary. there is other code): @State private var pleaseRefresh = "" @StateObject var model = HandTrackingViewModel() var body: some View { RealityView { content, attachments in if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) { content.add(immersiveContentEntity) } content.add(model.setupContentEntity()) content.add(entityDummy) print("View Loaded") } update: { content, attachments in print("Update Closure Executed") if (model.editWindowAdded) { print("WINDOW ADDED") let theattachment = attachments.entity(for: "sample")! entityDummy.addChild(theattachment) // more code here } } attachments: { Attachment(id: "sample") { Button(action: { model.canEditPos = true model.canRotate = false pleaseRefresh = "changed" }) { HStack { Image(systemName: "pencil.and.outline") .resizable() .scaledToFit() .frame(width: 32, height: 32) Text("Edit Placement") .font(.caption) } .padding(4) } .frame(width: 160, height: 60) } } How can the update method (or the code inside it) run when I want it to? I am new to swift. I apologize if my question seems naive.
1
0
136
4d
Tapping once with both hands only works sometimes in visionOS
Hello! I have an iOS app where I am looking into support for visionOS. I have a whole bunch of gestures set up using UIGestureRecognizer and so far most of them work great in visionOS! But I do see something odd that I am not sure can be fixed on my end. I have a UITapGestureRecognizer which is set up with numberOfTouchesRequired = 2 which I am assuming translates in visionOS to when you tap your thumb and index finger on both hands. When I tap with both hands sometimes this tap gesture gets kicked off and other times it doesn't and it says it only received one touch when it should be two. Interestingly, I see this behavior in Apple Maps where tapping once with both hands should zoom out the map, which only works sometimes. Can anyone explain this or am I missing something?
0
0
114
5d
VisionOS GroupActivities WatchTogether
I have an application that is meant to be a "watch together" GroupActivity using SharePlay that coordinates video playback using AVPlayerPlaybackCoordinator. In the current implementation, the activity begins before opening the AVPlayer, however when clicking the back button within the AVPlayer view, the user is prompted to "End Activity for Everyone" or "End Activity for just me". There is not an option to continue the group activity. My goal is to retain the same GroupSession, even if a user exits the AVPlayer view. Is there a way to avoid ending the session when coordinating playback using the AVPlayerPlaybackCoordinator? private func startObservingSessions() async { sessionInfo = .init() // Await new sessions to watch video together. for await session in MyActivity.sessions() { // Clean up the old session, if it exists. cleanUpSession(groupSession) #if os(visionOS) // Retrieve the new session's system coordinator object to update its configuration. guard let systemCoordinator = await session.systemCoordinator else { continue } // Create a new configuration that enables all participants to share the same immersive space. var configuration = SystemCoordinator.Configuration() // Sets up spatial persona configuration configuration.spatialTemplatePreference = .sideBySide configuration.supportsGroupImmersiveSpace = true // Update the coordinator's configuration. systemCoordinator.configuration = configuration #endif // Set the app's active group session before joining. groupSession = session // Store session for use in sending messages sessionInfo?.session = session let stateListener = Task { await self.handleStateChanges(groupSession: session) } subscriptions.insert(.init { stateListener.cancel() }) // Observe when the local user or a remote participant changes the activity on the GroupSession let activityListener = Task { await self.handleActivityChanges(groupSession: session) } subscriptions.insert(.init { activityListener.cancel() }) // Join the session to participate in playback coordination. session.join() } } /// An implementation of `AVPlayerPlaybackCoordinatorDelegate` that determines how /// the playback coordinator identifies local and remote media. private class CoordinatorDelegate: NSObject, AVPlayerPlaybackCoordinatorDelegate { var video: Video? // Adopting this delegate method is required when playing local media, // or any time you need a custom strategy for identifying media. Without // implementing this method, coordinated playback won't function correctly. func playbackCoordinator(_ coordinator: AVPlayerPlaybackCoordinator, identifierFor playerItem: AVPlayerItem) -> String { // Return the video id as the player item identifier. "\(video?.id ?? -1)" } } /// /// Initializes the playback coordinator for synchronizing video playback func initPlaybackCoordinator(playbackCoordinator: AVPlayerPlaybackCoordinator) async { self.playbackCoordinator = playbackCoordinator if let coordinator = self.playbackCoordinator { coordinator.delegate = coordinatorDelegate } if let activeSession = groupSession { // Set the group session on the AVPlayer instances's playback coordinator // so it can synchronize playback with other devices. playbackCoordinator.coordinateWithSession(activeSession) } } /// A coordinator that acts as the player view controller's delegate object. final class PlayerViewControllerDelegate: NSObject, AVPlayerViewControllerDelegate { let player: PlayerModel init(player: PlayerModel) { self.player = player } #if os(visionOS) // The app adopts this method to reset the state of the player model when a user // taps the back button in the visionOS player UI. func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { Task { @MainActor in // Calling reset dismisses the full-window player. player.reset() } } #endif }
0
0
89
5d