View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Vidéos

Ouvrir le menu Fermer le menu
  • Collections
  • Toutes les vidéos
  • À propos

Plus de vidéos

  • À propos
  • Résumé
  • Code
  • Nouveautés du rendu Metal pour les apps immersives

    Découvrez les dernières améliorations apportées au rendu Metal pour les apps immersives grâce aux Compositor Services. Apprenez à ajouter des effets de survol pour mettre en valeur les éléments interactifs de votre app et à assurer un rendu plus fidèle grâce à la qualité de rendu dynamique. Découvrez le nouveau style d'immersion progressive. Et explorez comment mettre en œuvre des expériences immersives dans les apps macOS en effectuant le rendu de contenu Metal directement du Mac vers le Vision Pro.

    Pour tirer le meilleur parti de cette séance, regardez d'abord « Découvrez Metal pour les apps immersives » de la WWDC23.

    Chapitres

    • 0:00 - Introduction
    • 1:58 - Nouvelles API de boucle de rendu
    • 4:21 - Effets de survol
    • 10:50 - Qualité de rendu dynamique
    • 14:44 - Immersion progressive
    • 18:32 - Rendu spatial macOS
    • 23:51 - Étapes suivantes

    Ressources

    • Analyzing the performance of your Metal app
    • Rendering hover effects in Metal immersive apps
    • Optimizing GPU performance
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC25

    • Allez plus loin avec les jeux Metal 4
    • Découvrez Metal 4
    • Explorer les entrées d’accessoires spatiaux sur visionOS
    • Explorez les jeux Metal 4
    • Nouveautés dans SwiftUI
    • Quoi de neuf dans visionOS 26

    WWDC24

    • Render Metal with passthrough in visionOS

    WWDC23

    • Discover Metal for immersive apps
  • Rechercher dans cette vidéo…
    • 0:01 - Scene render loop

      // Scene render loop
      
      extension Renderer {
          func renderFrame(with scene: MyScene) {
              guard let frame = layerRenderer.queryNextFrame() else { return }
      
              frame.startUpdate()
              scene.performFrameIndependentUpdates()
              frame.endUpdate()
      
              let drawables = frame.queryDrawables()
              guard !drawables.isEmpty else { return }
      
              guard let timing = frame.predictTiming() else { return }
              LayerRenderer.Clock().wait(until: timing.optimalInputTime)
              frame.startSubmission()
              scene.render(to: drawable)
              frame.endSubmission()
          }
      }
    • 5:54 - Layer configuration

      // Layer configuration
      
      struct MyConfiguration: CompositorLayerConfiguration {
          func makeConfiguration(capabilities: LayerRenderer.Capabilities,
                                 configuration: inout LayerRenderer.Configuration) {
              // Configure other aspects of LayerRenderer
      
              let trackingAreasFormat: MTLPixelFormat = .r8Uint
              if capabilities.supportedTrackingAreasFormats.contains(trackingAreasFormat) {
                  configuration.trackingAreasFormat = trackingAreasFormat
              }
          }
      }
    • 7:54 - Object render function

      // Object render function
      
      extension MyObject {
          func render(drawable: Drawable, renderEncoder: MTLRenderCommandEncoder) {
              var renderValue: LayerRenderer.Drawable.TrackingArea.RenderValue? = nil
              if self.isInteractive {
                  let trackingArea = drawable.addTrackingArea(identifier: self.identifier)
                  if self.usesHoverEffect {
                      trackingArea.addHoverEffect(.automatic)
                  }
                  renderValue = trackingArea.renderValue
              }
      		self.draw(with: commandEncoder, trackingAreaRenderValue: renderValue)
          }
      }
    • 8:26 - Metal fragment shader

      // Metal fragment shader
      
      struct FragmentOut
      {
          float4 color [[color(0)]];
          uint16_t trackingAreaRenderValue [[color(1)]];
      };
      
      fragment FragmentOut fragmentShader( /* ... */ )
      {
          // ...
      
          return FragmentOut {
              float4(outColor, 1.0),
              uniforms.trackingAreaRenderValue
          };
      }
    • 10:09 - Event processing

      // Event processing
      
      extension Renderer {
          func processEvent(_ event: SpatialEventCollection.Event) {
             let object = scene.objects.first {
                 $0.identifier == event.trackingAreaIdentifier
             }
             if let object {
                 object.performAction()
             }
         }
      }
    • 13:08 - Quality constants

      // Quality constants
      
      extension MyScene {
          struct Constants {
              static let menuRenderQuality: LayerRenderer.RenderQuality = .init(0.8)
              static let worldRenderQuality: LayerRenderer.RenderQuality = .init(0.6)
              static var maxRenderQuality: LayerRenderer.RenderQuality { menuRenderQuality }
          }
      }
    • 13:32 - Layer configuration

      // Layer configuration
      
      struct MyConfiguration: CompositorLayerConfiguration {
          func makeConfiguration(capabilities: LayerRenderer.Capabilities,
                                 configuration: inout LayerRenderer.Configuration) {
             // Configure other aspects of LayerRenderer
      
             if configuration.isFoveationEnabled {
                 configuration.maxRenderQuality = MyScene.Constants.maxRenderQuality
             }
      }
    • 13:57 - Set runtime render quality

      // Set runtime render quality
      
      extension MyScene {
          var renderQuality: LayerRenderer.RenderQuality {
              switch type {
              case .world: Constants.worldRenderQuality
              case .menu: Constants.menuRenderQuality
              }
          }
      }
      
      extension Renderer {
          func adjustRenderQuality(for scene: MyScene) {
              guard layerRenderer.configuration.isFoveationEnabled else {
                  return;
              }
              layerRenderer.renderQuality = scene.renderQuality
          }
      }
    • 16:58 - SwiftUI immersion style

      // SwiftUI immersion style
      
      @main
      struct MyApp: App {
          @State var immersionStyle: ImmersionStyle
      
          var body: some Scene {
              ImmersiveSpace(id: "MyImmersiveSpace") {
                  CompositorLayer(configuration: MyConfiguration()) { @MainActor layerRenderer in
                      Renderer.startRenderLoop(layerRenderer)
                  }
              }
              .immersionStyle(selection: $immersionStyle, in: .progressive, .full)
          }
      }
    • 17:12 - Layer configuration

      // Layer configuration
      
      struct MyConfiguration: CompositorLayerConfiguration {
          func makeConfiguration(capabilities: LayerRenderer.Capabilities,
                                 configuration: inout LayerRenderer.Configuration) {
              // Configure other aspects of LayerRenderer
              
              if configuration.layout == .layered {
                  let stencilFormat: MTLPixelFormat = .stencil8 
                  if capabilities.drawableRenderContextSupportedStencilFormats.contains(
                      stencilFormat
                  ) {
                      configuration.drawableRenderContextStencilFormat = stencilFormat 
                  }
                  configuration.drawableRenderContextRasterSampleCount = 1
              }
          }
      }
    • 17:40 - Render loop

      // Render loop
      
      struct Renderer {
          let portalStencilValue: UInt8 = 200 // Value not used in other stencil operations
      
          func renderFrame(with scene: MyScene,
                           drawable: LayerRenderer.Drawable,
                           commandBuffer: MTLCommandBuffer) {
              let drawableRenderContext = drawable.addRenderContext(commandBuffer: commandBuffer)
              let renderEncoder = configureRenderPass(commandBuffer: commandBuffer)
              drawableRenderContext.drawMaskOnStencilAttachment(commandEncoder: renderEncoder,
                                                                value: portalStencilValue)
              renderEncoder.setStencilReferenceValue(UInt32(portalStencilValue))
              
              scene.render(to: drawable, renderEncoder: renderEncoder)
      
              drawableRenderContext.endEncoding(commandEncoder: commandEncoder)
              drawable.encodePresent(commandBuffer: commandBuffer)
          }
      }
    • 20:55 - App structure

      // App structure
      
      @main
      struct MyImmersiveMacApp: App {
          @State var immersionStyle: ImmersionStyle = .full
      
          var body: some Scene {
              WindowGroup {
                  MyAppContent()
              }
      
              RemoteImmersiveSpace(id: "MyRemoteImmersiveSpace") {
                  MyCompositorContent()
              }
              .immersionStyle(selection: $immersionStyle, in: .full, .progressive)
         }
      }
    • 21:14 - App UI

      // App UI
      
      struct MyAppContent: View {
          @Environment(\.supportsRemoteScenes) private var supportsRemoteScenes
          @Environment(\.openImmersiveSpace) private var openImmersiveSpace
          @State private var spaceState: OpenImmersiveSpaceAction.Result?
      
          var body: some View {
              if !supportsRemoteScenes {
                  Text("Remote SwiftUI scenes are not supported on this Mac.")
              } else if spaceState != nil {
                  MySpaceStateView($spaceState)
              } else {
                  Button("Open remote immersive space") {
                      Task {
                          spaceState = await openImmersiveSpace(id: "MyRemoteImmersiveSpace")
                      }
                  }
              }
          }
      }
    • 21:35 - Compositor content and ARKit session

      // Compositor content and ARKit session
      
      struct MyCompositorContent: CompositorContent {
          @Environment(\.remoteDeviceIdentifier) private var remoteDeviceIdentifier
      
          var body: some CompositorContent {
              CompositorLayer(configuration: MyConfiguration()) { @MainActor layerRenderer in
                  guard let remoteDeviceIdentifier else { return }
                  let arSession = ARKitSession(device: remoteDeviceIdentifier)
                  Renderer.startRenderLoop(layerRenderer, arSession)
              }
          }
      }
    • 23:17 - C interoperability

      // Swift
      let remoteDevice: ar_device_t = remoteDeviceIdentifier.cDevice
Renderer.start_rendering(layerRenderer, remoteDevice)
      
      // C
      void start_rendering(cp_layer_renderer_t layer_renderer, ar_device_t remoteDevice) {
    ar_session_t session = ar_session_create_with_device(remoteDevice);
    // ...
}
    • 0:00 - Introduction
    • Le rendu Metal sur visionOS, associé aux Compositor Services, apporte cette année de nouvelles fonctionnalités passionnantes : effets de survol sur les objets interactifs, qualité de rendu dynamique pour vos contenus, tout nouveau style d’immersion progressive et possibilité de diffuser du contenu immersif sur le Vision Pro directement depuis macOS.

    • 1:58 - Nouvelles API de boucle de rendu
    • La boucle de rendu de visionOS connaît un changement important cette année. Au lieu de renvoyer un seul objet drawable, l’objet queryDrawables renvoie désormais un tableau contenant 1 ou 2 drawables. Un second drawable est généré automatiquement lors de l’enregistrement de vidéos haute qualité dans Reality Composer Pro. Consultez Xcode pour trouver un modèle afin de bien démarrer. Metal et Metal 4 sont pris en charge.

    • 4:21 - Effets de survol
    • Une fois que vous avez adopté la nouvelle API de boucle de rendu, vous pouvez commencer à implémenter des effets de survol sur les objets interactifs. Grâce aux effets de survol, les utilisateurs peuvent voir quels objets sont interactifs et anticiper les cibles de leurs actions. Le système met en surbrillance de manière dynamique l’objet que l’utilisateur regarde. Par exemple, un jeu de puzzle peut mettre en évidence les pièces qui peuvent être sélectionnées. Vous pouvez le faire en utilisant la nouvelle texture de zones de suivi qui définit les différentes zones interactives de votre scène. Il y a quelques éléments supplémentaires à prendre en compte si vous utilisez le MSAA (anticrénelage multi-échantillons).

    • 10:50 - Qualité de rendu dynamique
    • Vous pouvez restituer votre contenu avec une précision encore plus élevée. En utilisant la qualité de rendu dynamique, vous pouvez ajuster la résolution de votre contenu à la complexité de vos scènes. Cette approche s’appuie sur le rendu fovéal, qui privilégie la densité de pixels là où le spectateur regarde. Vous pouvez définir une qualité de rendu maximale, puis l’ajuster dynamiquement selon les besoins. Une meilleure qualité améliore la clarté, mais consomme plus de mémoire et d’énergie. L’équilibre entre qualité et performance est crucial. Utilisez des outils comme Instruments et le débogueur Metal pour trouver le bon équilibre.

    • 14:44 - Immersion progressive
    • Le contenu peut désormais s’afficher dans un portail immersif progressif. Les utilisateurs contrôlent le niveau d’immersion en tournant la Digital Crown. Cela les ancre dans l’environnement réel et peut les aider à se sentir plus à l’aise devant des scènes complexes avec du mouvement. Pour l’activer, demandez au système de fournir un stencil buffer afin de masquer le contenu hors des limites du portail. Le système applique un effet de fondu sur les bords du portail, créant une transition fluide entre l’environnement réel et le contenu rendu. Les pixels hors du portail ne sont pas rendus, ce qui économise des ressources. Les détails d’implémentation sont partagés.

    • 18:32 - Rendu spatial macOS
    • Le rendu spatial macOS vous permet d’exploiter la puissance de votre Mac pour diffuser des contenus immersifs directement sur l’Apple Vision Pro. Cette fonctionnalité enrichit les apps Mac existantes avec des expériences immersives, comme des aperçus 3D en temps réel. ARKit et worldTrackingProvider sont désormais disponibles sur macOS. Cela vous permet d’interroger la position du Vision Pro dans l’espace. Le RemoteImmersiveSpace de macOS héberge le CompositorLayer et l’ARKitSession, comme le ferait une app native visionOS. Un nouvel ID (remoteDeviceIdentifier) permet de connecter la session ARKit de votre Mac au Vision Pro. Toutes les API concernées disposent d’équivalents natifs en C.

    • 23:51 - Étapes suivantes
    • Ces nouvelles capacités de Metal et des Compositor Services sur visionOS offrent une meilleure interactivité, une fidélité visuelle accrue et un nouveau style d’immersion progressive dans les apps et jeux. Ensuite, consultez « Set the scene with SwiftUI in visionOS » et « What’s new in visionOS 26 ».

Developer Footer

  • Vidéos
  • WWDC25
  • Nouveautés du rendu Metal pour les apps immersives
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines