Panorama Photo

How can I show a panorama photo as is done in the Photos app for Vision Pro?

Replies

If anyone runs into this, please file an enhancement request at https://feedbackassistant.apple.com. There is no high-level panoramic API to do this.

Some steps you can take to do this yourself are as follows:

  • Create (and then load) a "pano mesh"
  • Load the pano as a TextureResource
  • Put the texture in an UnlitMaterial
  • Use the material with the pano mesh
  • Scale the pano mesh based on the aspect ratio of the texture

In code, this looks like:

RealityView { content in
            
            do {
                
                // Load the scene that has the pano mesh.
                let scene = try await Entity(named: "PanoMesh", in: realityKitContentBundle)
                
                // Find the entity that has the model component holding the pano mesh.
                let panoEntity = scene.findEntity(with: ModelComponent.self)!
                
                // Get the model component.
                var panoModel = panoEntity.components[ModelComponent.self]!
                
                // Create a new UnlitMaterial (you most likely don't want to apply lighting to a pano image).
                var material = UnlitMaterial()
                // Load the pano texture from the main bundle.
                let texture = try! await TextureResource(named: "MyPano")
                
                // Set the color of the unlit material to the pano image (tint white to make it render normally).
                material.color = .init(tint: .white, texture: .init(texture))
                
                // Set the materials of the model component with the new material.
                panoModel.materials = [material]
                
                // Set the updated model component on the entity.
                panoEntity.components.set(panoModel)
                
                // Calculate the aspect ratio of the pano.
                let aspectRatio = Float(texture.width) / Float(texture.height)
                
                // Scale the scene according to the aspect ratio of the pano.
                scene.scale = [aspectRatio, 1, aspectRatio]
                
                // This is usually a good position for content when an ImmersiveScene launches.
                scene.position = [0, 1.3, -1.3]
                
                // This constraint restricts the mesh from appearing greater than 3 meters wide / deep.
                if aspectRatio > 3 {
                    scene.scale *= 3 / aspectRatio
                }
                
                // Add the scene to the view's content.
                content.add(scene)
                
            } catch {
                fatalError(error.localizedDescription)
            }
        }
extension Entity {
    func findEntity(where predicate: (Entity) -> Bool) -> Entity? {
        
        var stack = [self]
        
        while let next = stack.popLast() {
            
            if predicate(next) {
                return next
            } else {
                stack.append(contentsOf: next.children)
            }
        }
        return nil
    }
    
    func findEntity<C: Component>(with componentType: C.Type) -> Entity? {
        findEntity { $0.components.has(componentType) }
    }
}