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
 

Videos

Abrir menú Cerrar menú
  • Colecciones
  • Todos los videos
  • Información

Más videos

  • Información
  • Resumen
  • Código
  • Novedades del renderizado de Metal para apps inmersivas

    Descubre las últimas mejoras en el renderizado de Metal para apps inmersivas con Compositor Services. Aprende a agregar efectos de desplazamiento para resaltar los elementos interactivos de tu app y cómo renderizar con mayor fidelidad y calidad de renderizado dinámico. Descubre el nuevo estilo de inmersión progresiva. Además, descubre cómo puedes llevar experiencias inmersivas a las apps de macOS renderizando directamente el contenido de Metal desde Mac a Vision Pro.

    Para aprovechar al máximo esta sesión, primero ve “Discover Metal for immersive apps" del WWDC23.

    Capítulos

    • 0:00 - Introducción
    • 1:58 - Nuevas API de bucle de renderizado
    • 4:21 - Efectos de desplazamiento
    • 10:50 - Calidad de renderización dinámica
    • 14:44 - Inmersión progresiva
    • 18:32 - Renderizado espacial de macOS
    • 23:51 - Próximos pasos

    Recursos

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

    Videos relacionados

    WWDC25

    • Descubrir Metal 4
    • Explora la entrada de accesorios espaciales en visionOS
    • Explorar juegos de Metal 4
    • Novedades de SwiftUI
    • Novedades de visionOS 26
    • Ve más allá con los juegos de Metal 4

    WWDC24

    • Render Metal with passthrough in visionOS

    WWDC23

    • Discover Metal for immersive apps
  • Buscar este video…
    • 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 - Introducción
    • El renderizado de Metal en visionOS, junto con Compositor Services, trae nuevas y emocionantes funcionalidades este año, como efectos de desplazamiento sobre objetos con los que se puede interactuar, calidad de renderizado dinámico de tu contenido, un nuevo estilo de inmersión progresiva y la capacidad de renderizar contenido inmersivo en el Vision Pro desde macOS.

    • 1:58 - Nuevas API de bucle de renderizado
    • Se hizo un cambio importante en el bucle de renderizado en visionOS este año. El objeto queryDrawables ahora arroja una matriz de uno o dos elementos dibujables en lugar de solo uno. El segundo elemento dibujable estará presente siempre que grabes un video de alta calidad con Reality Composer Pro. Busca una plantilla que te ayude a iniciar en Xcode. Se admiten tanto Metal como Metal 4.

    • 4:21 - Efectos de desplazamiento
    • Una vez que hayas adoptado la nueva API de bucle de renderizado, podrás empezar a implementar efectos de desplazamiento sobre los objetos con los que se puede interactuar. Con estos efectos, las personas pueden ver qué objetos son interactivos y anticipar los objetivos de sus acciones. El sistema resaltará dinámicamente el objeto que la persona esté viendo. Por ejemplo, en un juego de rompecabezas se enfatizarán las piezas que el jugador puede seleccionar. Puedes hacer esto con la nueva textura de áreas de seguimiento, que define las regiones interactivas en tu escena. Hay algunas consideraciones extra que debes tener en cuenta cuando uses el suavizado multimuestra (MSAA).

    • 10:50 - Calidad de renderización dinámica
    • Ahora puedes dibujar tu contenido con una mayor fidelidad. Al usar la calidad de renderizado dinámico, puedes ajustar la resolución de tu contenido según la complejidad de tus escenas. Se basa en el renderizado foveado, que prioriza la densidad de pixeles donde el usuario está mirando. Puedes establecer una calidad de renderizado máxima y luego ajustar una calidad de ejecución acorde a ese rango. Una mayor calidad mejora la claridad del texto y de la interfaz, pero aumenta el uso de memoria y energía. Equilibrar la calidad y el rendimiento es crucial. Usa herramientas como Instruments y el depurador de Metal para encontrar ese equilibrio.

    • 14:44 - Inmersión progresiva
    • Este año, podrás renderizar contenido dentro de un portal inmersivo progresivo. Con esto, las personas controlan el nivel de inmersión al girar la Digital Crown. Esto las conecta con el entorno real y las ayuda a sentirse más cómodas cuando ven escenas complejas con movimiento. Para implementarlo, solicita al sistema que proporcione un búfer de plantilla con el fin de enmascarar el contenido que se encuentra fuera del límite del portal. El sistema aplica un efecto de difuminado en los bordes, creando una transición perfecta entre entornos reales y renderizados. Los pixeles que se encuentran fuera de la vista no se renderizan, lo que ahorra capacidad de procesamiento. Compartimos los detalles de implementación.

    • 18:32 - Renderizado espacial de macOS
    • El renderizado espacial de macOS permite aprovechar la capacidad de tu Mac para renderizar y transmitir contenido inmersivo al Apple Vision Pro. Esta nueva funcionalidad mejora las apps para Mac con experiencias inmersivas, como vistas previas de modelado 3D en tiempo real. ARKit y worldTrackingProvider ahora están disponibles en macOS. Esto te permite consultar la ubicación del Vision Pro en el espacio. El RemoteImmersiveSpace de macOS aloja CompositorLayer y ARKitSession, como lo haría una app nativa de visionOS. Hay un nuevo remoteDeviceIdentifier que deberás usar para conectar la sesión de ARKit de tu Mac al Vision Pro. Además, todas las API relevantes tienen equivalentes nativos en C.

    • 23:51 - Próximos pasos
    • Estas nuevas capacidades de Metal y Compositor Services en visionOS permiten brindar mejor interactividad, mayor fidelidad y un nuevo estilo de inmersión progresiva a tus apps y juegos. A continuación, consulta “Set the scene with SwiftUI in visionOS” y “What's new in visionOS 26”.

Developer Footer

  • Videos
  • WWDC25
  • Novedades del renderizado de Metal para apps inmersivas
  • 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