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
  • Mieux ensemble : SwiftUI et RealityKit

    Découvrez comment combiner harmonieusement SwiftUI et RealityKit dans visionOS 26. Nous explorerons les améliorations apportées à Model3D, y compris la prise en charge de l'animation et de ConfigurationCatalog, et démontrerons des transitions en douceur vers RealityView. Vous apprendrez à tirer parti des animations SwiftUI pour piloter les modifications de composants RealityKit, à mettre en œuvre des manipulations interactives, à utiliser les nouveaux composants SwiftUI pour des interactions plus riches et à observer les modifications apportées à RealityKit depuis votre code SwiftUI. Nous verrons également comment utiliser la conversion unifiée des coordonnées pour effectuer des transformations de coordonnées entre différents frameworks.

    Chapitres

    • 0:00 - Introduction
    • 1:24 - Améliorations de Model3D
    • 6:13 - Transition vers RealityView
    • 11:52 - Manipulation d’objets
    • 15:35 - Composants SwiftUI
    • 19:08 - Flux d’informations
    • 24:56 - Conversion de coordonnées unifiées
    • 27:01 - Animation
    • 29:41 - Étapes suivantes

    Ressources

    • Rendering hover effects in Metal immersive apps
    • Canyon Crosser: Building a volumetric hike-planning app
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC24

    • Compose interactive 3D content in Reality Composer Pro

    WWDC23

    • Discover Observation in SwiftUI

    WWDC21

    • Dive into RealityKit 2

    WWDC20

    • Data Essentials in SwiftUI
  • Rechercher dans cette vidéo…
    • 1:42 - Sparky in Model3D

      struct ContentView: View {
        var body: some View {
          Model3D(named: "sparky")
        }
      }
    • 1:52 - Sparky in Model3D with a name sign

      struct ContentView: View {
        var body: some View {
          HStack {
            NameSign()
            Model3D(named: "sparky")
          }
        }
      }
    • 3:18 - Display a model asset in a Model3D and present playback controls​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      struct RobotView: View {
        @State private var asset: Model3DAsset?
        var body: some View {
          if asset == nil {
            ProgressView().task { asset = try? await Model3DAsset(named: "sparky") }
          }
        }
      }
    • 3:34 - Display a model asset in a Model3D and present playback controls​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      struct RobotView: View {
        @State private var asset: Model3DAsset?
        var body: some View {
          if asset == nil {
            ProgressView().task { asset = try? await Model3DAsset(named: "sparky") }
          } else if let asset {
            VStack {
              Model3D(asset: asset)
              AnimationPicker(asset: asset)
            }
          }
        }
      }
    • 4:03 - Display a model asset in a Model3D and present playback controls​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      struct RobotView: View {
        @State private var asset: Model3DAsset?
        var body: some View {
          if asset == nil {
            ProgressView().task { asset = try? await Model3DAsset(named: "sparky") }
          } else if let asset {
            VStack {
              Model3D(asset: asset)
              AnimationPicker(asset: asset)
              if let animationController = asset.animationPlaybackController {
                RobotAnimationControls(playbackController: animationController)
              }
            }
          }
        }
      }
    • 4:32 - Pause, resume, stop, and change the move the play head in the animation​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      struct RobotAnimationControls: View {
        @Bindable var controller: AnimationPlaybackController
      
        var body: some View {
          HStack {
            Button(controller.isPlaying ? "Pause" : "Play") {
              if controller.isPlaying { controller.pause() }
              else { controller.resume() }
            }
      
            Slider(
              value: $controller.time,
              in: 0...controller.duration
            ).id(controller)
          }
        }
      }
    • 5:41 - Load a Model3D using a ConfigurationCatalog​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      struct ConfigCatalogExample: View {
        @State private var configCatalog: Entity.ConfigurationCatalog?
        @State private var configurations = [String: String]()
        @State private var showConfig = false
        var body: some View {
          if let configCatalog {
            Model3D(from: configCatalog, configurations: configurations)
              .popover(isPresented: $showConfig, arrowEdge: .leading) {
                ConfigPicker(
                  name: "outfits",
                  configCatalog: configCatalog,
                  chosenConfig: $configurations["outfits"])
              }
          } else {
            ProgressView()
              .task {
                await loadConfigurationCatalog()
              }
          }
        }
      }
    • 6:51 - Switching from Model3D to RealityView

      struct RobotView: View {
        let url: URL = Bundle.main.url(forResource: "sparky", withExtension: "reality")!
      
        var body: some View {
          HStack {
            NameSign()
            RealityView { content in
              if let sparky = try? await Entity(contentsOf: url) {
                content.add(sparky)
              }
            }
          }
        }
      }
    • 7:25 - Switching from Model3D to RealityView with layout behavior

      struct RobotView: View {
        let url: URL = Bundle.main.url(forResource: "sparky", withExtension: "reality")!
      
        var body: some View {
          HStack {
            NameSign()
            RealityView { content in
              if let sparky = try? await Entity(contentsOf: url) {
                content.add(sparky)
              }
            }
            .realityViewLayoutBehavior(.fixedSize)
          }
        }
      }
    • 8:48 - Switching from Model3D to RealityView with layout behavior and RealityKit animation

      struct RobotView: View {
        let url: URL = Bundle.main.url(forResource: "sparky", withExtension: "reality")!
      
        var body: some View {
          HStack {
            NameSign()
            RealityView { content in
              if let sparky = try? await Entity(contentsOf: url) {
                content.add(sparky)
                sparky.playAnimation(getAnimation())
              }
            }
            .realityViewLayoutBehavior(.fixedSize)
          }
        }
      }
    • 10:34 - Add 2 particle emitters; one to each side of the robot's head

      func setupSparks(robotHead: Entity) {
        let leftSparks = Entity()
        let rightSparks = Entity()
      
        robotHead.addChild(leftSparks)
        robotHead.addChild(rightSparks)
      
        rightSparks.components.set(sparksComponent())
        leftSparks.components.set(sparksComponent())
      
        leftSparks.transform.rotation = simd_quatf(Rotation3D(
          angle: .degrees(180),
          axis: .y))
      
        leftSparks.transform.translation = leftEarOffset()
        rightSparks.transform.translation = rightEarOffset()
      }
      
      // Create and configure the ParticleEmitterComponent
      func sparksComponent() -> ParticleEmitterComponent { ... }
    • 12:30 - Apply the manipulable view modifier

      struct RobotView: View {
        let url: URL
        var body: some View {
          HStack {
            NameSign()
            Model3D(url: url)
              .manipulable()
          }
        }
      }
    • 12:33 - Allow translate, 1- and 2-handed rotation, but not scaling

      struct RobotView: View {
        let url: URL
        var body: some View {
          HStack {
            NameSign()
            Model3D(url: url)
              .manipulable(
                operations: [.translation,
                             .primaryRotation,
                             .secondaryRotation]
             )
          }
        }
      }
    • 12:41 - The model feels heavy with high inertia

      struct RobotView: View {
        let url: URL
        var body: some View {
          HStack {
            NameSign()
            Model3D(url: url)
              .manipulable(inertia: .high)
          }
        }
      }
    • 13:18 - Add a ManipulationComponent to an entity​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

      RealityView { content in
        let sparky = await loadSparky()
        content.add(sparky)
        ManipulationComponent.configureEntity(sparky)
      }
    • 13:52 - Add a ManipulationComponent to an entity​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ with configuration

      RealityView { content in
        let sparky = await loadSparky()
        content.add(sparky)
        ManipulationComponent.configureEntity(
          sparky,
          hoverEffect: .spotlight(.init(color: .purple)),
          allowedInputTypes: .all,
          collisionShapes: myCollisionShapes()
        )
      }
    • 14:08 - Manipulation interaction events

      public enum ManipulationEvents {
      
        /// When an interaction is about to begin on a ManipulationComponent's entity
        public struct WillBegin: Event { }
        
        /// When an entity's transform was updated during a ManipulationComponent
        public struct DidUpdateTransform: Event { }
      
        /// When an entity was released
        public struct WillRelease: Event { }
      
        /// When the object has reached its destination and will no longer be updated
        public struct WillEnd: Event { }
      
        /// When the object is directly handed off from one hand to another
        public struct DidHandOff: Event { }
      }
    • 14:32 - Replace the standard sounds with custom ones

      RealityView { content in
        let sparky = await loadSparky()
        content.add(sparky)
      
        var manipulation = ManipulationComponent()
        manipulation.audioConfiguration = .none
        sparky.components.set(manipulation)
      
        didHandOff = content.subscribe(to: ManipulationEvents.DidHandOff.self) { event in
          sparky.playAudio(handoffSound)
        }
      }
    • 16:19 - Builder based attachments

      struct RealityViewAttachments: View {
        var body: some View {
          RealityView { content, attachments in
            let bolts = await loadAndSetupBolts()
            if let nameSign = attachments.entity(
              for: "name-sign"
            ) {
              content.add(nameSign)
              place(nameSign, above: bolts)
            }
            content.add(bolts)
          } attachments: {
            Attachment(id: "name-sign") {
              NameSign("Bolts")
            }
          }
          .realityViewLayoutBehavior(.centered)
        }
      }
    • 16:37 - Attachments created with ViewAttachmentComponent

      struct AttachmentComponentAttachments: View {
        var body: some View {
          RealityView { content in
            let bolts = await loadAndSetupBolts()
            let attachment = ViewAttachmentComponent(
                rootView: NameSign("Bolts"))
            let nameSign = Entity(components: attachment)
            place(nameSign, above: bolts)
            content.add(bolts)
            content.add(nameSign)
          }
          .realityViewLayoutBehavior(.centered)
        }
      }
    • 17:04 - Targeted to entity gesture API

      struct AttachmentComponentAttachments: View {
        @State private var bolts = Entity()
        @State private var nameSign = Entity()
      
        var body: some View {
          RealityView { ... }
          .realityViewLayoutBehavior(.centered)
          .gesture(
            TapGesture()
              .targetedToEntity(bolts)
              .onEnded { value in
                nameSign.isEnabled.toggle()
              }
          )
        }
      }
    • 17:10 - Gestures with GestureComponent

      struct AttachmentComponentAttachments: View {
        var body: some View {
          RealityView { content in
            let bolts = await loadAndSetupBolts()
            let attachment = ViewAttachmentComponent(
                rootView: NameSign("Bolts"))
            let nameSign = Entity(components: attachment)
            place(nameSign, above: bolts)
            bolts.components.set(GestureComponent(
              TapGesture().onEnded {
                nameSign.isEnabled.toggle()
              }
            ))
            content.add(bolts)
            content.add(nameSign)
          }
          .realityViewLayoutBehavior(.centered)
        }
      }
    • 0:00 - Introduction
    • Découvrez les améliorations de RealityKit et SwiftUI. Elles permettent une intégration transparente de l’interface utilisateur traditionnelle et du contenu 3D interactif. Parmi les principales mises à jour figurent les améliorations apportées à Model3D et RealityView, l’introduction de l’API Object Manipulation, de nouveaux types de composants, le flux de données bidirectionnel entre SwiftUI et RealityKit, une conversion plus facile de l’espace de coordonnées et des animations pilotées par SwiftUI pour les composants RealityKit.

    • 1:24 - Améliorations de Model3D
    • Dans visionOS 26, Model3D permet d’afficher des modèles 3D avec des animations et de les charger à partir d’un « ConfigurationCatalog ». Vous pouvez désormais créer des expériences 3D interactives avec seulement quelques lignes de code. Utilisez le nouveau type « Model3DAsset » pour charger et contrôler les animations, et « ConfigurationCatalog » pour basculer entre les différentes représentations d’une entité, telles que des tenues ou des types de corps. L’exemple d’un robot nommé Sparky, que vous pouvez animer, habiller de différentes tenues et contrôler à l’aide des vues et des sélecteurs SwiftUI, afin qu’il soit prêt à interagir avec d’autres robots dans une serre virtuelle, présente ces fonctionnalités.

    • 6:13 - Transition vers RealityView
    • Pour ajouter un émetteur de particules à un modèle 3D au moment de l’exécution, vous devez passer de l’utilisation de « Model3D » à « RealityView » dans RealityKit, car Model3D ne prend pas en charge l’ajout de composants. RealityView est chargé avec l’entité modèle, mais cela pose des problèmes de mise en forme, car il occupe par défaut tout l’espace disponible. Le modificateur « realityViewLayoutBehavior » est appliqué avec « fixedSize » pour résoudre ce problème, afin que RealityView s’adapte aux limites initiales du modèle. Il existe trois options « realityViewLayoutBehavior » différentes : « flexible », « centered » et « fixedSize », chacune affectant le point d’origine de RealityView sans repositionner les entités. Utilisez Reality Composer Pro pour concevoir des émetteurs de particules configurables dans le code. Les émetteurs de particules sont ajoutés aux entités en tant que composants. RealityKit est basé sur le paradigme « Entity Component System ». L’exemple ajoute des émetteurs de particules pour créer des effets d’étincelles, en utilisant des entités invisibles comme conteneurs pour les étincelles. RealityView est idéal pour la création détaillée et le contrôle fin du comportement du contenu 3D, tandis que Model3D convient à l’affichage de ressources 3D autonomes. Vous pouvez passer en douceur de l’un à l’autre, selon vos besoins.

    • 11:52 - Manipulation d’objets
    • La nouvelle API Object Manipulation de visionOS 26 permet d’interagir avec des objets virtuels dans des apps qui utilisent SwiftUI et RealityKit. Il est possible de déplacer, faire pivoter et mettre à l’échelle des objets avec les mains, et même de passer des objets d’une main à l’autre. Pour les vues SwiftUI, vous pouvez appliquer le modificateur « manipulable », ce qui permet de personnaliser les opérations prises en charge et l’inertie des objets. Dans RealityKit, ajoutez le « ManipulationComponent » aux entités via la fonction statique « configureEntity », qui ajoute également des composants de type collision, cible d’entrée et effet de survol. La fonction a plusieurs paramètres pour la personnalisation du comportement. Abonnez-vous à des « ManipulationEvents » déclenchés lors d’interactions, telles que les démarrages, les arrêts, les mises à jour, les versions et les transferts, afin de mettre à jour l’état de l’app et de personnaliser l’expérience, notamment en remplaçant les sons par défaut par des ressources audio personnalisées.

    • 15:35 - Composants SwiftUI
    • Les nouveaux composants SwiftUI et RealityKit améliorent les interactions et la connexion de l’utilisateur au sein des scènes RealityKit. Ces composants vous permettent d’intégrer en toute transparence les vues SwiftUI dans des environnements 3D. Parmi les principales fonctionnalités, citons le « ViewAttachmentComponent », pour ajouter des vues SwiftUI directement aux entités ; le « GestureComponent », pour rendre les entités réactives au toucher et aux gestes ; et le « PresentationComponent », pour présenter des vues SwiftUI, telles que des popovers, au sein de la scène. Le paramètre de configuration de « PresentationComponent » correspond au type de présentation à afficher. Ces améliorations simplifient le processus de développement, vous permettant de créer des expériences plus dynamiques et plus captivantes. Dans l’exemple, un robot nommé Bolts peut avoir un nom qui s’allume et s’éteint d’un simple geste, et il est possible de choisir la tenue de Bolts dans un menu contextuel, le tout dans l’environnement immersif de RealityKit.

    • 19:08 - Flux d’informations
    • Dans visionOS 26, les entités sont désormais observables, ce qui permet aux entités, telles que le robot Bolts, de notifier d’autres codes lorsque leurs propriétés changent. Cela est particulièrement utile pour suivre les mouvements de Bolts lorsqu’il arrose les plantes dans la serre. L’exemple utilise SwiftUI pour implémenter une mini-carte qui affiche la position de Bolts en temps réel. En accédant à la propriété de position observable de Bolts, SwiftUI met automatiquement à jour la mini-carte chaque fois que Bolts se déplace. Ce flux de données bidirectionnel entre SwiftUI et RealityKit, rendu possible par des entités observables, constitue un nouvel outil important. Cette nouvelle fonctionnalité d’observation crée aussi des boucles infinies si elle n’est pas gérée avec soin. Pour éviter ces boucles, faites attention à l’endroit où vous modifiez l’état observé. Ne modifiez pas l’état observé lors de la fermeture « update » de « RealityView », au risque de déclencher un cycle de mise à jour récursif. Au lieu de cela, effectuez des modifications dans des endroits spécifiques, tels que les systèmes personnalisés, les fermetures gestuelles ou la fermeture « make », qui ne sont pas couverts par l’évaluation du corps de la vue de SwiftUI. En décomposant les grandes vues en éléments plus petits et autonomes, et en faisant attention à l’endroit où l’état est modifié, vous pouvez garantir un flux de données fluide et efficace entre SwiftUI et RealityKit, en évitant les boucles infinies et en améliorant les performances globales de l’app.

    • 24:56 - Conversion de coordonnées unifiées
    • La nouvelle API Unified Coordinate Conversion comble le fossé entre RealityKit et SwiftUI. En implémentant le protocole « CoordinateSpace3D », vous pouvez convertir des valeurs de manière fluide entre les deux frameworks. Ainsi, vous calculez la distance absolue entre Bolts, une entité dans RealityKit, et Sparky, un Model3D dans SwiftUI, à mesure qu’ils se rapprochent les uns des autres, générant dynamiquement des étincelles en fonction de leur proximité.

    • 27:01 - Animation
    • Dans visionOS 26, vous pouvez désormais exploiter les API d’animation de SwiftUI pour animer implicitement les modifications apportées aux composants RealityKit. Cela permet d’obtenir des mouvements fluides et rebondissants des entités par simple définition des composants pris en charge dans un bloc d’animation. Pour y parvenir, il existe deux méthodes : en utilisant « content.animate() » dans un RealityView ou en appelant directement « Entity.animate() ». Cette intégration permet de personnaliser les comportements de relâchement lors de la manipulation des entités, ce qui rend les interactions avec les objets 3D plus attrayantes et plus amusantes. Différents composants RealityKit, dont Transform, Audio, Model et Light, prennent en charge ces animations implicites.

    • 29:41 - Étapes suivantes
    • Utilisez cette nouvelle connexion entre SwiftUI et RealityKit pour créer des apps spatiales innovantes en intégrant des composants SwiftUI aux scènes RealityKit, en permettant des interactions dynamiques entre les mondes virtuels et physiques, et en faisant émerger de nouvelles potentialités dans le développement d’apps.

Developer Footer

  • Vidéos
  • WWDC25
  • Mieux ensemble : SwiftUI et RealityKit
  • 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