View in English

  • Global Nav Open Menu Global Nav Close Menu
  • Apple Developer
Search
Cancel
  • Apple Developer
  • News
  • Discover
  • Design
  • Develop
  • Distribute
  • Support
  • Account
Only search within “”

Quick Links

5 Quick Links

Vidéos

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

Retour à WWDC25

  • À propos
  • Résumé
  • Transcription
  • 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
    • Optimizing GPU performance
    • Rendering hover effects in Metal immersive apps
      • 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…

    Bonjour, je m’appelle Ricardo et je suis ingénieur logiciel chez Apple. Je vais vous montrer de nouvelles fonctionnalités à adopter lorsque vous utilisez Metal pour rendre des contenus immersifs sur l’Apple Vision Pro. L’an dernier, nous avons montré comment tirer parti de Metal, Compositor Services et ARKit, pour créer des expériences immersives lors du rendu direct de votre contenu sur visionOS.

    Vous pouvez mettre en œuvre une expérience totalement immersive, comme dans Demeo de Resolution Games, ou adopter le style d’immersion mixte pour montrer votre contenu dans le monde réel.

    Et grâce aux précieux commentaires de développeurs, le rendu Metal sur visionOS prend en charge de nouvelles fonctionnalités intéressantes.

    Vous pourrez ajouter encore plus de détails et d’effets interactifs à vos apps et jeux. Je vais tout expliquer sur les nouvelles fonctionnalités de Compositor Services dans cette vidéo.

    Pour en tirer le meilleur parti, vous devez connaître le framework Compositor Services et les techniques de rendu Metal. Si vous n’avez jamais utilisé ces technologies, vous en apprendrez davantage à leur sujet dans les vidéos précédentes.

    Pour adopter les nouvelles fonctionnalités, vous devez d’abord apporter des modifications à votre boucle de rendu existante. Je vais vous expliquer comment adopter de nouvelles API pour flexibiliser le pipeline. Après cela, vous pourrez ajouter des effets de survol pour mettre en évidence les éléments interactifs de votre app. Vous pourrez également régler de manière dynamique la résolution de contenu du rendu. Un nouveau style d’immersion progressive permet de régler le niveau d’immersion avec Digital Crown. Et vous pouvez utiliser votre Mac pour le rendu de contenu immersif directement dans Vision Pro ! Tout commence avec les nouvelles API de boucles de rendu. Allons-y.

    Une app immersive Metal commence dans SwiftUI, où vous créez un espace immersif contenant une couche de compositeur.

    Le calque fournit un objet LayerRenderer à utiliser dans votre boucle de rendu. Vous interrogez les images à partir LayerRenderer. À partir de chaque image, vous obtenez des drawables dont les textures sont utilisées pour le rendu de votre contenu. Si vous avez déjà créé une app immersive Metal, vous interrogez un seul drawable pour chaque image rendue. Cette année, Compositor Services dispose d’une nouvelle fonction de requêtes drawables qui renvoie un tableau de drawables. Selon le contexte système, ce tableau contiendra un ou deux drawables. La plupart du temps, vous obtiendrez un seul drawable. Cependant, chaque fois que vous enregistrez une vidéo de haute qualité avec Reality Composer Pro, une image renvoie deux drawables. Vous pouvez identifier les drawables avec la nouvelle propriété cible. Celui de votre écran Vision Pro a la valeur .builtIn et celui de votre enregistrement a la valeur .capture. Pour réaliser des vidéos de haute qualité, consultez la documentation du développeur.

    Vous connaissez peut-être cette fonction de rendu d’image. Après obtention de l’image suivante et mise à jour de l’état de la scène, j’appelle la fonction queryDrawable. Ensuite, j’attends le moment optimal. Et je rends la scène au drawable.

    Maintenant, je remplace .queryDrawable par .queryDrawables. Je m’assure que le tableau n’est pas vide et je fais un .render de ma scène à tous les drawables.

    Xcode comprend un modèle pratique qui explique comment créer une app immersive Metal. C’est un excellent point de départ. Pour en savoir plus, lancez un nouveau projet Xcode pour une app visionOS, et choisissez Metal 4 dans le menu contextuel Immersive Space Renderer.

    Notez que Metal 3 est toujours pris en charge cette année, et vous pouvez l’utiliser sur le modèle Xcode en sélectionnant l’option « Metal ».

    Pour en savoir plus sur la façon d’adopter la dernière version de Metal, consultez « Discover Metal 4 ». Une fois que vous aurez adopté la nouvelle fonction de requête drawables, vous pourrez utiliser toutes les nouvelles fonctionnalités. Dont l’ajout d’effets de survol sur les objets interactifs de votre scène.

    Ils permettent à la personne qui utilise votre app de voir quels objets sont interactifs et d’anticiper les cibles de leurs actions. Le système mettra en surbrillance de manière dynamique l’objet que le spectateur regarde. Par exemple, un jeu de puzzle peut mettre en évidence les pièces qui peuvent être sélectionnées.

    Imaginez une app qui affiche une scène avec plusieurs objets 3D, dont seuls quelques uns permettent une interaction. Je veux m’assurer que les effets de survol ne s’appliquent qu’aux objets interactifs de ma scène. Lorsqu’un objet n’est pas interactif, il n’est pas suivi et il n’a pas d’effet de survol. Donc son rendu est normal. Parallèlement, si un objet est interactif, j’ajoute une nouvelle zone de suivi au drawable. Notez que je dois attribuer un identifiant d’objet unique à chaque zone de suivi que j’enregistre.

    Ensuite, je vérifie si l’objet doit avoir un effet de survol. Si ce n’est pas le cas, je le dessine avec la valeur de rendu de la zone de suivi. Ceci est utile pour détecter les pincements sur mes objets. Mais, si l’objet a un effet de survol, je le configure sur la zone de suivi avant le rendu.

    Dans le code, je dois définir l’utilisation des effets de survol sur mon LayerRenderer. Je définis un format de pixel 8 bits pour la texture des zones de suivi. Il prend en charge jusqu’à 255 objets interactifs simultanés. Je m’assure que le format est pris en charge par mes fonctionnalités de calque et je le définis dans la configuration.

    Dans le code d’enregistrement de la zone de suivi, je vérifie si l’objet est interactif, et dans ce cas, j’enregistre une nouvelle zone de suivi dans le drawable avec mon identifiant d’objet. Conservez les identifiants uniques pendant tout le cycle de vie de vos objets. Ensuite, je vérifie si l’objet a un effet de survol, et dans ce cas, je l’ajoute avec l’attribut .automatic. Cela signifie que le système ajoute automatiquement un effet de survol à l’objet lorsqu’il est regardé. Enfin, je le transmets.

    Avec Compositor Services, le drawable fournit plusieurs textures que votre app peut utiliser pour le rendu du contenu.

    Vous connaissez peut-être la texture des couleurs, ce que voit la personne qui utilise votre app. Il y a aussi la texture de profondeur avec laquelle les couleurs les plus foncées sont les objets les plus éloignés de l’utilisateur. Le système utilise cette texture pour un rendu plus précis de votre contenu affiché lorsque le spectateur se déplace dans la scène. Cette année, il existe également une texture de zones de suivi qui définit les différentes régions interactives de votre scène. Un drawable fournit les textures de couleur et de profondeur. Vous pouvez également interroger la nouvelle texture des zones de suivi. Vous y dessinez des zones distinctes correspondant à vos objets interactifs. Avec les effets de survol, lorsque quelqu’un regarde un objet interactif dans votre scène, le système utilise la texture des zones de suivi pour trouver la région correspondante et applique un effet de survol sur la partie associée de votre texture de couleur. Voici à nouveau la fonction de rendu d’objet avec ma zone de suivi configurée. Pour effectuer le rendu dans la texture des zones de suivi, j’ai besoin d’une valeur de rendu calculée par le système. Je déclare une variable locale pour la stocker, et je l’obtiens à partir de ma zone de suivi correspondante. Si mon objet n’est pas interactif, je peux utiliser la valeur de rendu nil par défaut. Enfin, je le passe à ma fonction draw, d’où je l’enverrai à mon fragment shader.

    Jetons un œil au compilateur de shader.

    Le résultat du fragmentShader a une valeur TrackingAreaRenderValue, avec un index 1 de mappage d’attachement de couleur. J’y ai défini la texture de mes zones de suivi. J’ai lié la valeur de rendu à la structure des uniformes, et je la renvoie dans le résultat du shader avec la valeur de couleur. Maintenant, mon app a des effets de survol interactifs. Il y a autre chose à garder à l’esprit si vous utilisez l’anticrénelage multi-échantillons MSAA (Multisample anti-aliasing).

    Cette technique crée un rendu de texture intermédiaire de plus haute résolution avant de calculer la moyenne des valeurs de couleur sur une fenêtre d’échantillonnage. Cette opération s’effectue à l’aide de l’option de résolution multi-échantillons de votre action de stockage de textures cible. Vous ne pouvez pas résoudre la texture des zones de suivi comme vous résolvez un pixel de couleur. Cela ferait la moyenne de vos valeurs de rendu et donnerait un scalaire invalide qui ne correspond à aucune zone de suivi. Si vous utilisez la résolution multi-échantillons pour votre couleur, vous devez ajouter un outil de résolution personnalisé pour la texture des zones de suivi. Pour ce faire, utilisez l’option de stockage .dontcare avec un pipeline de rendu de vignettes personnalisé. Une bonne stratégie consiste à choisir la valeur de rendu la plus fréquente dans la fenêtre d’échantillonnage sur la texture source MSAA. Pour un examen approfondi des effets de survol, y compris leur utilisation avec MSAA, consultez « Rendering hover effects in Metal immersive apps » dans la documentation du développeur.

    Les zones de suivi permettent également à votre app de gérer les interactions avec les objets plus facilement qu’auparavant. Les événements spatiaux incluent désormais un identifiant de zone de suivi acceptant la valeur Null. J’utilise cet identifiant pour voir s’il correspond à l’un de mes objets de scène. Si je trouve un objet cible, je peux effectuer une action dessus.

    J’ai amélioré l’interactivité de mon app avec des effets de survol. La personne qui utilise mon app peut clairement distinguer les objets exploitables de ceux qui seront activés par pincement. Et cela rend la gestion des événements d’entrée plus facile que jamais ! Désormais, vous pouvez également dessiner votre contenu avec une plus grande fidélité. En utilisant la qualité de rendu dynamique, vous pouvez ajuster la résolution de votre contenu à la complexité de vos scènes.

    Tout d’abord, je vais récapituler le fonctionnement du rendu fovéal. Dans une texture standard non fovéale, les pixels sont répartis uniformément sur toute la surface. Avec le rendu fovéal, le système vous aide à dessiner jusqu’à une texture où le centre a une plus forte densité de pixels. Ainsi, votre app utilise ses ressources informatiques et énergétiques pour améliorer les parties du contenu les plus susceptibles d’être regardées. Cette année, vous pouvez tirer parti de la qualité dynamique pour le rendu fovéal. Vous pouvez contrôler la qualité des images rendues par votre app. Tout d’abord, vous devez spécifier une qualité de rendu maximale adaptée à votre app. Ceci définit la limite supérieure de la session de rendu de votre app. Vous pouvez ensuite ajuster la qualité d’exécution dans la plage choisie en fonction du type de contenu que vous affichez.

    À mesure que vous améliorez la qualité du rendu, la zone de pertinence de votre texture s’élargit, augmentant la taille globale de la texture. Attention, une qualité accrue implique que votre app utilise plus de mémoire et d’énergie. Pour le rendu de texte ou d’éléments d’interface, une qualité de rendu plus élevée est recommandée. Mais si vous montrez une scène 3D complexe, vous pouvez être limité par les ressources informatiques. Pour garantir le bon fonctionnement de votre app, il faut trouver l’équilibre entre qualité visuelle et puissance utilisée par votre app.

    Vous pouvez utiliser Instruments pour analyser les performances en temps réel de votre app, et le débogueur Metal pour analyser en profondeur et optimiser votre code et vos shaders Metal. Rappelez-vous qu’il faut profiler votre app avec vos scènes les plus complexes pour s’assurer qu’elle a assez de temps pour un rendu régulier d’images.

    Consultez la documentation du développeur pour en savoir plus sur l’optimisation de vos apps de rendu Metal.

    Dans cet exemple de code, j’ai profilé mon app et j’ai déterminé que je voulais afficher le menu de mon app avec une qualité 0.8. Ainsi, le texte sera plus net. Je veux un worldRenderQuality de 0.6 parce que c’est une scène complexe. J’ai aussi ajouté une propriété calculée avec le maxRenderQuality que je vais utiliser. Et voici la configuration de mon calque. La qualité de rendu dynamique ne peut être utilisée qu’avec la fovéation, je vérifie donc qu’elle est activée. Ensuite, je définis ma qualité de rendu maximale sur la valeur de ma propriété calculée. N’oubliez pas de la fixer à la valeur minimale raisonnable pour votre contenu. Si vous ne le faites pas, votre app utilisera plus de mémoire qu’il n’en faut.

    Lorsque je charge une nouvelle scène, j’appelle ma fonction d’ajustement de la qualité du rendu. Le réglage de la qualité du rendu n’est possible que si la fovéation est activée. Je passe à mon type de scène et je règle la qualité du rendu en conséquence.

    La transition entre les valeurs de qualité prend un peu de temps, elle n’est pas instantanée. Le système effectue la transition en douceur.

    Grâce à une qualité de rendu dynamique, vos scènes les plus détaillées seront excellentes. La plus haute résolution pour vos scènes peut vraiment apporter une grande précision à vos plus fins détails. Mais n’oubliez pas que vous devrez peut-être réduire la qualité pour des scènes très complexes. Vous pouvez désormais ajuster la qualité du rendu de votre app à votre contenu.

    Depuis cette année, le rendu de votre app Metal peut s’effectuer au sein d’un portail immersif progressif. Grâce au style d’immersion progressive, les personnes qui utilisent votre app peuvent contrôler le niveau d’immersion en tournant la Digital Crown. Ce mode permet de s’ancrer dans l’environnement réel et de se sentir plus à l’aise devant des scènes complexes avec du mouvement. Lorsque vous visualisez une app Metal en mode d’immersion progressive, le système ne restitue que le contenu compris dans le niveau d’immersion défini.

    Voici un exemple de scène de jeu en immersion totale. Et voici la même scène en immersion partielle, après le réglage de la Digital Crown. Comparez les deux scènes. Vous voyez comment économiser de la puissance de calcul en ignorant le rendu de la zone en surbrillance qui sort du portail. Cette partie n’est pas visible, son rendu n’est donc pas nécessaire. De nouvelles API vous permettent d’utiliser un pochoir de portail calculé par le système pour masquer votre contenu. Cet ovale blanc montre le pochoir de portail correspondant. Le tampon de pochoir fonctionne comme un masque pour le rendu de votre scène. Grâce à lui, le rendu ne concerne que le contenu à l’intérieur du portail. Vous pouvez voir que le rendu de la scène n’a pas encore un bord bien net. Le fondu est appliqué par le système en dernière étape de votre tampon de commande, ce qui donne la scène livrée au spectateur.

    Pour utiliser le pochoir et éviter le rendu de contenu inutile, vous devez d’abord configurer votre calque de compositeur. Assurez-vous que le format de pochoir est pris en charge par les fonctionnalités de calque, puis configurez-le. Pour appliquer le pochoir de portail, vous devez ajouter un contexte de rendu au drawable avec votre tampon de commande. Dessiner votre masque sur le pochoir empêchera le rendu des pixels invisibles. Vous devez également terminer l’encodage via votre contexte de rendu, au lieu de terminer directement votre encodeur de commande. De cette façon, l’effet de portail est appliqué efficacement sur votre contenu. Dans mon app, je crée un espace immersif dans SwiftUI, et j’ajoute le style d’immersion progressive comme nouvelle option à ma liste. La personne qui utilise mon app peut alterner entre le style progressif et le style complet. Je configure ensuite le calque. Tout d’abord, sachez que le style d’immersion progressive ne fonctionne qu’avec la disposition en calques. Je définis le format de pochoir souhaité à 8 bits par pixel. Je vérifie que les fonctionnalités prennent en charge ce format, et je le configure. J’ai également défini le nombre d’échantillons à 1, puisque je n’utilise pas MSAA. Si vous utilisez cette technique, définissez-la sur le nombre d’échantillons MSAA.

    Dans mon moteur de rendu, j’ajoute un contexte de rendu au drawable. Je passe le tampon de commande que j’utiliserai pour mes commandes de rendu. Ensuite, je dessine mon masque de portail sur la fixation du pochoir. J’ai sélectionné une valeur de pochoir que je n’utilise dans aucune autre opération de pochoir. Je définis la valeur de référence du pochoir sur l’encodeur de rendu. De cette façon, mon moteur de rendu ne dessinera pas la zone située en dehors du niveau d’immersion actuel. Après le rendu de la scène, notez comment je termine l’encodage sur mon contexte de rendu drawable.

    Pour voir un exemple fonctionnel d’un moteur de rendu avec le style d’immersion progressive, choisissez l’option progressive dans le modèle visionOS Metal app. Cela vous permettra de créer une app Metal de style portail.

    Pour finir, explorons le rendu spatial macOS.

    Jusqu’à présent, j’ai parlé de créer des expériences immersives natives sur Vision Pro. Cette année, vous pouvez exploiter la puissance de votre Mac pour le rendu et la diffusion de contenus immersifs directement sur Vision Pro. Cela peut servir à ajouter des expériences immersives à des apps Mac existantes.

    Par exemple, une app de modélisation 3D peut prévisualiser directement vos scènes sur Vision Pro. Vous pouvez aussi créer une app macOS immersive en partant de zéro. De cette façon, vous pouvez créer des expériences immersives complexes à forte capacité de calcul, sans être limité par la consommation d’énergie de Vision Pro. Démarrer une session immersive à distance depuis une app Mac est très simple. Lorsque vous ouvrez un espace immersif dans macOS, vous êtes invité à accepter la connexion sur Vision Pro.

    Faites cela, et vous commencerez à voir le rendu de votre contenu immersif sur Mac.

    Une app Mac type est conçue avec SwiftUI ou AppKit. Vous utilisez l’un ou l’autre de ces frameworks pour créer et afficher des fenêtres. Le système effectue le rendu du contenu de votre fenêtre avec Core Animation. Vous pouvez adopter divers frameworks macOS pour implémenter les fonctionnalités de votre app. Et le système affiche votre contenu sur l’écran de votre Mac. Pour créer une expérience immersive compatible avec Mac, vous utilisez les mêmes frameworks de création des apps immersives visionOS. Tout d’abord, vous utilisez SwiftUI avec le nouveau type de scène RemoteImmersiveSpace. Vous adoptez ensuite le framework Compositor Services. Vous faites appel à ARKit et Metal pour placer et afficher vos contenus. Et le système affiche directement votre scène immersive sur Vision Pro. L’espace immersif distant de macOS héberge le calque compositeur et la session ARKit, comme le fait une app visionOS native. Ils se connectent simplement à votre écran et à vos capteurs Vision Pro. Pour connecter votre session ARKit à visionOS, vous transmettez un nouvel objet d’environnement SwiftUI remoteDeviceIdentifier à l’initialiseur de session. Voici la structure d’une app immersive pour Mac.

    Je définis un nouvel espace immersif distant, qui intègre mon contenu compositeur. Je montrerai comment il utilise le calque compositeur dans un instant. Sur Mac, seuls les styles d’immersion progressive et intégrale sont pris en charge. Dans l’interface de mon app Mac, j’utilise la nouvelle variable d’environnement supportsRemoteScenes pour vérifier si c’est le cas de mon Mac. Je peux personnaliser mon interface utilisateur pour afficher un message si les scènes distantes ne sont pas prises en charge. Si elles sont prises en charge, et que je n’ai pas encore ouvert l’espace immersif, je peux le lancer. La dernière partie de mon app est mon contenu compositeur. Il y a mon calque compositeur et ma session ARKit. Je crée et utilise un calque compositeur comme je l’ai fait sur visionOS. J’accède au nouvel objet d’environnement SwiftUI remoteDeviceIdentifier et le transmets à l’initialiseur de session ARKit. Cela connectera la session ARKit de mon Mac à Vision Pro. Enfin, je lance ma boucle de rendu comme je le ferais sur une app immersive Metal type.

    ARKit et worldTrackingProvider sont désormais disponibles sur macOS. Cela vous permet d’interroger l’emplacement de Vision Pro dans l’espace. Comme vous le feriez dans une app immersive native, vous utiliserez la pose de l’appareil pour mettre à jour votre scène et vos drawables avant le rendu. Une app spatiale macOS prend en charge n’importe quel appareil d’entrée connecté à votre Mac. Vous pouvez utiliser les commandes du clavier et de la souris. Vous pouvez aussi connecter une manette de jeu et gérer la saisie à l’aide du framework Manette de jeu. De plus, vous pouvez utiliser des pincements sur les éléments interactifs de votre scène immersive en utilisant le modificateur onSpatialEvent sur votre LayerRenderer.

    Depuis cette année : vous pouvez également créer des scènes SwiftUI à partir d’un AppKit ou d’une app UIKit existante. C’est un excellent moyen d’enrichir les apps Mac existantes de nouvelles expériences immersives. Vous trouverez plus d’informations sur la procédure à suivre dans « What’s new in SwiftUI ».

    Il est courant que les moteurs de rendu soient implémentés en C ou C++. Toutes les API mentionnées ont des équivalents natifs en C. Les types C du framework Compositor Services commencent par le préfixe ’cp’. Ils utilisent des modèles et des conventions similaires à ceux des bibliothèques C familières telles que Core Foundation. Pour ARKit, la propriété cDevice vous donne un identifiant d’appareil distant compatible C. Vous pouvez le passer dans votre framework C et initialiser votre session ARKit avec la fonction create_with_device. Vous disposez maintenant de tous les éléments nécessaires pour utiliser votre Mac et créer des contenus immersifs sur Vision Pro.

    J’ai hâte de voir comment vous utiliserez ces nouvelles fonctionnalités pour augmenter vos apps immersives. Elles permettent une meilleure interactivité, une plus grande fidélité et le nouveau style d’immersion progressive. J’ai hâte de voir ce que vous ferez des nouvelles fonctionnalités spatiales de macOS. Pour en savoir plus sur la façon de faire passer vos apps immersives au niveau supérieur, consultez la page « Set the scene with SwiftUI in visionOS ». Et pour une vue d’ensemble des autres améliorations de la plate-forme, consultez « What’s new in visionOS ». Merci de votre attention.

    • 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
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • App Store
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Fonts
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Open Source
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Sample Code
    • Tutorials
    • Downloads
    • Forums
    • Videos
    Open Menu Close Menu
    • Support Articles
    • Contact Us
    • 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
    • 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
    Get the Apple Developer app.
    Copyright © 2025 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines