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
 

Vídeos

Abrir menu Fechar menu
  • Coleções
  • Todos os vídeos
  • Sobre

Mais vídeos

  • Sobre
  • Resumo
  • Código
  • Aprimore jogos com o Metal 4

    Fique por dentro dos últimos avanços do Metal 4. Apresentaremos os novos recursos de traçado de raios que ajudam o Apple Silicon a processar suas cargas de trabalho mais complexas e visualmente robustas. Saiba como o MetalFX pode ajudar a aumentar as cargas de trabalho melhorando renderizações, interpolando quadros e reduzindo ruídos visuais em cenas.

    Para aproveitar ao máximo esta sessão, recomendamos assistir primeiro aos vídeos “Conheça o Metal 4” e “Explore jogos feitos com o Metal 4”.

    Capítulos

    • 0:00 - Introdução
    • 2:13 - Ampliar a renderização
    • 7:17 - Interpolar quadros
    • 13:50 - Traçado de raios com o Metal 4
    • 19:25 - Reduzir ruídos durante a ampliação
    • 26:08 - Próximas etapas

    Recursos

      • Vídeo HD
      • Vídeo SD

    Vídeos relacionados

    WWDC25

    • Combine o aprendizado de máquina e os gráficos do Metal 4
    • Conheça o Metal 4
    • Explore jogos feitos com o Metal 4
    • Melhore ainda mais seus jogos
    • Novidades na renderização no Metal para apps imersivos

    WWDC23

    • Your guide to Metal ray tracing

    WWDC22

    • Boost performance with MetalFX Upscaling
  • Buscar neste vídeo...
    • 6:46 - Reactive Mask

      // Create reactive mask setup in shader
      out.reactivity = m_material_id == eRain ? (m_material_id == eSpark ? 1.0f : 0.0f) : 0.8f;
      
      // Set reactive mask before encoding upscaler on host
      temporalUpscaler.reactiveMask = reactiveMaskTexture;
    • 8:35 - MetalFX Frame Interpolator

      // Create and configure the interpolator descriptor
      MTLFXFrameInterpolatorDescriptor* desc = [MTLFXFrameInterpolatorDescriptor new];
      desc.scaler = temporalScaler;
      // ...
      
      // Create the effect and configure your effect
      id<MTLFXFrameInterpolator> interpolator = [desc newFrameInterpolatorWithDevice:device];
      interpolator.motionVectorScaleX = mvecScaleX;
      interpolator.motionVectorScaleY = mvecScaleY;
      interpolator.depthReversed = YES;
      
      // Set input textures
      interpolator.colorTexture = colorTexture;
      interpolator.prevColorTexture = prevColorTexture;
      interpolator.depthTexture = depthTexture;
      interpolator.motionTexture = motionTexture;
      interpolator.outputTexture = outputTexture;
    • 12:45 - Interpolator present helper class

      #include <thread>
      #include <mutex>
      #include <sys/event.h>
      #include <mach/mach_time.h>
      
      
      class PresentThread
      {
          int m_timerQueue;
          std::thread m_encodingThread, m_pacingThread;
          std::mutex m_mutex;
          std::condition_variable m_scheduleCV, m_threadCV, m_pacingCV;
          float m_minDuration;
          
          uint32_t m_width, m_height;
          MTLPixelFormat m_pixelFormat;
          
          const static uint32_t kNumBuffers = 3;
          uint32_t m_bufferIndex, m_inputIndex;
          bool m_renderingUI, m_presentsPending;
          
          CAMetalLayer *m_metalLayer;
          id<MTLCommandQueue> m_presentQueue;
      
          id<MTLEvent> m_event;
          id<MTLSharedEvent> m_paceEvent, m_paceEvent2;
          uint64_t m_eventValue;
          uint32_t m_paceCount;
          
          int32_t m_numQueued, m_framesInFlight;
          
          id<MTLTexture> m_backBuffers[kNumBuffers];
          id<MTLTexture> m_interpolationOutputs[kNumBuffers];
          id<MTLTexture> m_interpolationInputs[2];
          id<MTLRenderPipelineState> m_copyPipeline;
          
          std::function<void(id<MTLRenderCommandEncoder>)> m_uiCallback = nullptr;
          
          void PresentThreadFunction();
          void PacingThreadFunction();
          
          void CopyTexture(id<MTLCommandBuffer> commandBuffer, id<MTLTexture> dest, id<MTLTexture> src, NSString *label);
      
      public:
          
          PresentThread(float minDuration, CAMetalLayer *metalLayer);
          ~PresentThread()
          {
              std::unique_lock<std::mutex> lock(m_mutex);
              m_numQueued = -1;
              m_threadCV.notify_one();
              m_encodingThread.join();
          }
          void StartFrame(id<MTLCommandBuffer> commandBuffer)
          {
              [commandBuffer encodeWaitForEvent:m_event value:m_eventValue++];
          }
      
          void StartUI(id<MTLCommandBuffer> commandBuffer)
          {
              assert(m_uiCallback == nullptr);
              if(!m_renderingUI)
              {
                  CopyTexture(commandBuffer, m_interpolationInputs[m_inputIndex], m_backBuffers[m_bufferIndex], @"Copy HUDLESS");
                  m_renderingUI = true;
              }
          }
          
          void Present(id<MTLFXFrameInterpolator> frameInterpolator, id<MTLCommandQueue> queue);
          
          id<MTLTexture> GetBackBuffer()
          {
              return m_backBuffers[m_bufferIndex];
          }
      
          void Resize(uint32_t width, uint32_t height, MTLPixelFormat pixelFormat);
          
          void DrainPendingPresents()
          {
              std::unique_lock<std::mutex> lock(m_mutex);
              while(m_presentsPending)
                  m_scheduleCV.wait(lock);
          }
          
          bool UICallbackEnabled() const
          {
              return m_uiCallback != nullptr;
          }
          
          void SetUICallback(std::function<void(id<MTLRenderCommandEncoder>)> callback)
          {
              m_uiCallback = callback;
          }
          
      };
      
      PresentThread::PresentThread(float minDuration, CAMetalLayer *metalLayer)
          : m_encodingThread(&PresentThread::PresentThreadFunction, this)
          , m_pacingThread(&PresentThread::PacingThreadFunction, this)
          , m_minDuration(minDuration)
          , m_numQueued(0)
          , m_metalLayer(metalLayer)
          , m_inputIndex(0u)
          , m_bufferIndex(0u)
          , m_renderingUI(false)
          , m_presentsPending(false)
          , m_framesInFlight(0)
          , m_paceCount(0)
          , m_eventValue(0)
      {
          id<MTLDevice> device = metalLayer.device;
          m_presentQueue = [device newCommandQueue];
          m_presentQueue.label = @"presentQ";
          m_timerQueue = kqueue();
          
          metalLayer.maximumDrawableCount = 3;
          
          Resize(metalLayer.drawableSize.width, metalLayer.drawableSize.height, metalLayer.pixelFormat);
          
          m_event = [device newEvent];
          m_paceEvent = [device newSharedEvent];
      	m_paceEvent2 = [device newSharedEvent];
      }
      
      
      void PresentThread::Present(id<MTLFXFrameInterpolator> frameInterpolator, id<MTLCommandQueue> queue)
      {
          id<MTLCommandBuffer> commandBuffer = [queue commandBuffer];
          
          if(m_renderingUI)
          {
              frameInterpolator.colorTexture = m_interpolationInputs[m_inputIndex];
              frameInterpolator.prevColorTexture = m_interpolationInputs[m_inputIndex^1];
              frameInterpolator.uiTexture = m_backBuffers[m_bufferIndex];
          }
          else
          {
              frameInterpolator.colorTexture = m_backBuffers[m_bufferIndex];
              frameInterpolator.prevColorTexture = m_backBuffers[(m_bufferIndex + kNumBuffers - 1) % kNumBuffers];
              frameInterpolator.uiTexture = nullptr;
          }
          
          frameInterpolator.outputTexture = m_interpolationOutputs[m_bufferIndex];
      
          [frameInterpolator encodeToCommandBuffer:commandBuffer];
          [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
              std::unique_lock<std::mutex> lock(m_mutex);
              m_framesInFlight--;
              m_scheduleCV.notify_one();
              m_paceCount++;
              m_pacingCV.notify_one();
          }];
          [commandBuffer encodeSignalEvent:m_event value:m_eventValue++];
          [commandBuffer commit];
      
          std::unique_lock<std::mutex> lock(m_mutex);
          m_framesInFlight++;
          m_numQueued++;
          m_presentsPending = true;
          m_threadCV.notify_one();
          while((m_framesInFlight >= 2) || (m_numQueued >= 2))
              m_scheduleCV.wait(lock);
      
          m_bufferIndex = (m_bufferIndex + 1) % kNumBuffers;
          m_inputIndex = m_inputIndex^1u;
          m_renderingUI = false;
      }
      
      void PresentThread::CopyTexture(id<MTLCommandBuffer> commandBuffer, id<MTLTexture> dest, id<MTLTexture> src, NSString *label)
      {
          MTLRenderPassDescriptor *desc = [MTLRenderPassDescriptor new];
          desc.colorAttachments[0].texture = dest;
          desc.colorAttachments[0].loadAction = MTLLoadActionDontCare;
          desc.colorAttachments[0].storeAction = MTLStoreActionStore;
          id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:desc];
          [renderEncoder setFragmentTexture:src atIndex:0];
          [renderEncoder setRenderPipelineState:m_copyPipeline];
          [renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
          if(m_uiCallback)
              m_uiCallback(renderEncoder);
          renderEncoder.label = label;
          [renderEncoder endEncoding];
      }
      
      
      void PresentThread::PacingThreadFunction()
      {
          NSThread *thread = [NSThread currentThread];
          [thread setName:@"PacingThread"];
          [thread setQualityOfService:NSQualityOfServiceUserInteractive];
          [thread setThreadPriority:1.f];
          
          mach_timebase_info_data_t info;
          mach_timebase_info(&info);
          
          // maximum delta (0.1ms) in machtime units
          const uint64_t maxDeltaInNanoSecs = 100000000;
          const uint64_t maxDelta = maxDeltaInNanoSecs * info.denom / info.numer;
          
          uint64_t time = mach_absolute_time();
          
          uint64_t paceEventValue = 0;
          
          for(;;)
          {
              std::unique_lock<std::mutex> lock(m_mutex);
              while(m_paceCount == 0)
                  m_pacingCV.wait(lock);
              m_paceCount--;
              lock.unlock();
              
              // we get signal...
              const uint64_t prevTime = time;
              time = mach_absolute_time();
      		m_paceEvent.signaledValue = ++paceEventValue;
      
              const uint64_t delta = std::min(time - prevTime, maxDelta);
              const uint64_t timeStamp = time + ((delta*31)>>6);
              
              struct kevent64_s timerEvent, eventOut;
              struct timespec timeout;
              timeout.tv_nsec = maxDeltaInNanoSecs;
              timeout.tv_sec = 0;
              EV_SET64(&timerEvent,
                       0,
                       EVFILT_TIMER,
                       EV_ADD | EV_ONESHOT | EV_ENABLE,
                       NOTE_CRITICAL | NOTE_LEEWAY | NOTE_MACHTIME | NOTE_ABSOLUTE,
                       timeStamp,
                       0,
                       0,
                       0);
              
              kevent64(m_timerQueue, &timerEvent, 1, &eventOut, 1, 0, &timeout);
              
              // main screen turn on...
              m_paceEvent2.signaledValue = ++paceEventValue;
          }
      }
      
      
      void PresentThread::PresentThreadFunction()
      {
          NSThread *thread = [NSThread currentThread];
          [thread setName:@"PresentThread"];
          [thread setQualityOfService:NSQualityOfServiceUserInteractive];
          [thread setThreadPriority:1.f];
          
      
          uint64_t eventValue = 0;
          uint32_t bufferIndex = 0;
      
          uint64_t paceEventValue = 0;
      
          for(;;)
          {
              std::unique_lock<std::mutex> lock(m_mutex);
              
              if(m_numQueued == 0)
              {
                  m_presentsPending = false;
                  m_scheduleCV.notify_one();
              }
              
              while(m_numQueued == 0)
                  m_threadCV.wait(lock);
              
              if(m_numQueued < 0)
                  break;
              lock.unlock();
      
              @autoreleasepool
              {
                  id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
      
      			lock.lock();
      			m_numQueued--;
      			m_scheduleCV.notify_one();
      			lock.unlock();
      
                  id<MTLCommandBuffer> commandBuffer = [m_presentQueue commandBuffer];
                  [commandBuffer encodeWaitForEvent:m_event value:++eventValue];
                  CopyTexture(commandBuffer, drawable.texture, m_interpolationOutputs[bufferIndex], @"Copy Interpolated");
                  [commandBuffer encodeSignalEvent:m_event value:++eventValue];
      			[commandBuffer encodeWaitForEvent:m_paceEvent value:++paceEventValue];
      
                  if(m_minDuration > 0.f)
                      [commandBuffer presentDrawable:drawable afterMinimumDuration:m_minDuration];
                  else
                      [commandBuffer presentDrawable:drawable];
                  [commandBuffer commit];
              }
              
              @autoreleasepool
              {
                  id<MTLCommandBuffer> commandBuffer = [m_presentQueue commandBuffer];
                  id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
                  CopyTexture(commandBuffer, drawable.texture, m_backBuffers[bufferIndex], @"Copy Rendered");
      			[commandBuffer encodeWaitForEvent:m_paceEvent2 value:++paceEventValue];
                  if(m_minDuration > 0.f)
                      [commandBuffer presentDrawable:drawable afterMinimumDuration:m_minDuration];
                  else
                      [commandBuffer presentDrawable:drawable];
                  [commandBuffer commit];
              }
              
              bufferIndex = (bufferIndex + 1) % kNumBuffers;
          }
      }
      
      void PresentThread::Resize(uint32_t width, uint32_t height, MTLPixelFormat pixelFormat)
      {
          if((m_width != width) || (m_height != height) || (m_pixelFormat != pixelFormat))
          {
              id<MTLDevice> device = m_metalLayer.device;
      
              if(m_pixelFormat != pixelFormat)
              {
                  id<MTLLibrary> lib = [device newDefaultLibrary];
                  MTLRenderPipelineDescriptor *pipelineDesc = [MTLRenderPipelineDescriptor new];
                  pipelineDesc.vertexFunction = [lib newFunctionWithName:@"FSQ_VS_V4T2"];
                  pipelineDesc.fragmentFunction = [lib newFunctionWithName:@"FSQ_simpleCopy"];
                  pipelineDesc.colorAttachments[0].pixelFormat = pixelFormat;
                  m_copyPipeline = [device newRenderPipelineStateWithDescriptor:pipelineDesc error:nil];
                  m_pixelFormat = pixelFormat;
              }
              
              DrainPendingPresents();
              
              m_width = width;
      		m_height = height;
              
              MTLTextureDescriptor *texDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pixelFormat width:width height:height mipmapped:NO];
      		texDesc.storageMode = MTLStorageModePrivate;
              for(uint32_t i = 0; i < kNumBuffers; i++)
              {
                  texDesc.usage = MTLTextureUsageShaderRead|MTLTextureUsageShaderWrite|MTLTextureUsageRenderTarget;
                  m_backBuffers[i] = [device newTextureWithDescriptor:texDesc];
                  texDesc.usage = MTLTextureUsageShaderRead|MTLTextureUsageRenderTarget;
                  m_interpolationOutputs[i] = [device newTextureWithDescriptor:texDesc];
              }
              texDesc.usage = MTLTextureUsageShaderRead|MTLTextureUsageRenderTarget;
              m_interpolationInputs[0] = [device newTextureWithDescriptor:texDesc];
              m_interpolationInputs[1] = [device newTextureWithDescriptor:texDesc];
      
          }
      }
    • 13:00 - Set intersection function table offset

      // Set intersection function table offset on host-side geometry descriptors
      NSMutableArray<MTLAccelerationStructureGeometryDescriptor *> *geomDescs ...;
      for (auto g = 0; g < geomList.size(); ++g)
      {
          MTLAccelerationStructureGeometryDescriptor *descriptor = ...;
          descriptor.intersectionFunctionTableOffset = g;
          ...
          [geomDescs addObject:descriptor];
      }
    • 13:01 - Set up the intersector

      // Set up the intersector
      metal::raytracing::intersector<intersection_function_buffer, instancing, triangle> trace;
      trace.set_geometry_multiplier(2); // Number of ray types, defaults to 1
      trace.set_base_id(1);             // Set ray type index, defaults to 0
    • 13:02 - Ray trace intersection function buffers

      // Ray trace intersection function buffers
      
      // Set up intersection function buffer arguments
      intersection_function_buffer_arguments ifb_arguments;
      ifb_arguments.intersection_function_buffer = raytracingResources.ifbBuffer;
      ifb_arguments.intersection_function_buffer_size = raytracingResources.ifbBufferSize;
      ifb_arguments.intersection_function_stride = raytracingResources.ifbBufferStride;
      
      // Set up the ray and finish intersecting
      metal::raytracing::ray r = { origin, direction };
      auto result = trace.intersect(r, ads, ifb_arguments);
    • 13:02 - Change of temporal scaler setup to denoised temporal scaler setup

      // Change of temporal scaler setup to denoised temporal scaler setup
      
      MTLFXTemporalScalerDescriptor* desc = [MTLFXTemporalScalerDescriptor new];
      desc.colorTextureFormat = MTLPixelFormatBGRA8Unorm_sRGB;
      desc.outputTextureFormat = MTLPixelFormatBGRA8Unorm_sRGB;
      desc.depthTextureFormat = DepthStencilFormat;
      desc.motionTextureFormat = MotionVectorFormat;
      
      desc.diffuseAlbedoTextureFormat = DiffuseAlbedoFormat;
      desc.specularAlbedoTextureFormat = SpecularAlbedoFormat;
      desc.normalTextureFormat = NormalVectorFormat;
      desc.roughnessTextureFormat = RoughnessFormat;
      
      desc.inputWidth = _mainViewWidth;
      desc.inputHeight = _mainViewHeight;
      desc.outputWidth = _screenWidth;
      desc.outputHeight = _screenHeight;
      temporalScaler = [desc newTemporalDenoisedScalerWithDevice:_device];
    • 13:04 - Change temporal scaler encode to denoiser temporal scaler encode

      // Change temporal scaler encode to denoiser temporal scaler encode
      
      temporalScaler.colorTexture = _mainView;
      temporalScaler.motionTexture = _motionTexture;
      
      temporalScaler.diffuseAlbedoTexture = _diffuseAlbedoTexture;
      temporalScaler.specularAlbedoTexture = _specularAlbedoTexture;
      temporalScaler.normalTexture = _normalTexture;
      temporalScaler.roughnessTexture = _roughnessTexture;
      
      temporalScaler.depthTexture = _depthTexture;
      temporalScaler.jitterOffsetX = _pixelJitter.x;
      temporalScaler.jitterOffsetY = -_pixelJitter.y;
      temporalScaler.outputTexture = _upscaledColorTarget;
      temporalScaler.motionVectorScaleX = (float)_motionTexture.width;
      temporalScaler.motionVectorScaleY = (float)_motionTexture.height;
      [temporalScaler encodeToCommandBuffer:commandBuffer];
    • 16:04 - Creating instance descriptors for instance acceleration structure

      // Creating instance descriptors for instance acceleration structure
      MTLAccelerationStructureInstanceDescriptor *grassInstanceDesc, *treeInstanceDesc = . . .;
      grassInstanceDesc.intersectionFunctionTableOffset = 0;
      treeInstanceDesc.intersectionFunctionTableOffset  = 1;
      
      // Create buffer for instance descriptors of as many trees/grass instances the scene holds
      id <MTLBuffer> instanceDescs = . . .;
      for (auto i = 0; i < scene.instances.size(); ++i)
      . . .
    • 0:00 - Introdução
    • Saiba mais sobre a série de jogos Metal 4, incluindo técnicas avançadas e melhores práticas para o desenvolvimento de jogos avançados e apps profissionais nas plataformas Apple. As APIs no Metal 4 permitem dimensionar suas cargas de trabalho para resoluções e taxas de quadros mais altas em dispositivos Apple.

    • 2:13 - Ampliar a renderização
    • O MetalFX tem um upscaler baseado em aprendizado de máquina que pode ajudar você a alcançar resoluções mais altas e taxas de quadros mais rápidas. A novidade deste ano, o upscaler temporal do MetalFX agora oferece suporte a entradas com tamanho dinâmico, permitindo que se reduza dinamicamente a resolução de entrada de quadros particularmente complexos. Se desejar, você pode usar as Dicas de Reatividade para sugerir ao upscaler sobre a reatividade dos pixels, a fim de obter resultados mais nítidos em áreas com efeitos ou partículas transparentes. E, usando a nova ferramenta de depuração de exposição, você pode verificar se o valor de exposição passado ao upscaler está correto.

    • 7:17 - Interpolar quadros
    • Neste ano, o MetalFX Frame Interpolation introduza a capacidade de gerar um frame adicional entre dois quadros renderizados. Existem várias técnicas para renderizar a interface do usuário com o Frame Interpolation. Também há considerações a serem feitas ao controlar o ritmo e apresentar quadros interpolados e nativamente renderizados.

    • 13:50 - Traçado de raios com o Metal 4
    • O Metal 4 incorpora novos recursos de traçado de raios relacionados à construção de estruturas de aceleração e funções de interseção. Se você estiver migrando de outras APIs, é fácil portar suas Shader Binding Tables para os buffers de função de interseção do Metal. Depois que tudo estiver funcionando, também é possível otimizar como o Metal 4 constrói suas estruturas de aceleração.

    • 19:25 - Reduzir ruídos durante a ampliação
    • Ao traçar raios em cenas, você pode alcançar o melhor equilíbrio entre qualidade e desempenho usando técnicas de remoção de ruído com menos raios lançados. A nova API do MetalFX aprimora os pipelines de renderização de traçado de raios em tempo real ao integrar a remoção de ruído diretamente ao processo de upscaling. Isso simplifica a abordagem tradicional, que envolve etapas separadas de traçado, remoção de ruído e composição. Ao especificar buffers auxiliares sem ruído, como normais, albedo difuso, rugosidade e albedo especular, você pode obter resultados robustos, de alto desempenho e alta qualidade, sem a necessidade de ajustar parâmetros separadamente para cada cena.

    • 26:08 - Próximas etapas
    • Se você já integrou o Upscaler do MetalFX, esta é a chance de fazer upgrade para a interpolação de frame. Se você é iniciante no MetalFX, comece com o upscaler. Em seguida, certifique-se de que seus efeitos de traçado de raios usem buffers de função de interseção e o upscaler com remoção de ruído.

Developer Footer

  • Vídeos
  • WWDC25
  • Aprimore jogos com o Metal 4
  • 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