<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Siraj Razick</title>
    <description>The latest articles on DEV Community by Siraj Razick (@siraj_razick_8f740c3835c9).</description>
    <link>https://dev.to/siraj_razick_8f740c3835c9</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1835334%2F43809e93-ed24-4b7b-9693-9176d05e1f0d.jpg</url>
      <title>DEV Community: Siraj Razick</title>
      <link>https://dev.to/siraj_razick_8f740c3835c9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/siraj_razick_8f740c3835c9"/>
    <language>en</language>
    <item>
      <title>Ray Tracing on macOS: A Comprehensive Guide &amp; Hands-On Tutorial</title>
      <dc:creator>Siraj Razick</dc:creator>
      <pubDate>Wed, 04 Nov 2026 15:37:48 +0000</pubDate>
      <link>https://dev.to/siraj_razick_8f740c3835c9/ray-tracing-on-macos-a-comprehensive-guide-hands-on-tutorial-19am</link>
      <guid>https://dev.to/siraj_razick_8f740c3835c9/ray-tracing-on-macos-a-comprehensive-guide-hands-on-tutorial-19am</guid>
      <description>&lt;p&gt;Few notes that helped me while porting Quake engine to support Ray Tracing on Mac, sharing so others can benefit.&lt;/p&gt;

&lt;p&gt;original game is here : &lt;a href="https://buymeacoffee.com/plexydesk/e/593896" rel="noopener noreferrer"&gt;https://buymeacoffee.com/plexydesk/e/593896&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Overview&lt;/li&gt;
&lt;li&gt;Prerequisites&lt;/li&gt;
&lt;li&gt;Core Concepts&lt;/li&gt;
&lt;li&gt;Hands-On Tutorial: Step-by-Step&lt;/li&gt;
&lt;li&gt;Official Sample Analysis&lt;/li&gt;
&lt;li&gt;Troubleshooting&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;===&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Ray Tracing in Metal?
&lt;/h3&gt;

&lt;p&gt;Ray tracing in Apple's Metal API is a hardware-accelerated rendering technique that simulates the physical behavior of light by tracing rays through a scene. Introduced with &lt;strong&gt;Metal 3&lt;/strong&gt; (WWDC 2022), Metal provides a native ray tracing subsystem built on top of acceleration structures, enabling real-time lighting, shadows, reflections, and global illumination effects.&lt;/p&gt;

&lt;p&gt;Unlike traditional rasterization—which projects triangles onto a screen pixel by pixel—ray tracing casts rays from the camera (or light sources) into the scene, computing exact intersections with geometry. This produces physically accurate results including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soft shadows&lt;/strong&gt; from area lights&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realistic reflections&lt;/strong&gt; and refractions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ambient occlusion&lt;/strong&gt; and indirect lighting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accurate depth-of-field&lt;/strong&gt; effects&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Supported Hardware
&lt;/h3&gt;

&lt;p&gt;| Platform | Support Level | Details |&lt;br&gt;
|==========|===============|=========|&lt;br&gt;
| &lt;strong&gt;Apple Silicon&lt;/strong&gt; (M-series) | Full hardware acceleration | All M1/M2/M3/M4 chips include dedicated ray tracing cores |&lt;br&gt;
| &lt;strong&gt;Intel Macs&lt;/strong&gt; (with Metal-capable GPUs) | Software fallback / limited | Some Intel-based Macs support ray tracing via software; performance varies |&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Point&lt;/strong&gt;: Hardware-accelerated ray tracing requires an Apple Silicon Mac (M1 or later). On Intel Macs, ray tracing may fall back to CPU/software implementations, which are significantly slower.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  The Metal Ray Tracing Pipeline
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+======================+    +=========================+    +====================+
| Geometry Data |----&amp;gt;|| Acceleration Structure |----&amp;gt;|| Ray Tracing Pass   |
| (Vertices,     |    || (BVH Tree)               |    || (Compute Shader)  |
|  Indices)      |    ||                         |    ||                    |
+======================+    +=========================+    +====================+
                                                             |
                                                     +-------v-------+
                                                     | Output Image  |
                                                     | (Texture)     |
                                                     +---------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The workflow consists of three main stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build the Acceleration Structure (AS)&lt;/strong&gt; — Organize geometry for efficient ray intersection tests&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure the Ray Tracing Command Encoder&lt;/strong&gt; — Set up shaders, function tables, and resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dispatch the Ray Generation Routine&lt;/strong&gt; — Execute the compute shader that traces rays&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;===&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Prerequisites
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Minimum Requirements
&lt;/h3&gt;

&lt;p&gt;| Requirement | Version |&lt;br&gt;
|=============|=========|&lt;br&gt;
| &lt;strong&gt;macOS&lt;/strong&gt; | 13.0 (Ventura) or later |&lt;br&gt;
| &lt;strong&gt;Xcode&lt;/strong&gt; | 14.0 or later |&lt;br&gt;
| &lt;strong&gt;Metal SDK&lt;/strong&gt; | Metal 3+ |&lt;br&gt;
| &lt;strong&gt;Hardware&lt;/strong&gt; | Apple Silicon (M1/M2/M3/M4) recommended |&lt;/p&gt;
&lt;h3&gt;
  
  
  Checking Device Support
&lt;/h3&gt;

&lt;p&gt;Before using ray tracing, always verify that the target device supports it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift — Check if the default device supports ray tracing&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Metal&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLCreateSystemDefaultDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supportsFamily&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apple3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Device supports Apple Silicon features including ray tracing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ray tracing may not be hardware-accelerated on this device"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight objective_c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Objective-C&lt;/span&gt;
&lt;span class="cp"&gt;#import &amp;lt;Metal/Metal.h&amp;gt;
&lt;/span&gt;
&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MTLDevice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MTLCreateSystemDefaultDevice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="nf"&gt;supportsFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;MTLGPUFamilyApple3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"Device supports ray tracing"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;MTLGPUFamilyApple3&lt;/code&gt; family identifier indicates Apple Silicon GPUs with full Metal 3 feature support, including hardware ray tracing.&lt;/p&gt;

&lt;p&gt;===&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Core Concepts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Acceleration Structures (AS)
&lt;/h3&gt;

&lt;p&gt;An &lt;strong&gt;acceleration structure&lt;/strong&gt; is a hierarchical data structure (typically a Bounding Volume Hierarchy, or BVH) that organizes scene geometry to enable fast ray-intersection queries. Without an AS, every ray would need to test against every triangle in the scene — O(n) complexity. With an AS, the search becomes approximately O(log n).&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Classes
&lt;/h4&gt;

&lt;p&gt;| Class | Purpose |&lt;br&gt;
|=======|=========|&lt;br&gt;
| &lt;code&gt;MTLAccelerationStructureDescriptor&lt;/code&gt; | Describes the overall acceleration structure |&lt;br&gt;
| &lt;code&gt;MTLAccelerationStructureTriangleGeometryDescriptor&lt;/code&gt; | Describes triangle geometry within the AS |&lt;br&gt;
| &lt;code&gt;MTLAccelerationStructureBoundingBoxGeometryDescriptor&lt;/code&gt; | Describes bounding box geometry |&lt;br&gt;
| &lt;code&gt;MTLAccelerationStructureInstanceDescriptor&lt;/code&gt; | Describes instances (for instance-level AS) |&lt;br&gt;
| &lt;code&gt;MTLAccelerationStructureCommandEncoder&lt;/code&gt; | Encodes build, refit, and copy commands |&lt;/p&gt;
&lt;h4&gt;
  
  
  Building Triangle Geometry
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift — Create a triangle geometry descriptor&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;triangleDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLAccelerationStructureTriangleGeometryDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;triangleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numberOfTriangles&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vertexBuffer&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexBufferOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexStride&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strideInBytes&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float3&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;indexBuffer&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexBufferOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight objective_c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Objective-C&lt;/span&gt;
&lt;span class="n"&gt;MTLAccelerationStructureTriangleGeometryDescriptor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MTLAccelerationStructureTriangleGeometryDescriptor&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;triangleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numberOfTriangles&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vertexBuffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexBufferOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexStride&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Vertex&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MTLVertexFormatFloat3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;indexBuffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexBufferOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MTLIndexTypeUInt16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Configuring the Overall AS Descriptor
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift — Configure the acceleration structure descriptor&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;asDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLAccelerationStructureDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;asDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowQuery&lt;/span&gt; &lt;span class="c1"&gt;// Options: .static, .dynamic, .allowQuery&lt;/span&gt;
&lt;span class="n"&gt;asDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;geometryDescriptors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;// Calculate required scratch buffer size&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scratchBufferSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accelerationStructureScratchBufferWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asDescriptor&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scratchBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scratchBufferSize&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;usage&lt;/code&gt; property controls how the AS behaves at runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.static&lt;/code&gt;&lt;/strong&gt; (default): The AS will not change after building. Best performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.dynamic&lt;/code&gt;&lt;/strong&gt;: The AS may be updated/refitted. Slightly slower queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.allowQuery&lt;/code&gt;&lt;/strong&gt;: Enables ray casting queries against the AS. Required for ray tracing.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3.2 Ray Generation Routines
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;ray generation routine&lt;/strong&gt; is a compute shader entry point marked with the &lt;code&gt;[[kernel]]&lt;/code&gt; attribute. It is responsible for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Computing the initial ray origin and direction for each pixel/thread&lt;/li&gt;
&lt;li&gt;Invoking ray tracing via the intersector&lt;/li&gt;
&lt;li&gt;Handling hit/miss cases and writing output color
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Metal Shading Language — Ray Generation Kernel
#include &amp;lt;metal_stdlib&amp;gt;
using namespace metal;

#define GEOMETRY_MASK_TRIANGLE 1
#define RAY_MASK_PRIMARY (GEOMETRY_MASK_TRIANGLE)

struct Uniforms {
    uint width;
    uint height;
    float4x4 viewMatrix;
    float4x4 projectionMatrix;
};

kernel void raygen(
    device unsigned char* outputImage [[buffer(0)]],
    constant Uniforms&amp;amp; uniforms [[buffer(1)]],
    device MTLAccelerationStructure* accelerationStructure [[buffer(2)]],
    uint3 gid [[thread_position_in_grid]]
) {
    uint x = gid.x;
    uint y = gid.y;

    if (x &amp;gt;= uniforms.width || y &amp;gt;= uniforms.height) return;

    // Compute ray origin and direction from screen coordinates
    float2 uv = float2(x, y) / float2(uniforms.width, uniforms.height) * 2.0 - 1.0;
    uv.y = -uv.y; // Flip Y

    // Simple pinhole camera ray setup
    float3 rayOrigin = float3(0.0, 1.0, 3.0);
    float3 rayDir = normalize(float3(uv, -1.0));

    // Define ray bounds
    float tmin = 0.01f;
    float tmax = 1000.0f;

    // Perform ray intersection query
    float3 hitPoint;
    float2 barycentrics;
    uint primitiveId;
    bool hit = accelerationStructure-&amp;gt;intersect(
        rayOrigin, rayDir, tmin, tmax,
        RAY_MASK_PRIMARY, hitPoint, barycentrics, primitiveId
    );

    // Write result to output texture
    if (hit) {
        // Hit: shade the intersection point
        float3 color = float3(0.8, 0.2, 0.3); // Example hit color
        outputImage[(y * uniforms.width + x) * 4 + 0] = uint8_t(color.r * 255);
        outputImage[(y * uniforms.width + x) * 4 + 1] = uint8_t(color.g * 255);
        outputImage[(y * uniforms.width + x) * 4 + 2] = uint8_t(color.b * 255);
        outputImage[(y * uniforms.width + x) * 4 + 3] = 255;
    } else {
        // Miss: background color
        outputImage[(y * uniforms.width + x) * 4 + 0] = 0;
        outputImage[(y * uniforms.width + x) * 4 + 1] = 0;
        outputImage[(y * uniforms.width + x) * 4 + 2] = 0;
        outputImage[(y * uniforms.width + x) * 4 + 3] = 255;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  3.3 Intersection &amp;amp; Miss Shaders
&lt;/h3&gt;

&lt;p&gt;Metal supports &lt;strong&gt;custom intersection functions&lt;/strong&gt; that allow you to define bespoke intersection logic beyond standard triangle hits. These are marked with the &lt;code&gt;[[intersection]]&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Custom sphere intersection function
struct SphereIntersection {
    bool accept [[accept_intersection]];
    float distance [[distance]];
};

constant bool useResourcesBuffer = true;

[[intersection(bounding_box, triangle_data, instancing)]]
SphereIntersection sphereIntersectionFunction(
    float3 origin [[origin]],
    float3 direction [[direction]],
    float minDistance [[min_distance]],
    float maxDistance [[max_distance]],
    unsigned int primitiveId [[primitive_id]],
    unsigned int geometryIndex [[geometry_intersection_function_table_offset]],
    device void* resources [[buffer(0), function_constant(useResourcesBuffer)]]
) {
    // Mathematical sphere intersection test
    float3 oc = origin - spheres[primitiveId].origin;
    float a = dot(direction, direction);
    float b = 2.0f * dot(oc, direction);
    float c = dot(oc, oc) - spheres[primitiveId].radiusSquared;
    float disc = b * b - 4.0f * a * c;

    SphereIntersection ret;
    if (disc &amp;gt;= 0.0f) {
        float sqrtDisc = sqrt(disc);
        float t = (-b - sqrtDisc) / (2.0f * a);
        if (t &amp;gt;= minDistance &amp;amp;&amp;amp; t &amp;lt;= maxDistance) {
            ret.accept = true;
            ret.distance = t;
        } else {
            ret.accept = false;
        }
    } else {
        ret.accept = false;
    }
    return ret;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The intersection function keywords control what data Metal passes between pipeline stages:&lt;/p&gt;

&lt;p&gt;| Keyword | Purpose |&lt;br&gt;
|=========|=========|&lt;br&gt;
| &lt;code&gt;bounding_box&lt;/code&gt; | The intersector handles bounding box primitives |&lt;br&gt;
| &lt;code&gt;triangle_data&lt;/code&gt; | Barycentric coordinates are computed and passed |&lt;br&gt;
| &lt;code&gt;instancing&lt;/code&gt; | Instance acceleration structure traversal is used |&lt;/p&gt;

&lt;p&gt;When you omit keywords, Metal stores less intermediate data, potentially improving performance.&lt;/p&gt;

&lt;p&gt;===&lt;/p&gt;
&lt;h2&gt;
  
  
  4. Hands-On Tutorial: Step-by-Step
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Project Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Xcode → &lt;strong&gt;File → New → Project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;macOS → App&lt;/strong&gt; (or iOS → App)&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Swift&lt;/strong&gt; or &lt;strong&gt;Objective-C&lt;/strong&gt; as the language&lt;/li&gt;
&lt;li&gt;In your project settings, ensure &lt;strong&gt;Metal Framework&lt;/strong&gt; is linked:

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Target → General → Frameworks, Libraries, and Embedded Content&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;Metal.framework&lt;/code&gt; and &lt;code&gt;MetalPerformanceShaders.framework&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;.metal&lt;/code&gt; file for your shaders:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;File → New → File → Metal Shader File&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Name it &lt;code&gt;RayTracing.metal&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Step 2: Device Detection
&lt;/h3&gt;

&lt;p&gt;Before creating any ray tracing resources, check device capability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Metal&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;RayTracingRenderer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MTLDevice&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;commandQueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MTLCommandQueue&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLCreateSystemDefaultDevice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RayTracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSLocalizedDescriptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                             &lt;span class="s"&gt;"No Metal-capable device found"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;

        &lt;span class="c1"&gt;// Verify Apple Silicon support&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;supportsFamily&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apple3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RayTracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSLocalizedDescriptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                             &lt;span class="s"&gt;"Device does not support hardware ray tracing"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;commandQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeCommandQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RayTracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSLocalizedDescriptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                             &lt;span class="s"&gt;"Failed to create command queue"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commandQueue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commandQueue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Building the Acceleration Structure
&lt;/h3&gt;

&lt;p&gt;This is the most critical step. You must build the AS before any ray tracing can occur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift — Complete AS build workflow&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;buildAccelerationStructure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;MTLAccelerationStructure&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Create the triangle geometry descriptor&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;triangleDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLAccelerationStructureTriangleGeometryDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;triangleCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;triangleCount&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vertexBuffer&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexBufferOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexStride&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MemoryLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Vertex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;stride&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertexFormat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float3&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;indexBuffer&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexBufferOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;indexType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uint16&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Configure the overall AS descriptor&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;asDescriptor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLAccelerationStructureDescriptor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;asDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allowQuery&lt;/span&gt;
    &lt;span class="n"&gt;asDescriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;geometryDescriptors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triangleDescriptor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Create the acceleration structure buffer&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;asSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accelerationStructureSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asDescriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;accelerationStructure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeAccelerationStructure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asDescriptor&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RayTracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSLocalizedDescriptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                         &lt;span class="s"&gt;"Failed to create acceleration structure"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// 4. Allocate scratch buffer (temporary working memory)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scratchBufferSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accelerationStructureScratchBufferWidth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asDescriptor&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scratchBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scratchBufferSize&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

    &lt;span class="c1"&gt;// 5. Encode the build command&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;commandBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commandQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeCommandBuffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RayTracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSLocalizedDescriptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                         &lt;span class="s"&gt;"Failed to make command buffer"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commandBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeAccelerationStructureCommandEncoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="kt"&gt;NSError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"RayTracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="nv"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NSLocalizedDescriptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                         &lt;span class="s"&gt;"Failed to make acceleration structure command encoder"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// The build method signature:&lt;/span&gt;
    &lt;span class="c1"&gt;// build(accelerationStructure:descriptor:scratchBuffer:scratchBufferOffset:)&lt;/span&gt;
    &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;accelerationStructure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;accelerationStructure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;descriptor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asDescriptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;scratchBuffer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scratchBuffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;scratchBufferOffset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endEncoding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;commandBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;commandBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntilCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;accelerationStructure&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why the scratch buffer?&lt;/strong&gt; The acceleration structure build process requires temporary GPU memory to construct the BVH tree internally. The &lt;code&gt;scratchBuffer&lt;/code&gt; provides this workspace. Its required size is queried via &lt;code&gt;accelerationStructureScratchBufferWidth(descriptor:)&lt;/code&gt;. After the build completes, the scratch buffer can be reused for subsequent builds or refits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Defining the Ray Gen Shader
&lt;/h3&gt;

&lt;p&gt;Create your Metal shader file (&lt;code&gt;RayTracing.metal&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// RayTracing.metal
#include &amp;lt;metal_stdlib&amp;gt;
#include &amp;lt;simd/simd.h&amp;gt;
using namespace metal;

// Constants passed from the CPU
struct CameraParams {
    float4x4 viewMatrix;
    float4x4 projectionMatrix;
    float2 viewportSize;
};

struct RayPayload {
    float3 color;      // RGB color of the hit surface
    float3 normal;     // Surface normal at hit point
    float3 position;   // World-space position of the hit
    float distance;    // Distance from ray origin
    bool hit;          // Whether any geometry was hit
};

// Ray generation kernel — one thread per pixel
[[kernel]] void raygen(
    device RayPayload* payloads       [[buffer(0)]],
    device MTLAccelerationStructure* accelerationStructure [[buffer(1)]],
    constant CameraParams&amp;amp; params     [[buffer(2)]],
    uint2 gid                         [[thread_position_in_grid]]
) {
    uint x = gid.x;
    uint y = gid.y;

    if (x &amp;gt;= uint(params.viewportSize.x) || y &amp;gt;= uint(params.viewportSize.y))
        return;

    // --- Ray Setup ---
    // Map pixel coordinates to NDC [-1, 1]
    float2 ndc = (float2(x, y) / params.viewportSize) * 2.0 - 1.0;
    ndc.y = -ndc.y; // Flip Y for OpenGL-style coords

    // Build ray direction from camera matrices
    float4 clipPos = float4(ndc, 0.0, 1.0);
    float4 eyePos = inverse(params.projectionMatrix) * clipPos;
    eyePos = eyePos / eyePos.w;
    float4 worldPos = inverse(params.viewMatrix) * eyePos;
    float3 rayOrigin = params.viewMatrix[3].xyz; // Camera position
    float3 rayDirection = normalize(worldPos.xyz - rayOrigin);

    // --- Ray Query ---
    float tmin = 0.001f;
    float tmax = 1000.0f;
    uint rayFlags = 0xFF; // Test all geometry
    uint instanceMask = 0xFF;

    float3 hitPoint;
    float2 barycentrics;
    uint primitiveId;
    bool hit = accelerationStructure-&amp;gt;intersect(
        rayOrigin, rayDirection, tmin, tmax,
        rayFlags, instanceMask,
        hitPoint, barycentrics, primitiveId
    );

    // --- Output ---
    RayPayload payload;
    payload.hit = hit;
    if (hit) {
        payload.position = hitPoint;
        payload.distance = length(hitPoint - rayOrigin);
        payload.color = float3(0.8f, 0.2f, 0.3f); // Placeholder shading
        payload.normal = float3(0.0f, 1.0f, 0.0f);
    } else {
        payload.color = float3(0.0f, 0.05f, 0.1f); // Sky color
        payload.normal = float3(0.0f);
        payload.position = float3(0.0f);
        payload.distance = tmax;
    }

    payloads[gid.y * uint(params.viewportSize.x) + gid.x] = payload;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile the shader library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift — Compile and load the shader library&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;defaultLibrary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeDefaultLibrary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;raygenFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;defaultLibrary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"raygen"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

&lt;span class="c1"&gt;// Create a compute pipeline state for the ray gen shader&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;raygenPipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeComputePipelineState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;raygenFunction&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Dispatching the Ray Tracing Command
&lt;/h3&gt;

&lt;p&gt;Now that you have an acceleration structure and a compiled ray gen shader, encode the actual ray tracing work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Swift — Encode and dispatch the ray tracing pass&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;renderFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;outputTexture&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MTLTexture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throws&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;commandBuffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commandQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeCommandBuffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// --- Ray Tracing Compute Pass ---&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;computeEncoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commandBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeComputeCommandEncoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Set the pipeline state&lt;/span&gt;
    &lt;span class="n"&gt;computeEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setComputePipelineState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raygenPipeline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Bind the acceleration structure (resource at buffer slot 1)&lt;/span&gt;
    &lt;span class="n"&gt;computeEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAccelerationStructure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accelerationStructure&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Bind the output texture&lt;/span&gt;
    &lt;span class="n"&gt;computeEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTexture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputTexture&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Bind camera parameters&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cameraParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CameraParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;viewMatrix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;viewMatrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;projectionMatrix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;projectionMatrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;viewportSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textureWidth&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;Float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textureHeight&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;computeEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cameraParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MemoryLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;CameraParams&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Calculate threadgroup dimensions (one thread per pixel)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;threadsPerThreadgroup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;numThreadgroups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textureWidth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;textureHeight&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;depth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Dispatch the ray gen kernel&lt;/span&gt;
    &lt;span class="n"&gt;computeEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchThreadgroups&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numThreadgroups&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;threadsPerThreadgroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;threadsPerThreadgroup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;computeEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endEncoding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Present or blit the result&lt;/span&gt;
    &lt;span class="c1"&gt;// ... (presentation code depends on your view setup)&lt;/span&gt;

    &lt;span class="n"&gt;commandBuffer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Complete Workflow Summary:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Create MTLAccelerationStructureTriangleGeometryDescriptor
   |
2. Configure MTLAccelerationStructureDescriptor with usage=.allowQuery
   |
3. Create MTLAccelerationStructure buffer on the device
   |
4. Allocate scratch buffer (query size first)
   |
5. Encode build command via MTLAccelerationStructureCommandEncoder
   |
6. Commit command buffer and wait
   |
7. Create compute pipeline from ray gen shader
   |
8. Encode compute pass: set AS, textures, parameters
   |
9. Dispatch threadgroups (one per pixel or tile)
   |
10. Commit and present
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;===&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Official Sample Analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Analyzing the gfx-rs Metal Ray Tracing Sample
&lt;/h3&gt;

&lt;p&gt;One of the most thorough open-source examples of Metal ray tracing is the &lt;strong&gt;gfx-rs metal-rs ray tracing sample&lt;/strong&gt;, available at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/gfx-rs/metal-rs/tree/master/examples/raytracing" rel="noopener noreferrer"&gt;https://github.com/gfx-rs/metal-rs/tree/master/examples/raytracing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This sample demonstrates a complete path tracer implemented in Metal, including:&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Implementation Details
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;1. Geometry Masks and Ray Types&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#define GEOMETRY_MASK_TRIANGLE 1
#define GEOMETRY_MASK_SPHERE   2
#define GEOMETRY_MASK_LIGHT    4
#define GEOMETRY_MASK_GEOMETRY (GEOMETRY_MASK_TRIANGLE | GEOMETRY_MASK_SPHERE)
#define RAY_MASK_PRIMARY   (GEOMETRY_MASK_GEOMETRY | GEOMETRY_MASK_LIGHT)
#define RAY_MASK_SHADOW    GEOMETRY_MASK_GEOMETRY
#define RAY_MASK_SECONDARY GEOMETRY_MASK_GEOMETRY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sample uses bitmasks to filter which geometry types each ray should intersect. Primary rays test everything (geometry + lights), shadow rays only test geometry, and secondary rays (reflections/refractions) also only test geometry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Custom Intersection Functions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The sample implements custom sphere intersection functions using the &lt;code&gt;[[intersection]]&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[[intersection(bounding_box, triangle_data, instancing)]]
BoundingBoxIntersection sphereIntersectionFunction(
    float3 origin [[origin]],
    float3 direction [[direction]],
    float minDistance [[min_distance]],
    float maxDistance [[max_distance]],
    unsigned int primitiveId [[primitive_id]],
    unsigned int geometryIndex [[geometry_intersection_function_table_offset]],
    device void* resources [[buffer(0), function_constant(useResourcesBuffer)]]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This demonstrates how Metal allows you to define bespoke intersection logic for non-standard primitives (like spheres) while still leveraging the hardware BVH traversal for bounding box culling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Per-Primitive Data&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The sample shows two approaches to binding geometry data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per-primitive data&lt;/strong&gt;: Each primitive has its own data buffer, accessed via the &lt;code&gt;[[primitive_data]]&lt;/code&gt; attribute&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources buffer&lt;/strong&gt;: A single buffer indexed by geometry type
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (usePerPrimitiveData) {
    sphere = *(const device Sphere*)perPrimitiveData;
} else {
    device SphereResources&amp;amp; sphereResources =
        *(device SphereResources*)((device char*)resources + resourcesStride * geometryIndex);
    sphere = sphereResources.spheres[primitiveId];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Monte Carlo Sampling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The sample implements cosine-weighted hemisphere sampling for diffuse shading:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;inline float3 sampleCosineWeightedHemisphere(float2 u) {
    float phi = 2.0f * M_PI_F * u.x;
    float cos_phi;
    float sin_phi = sincos(phi, cos_phi);
    float cos_theta = sqrt(u.y);
    float sin_theta = sqrt(1.0f - cos_theta * cos_theta);
    return float3(sin_theta * cos_phi, cos_theta, sin_theta * sin_phi);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Halton Sequence for Anti-Aliasing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;float halton(unsigned int i, unsigned int d) {
    unsigned int b = primes[d];
    float f = 1.0f;
    float invB = 1.0f / b;
    float r = 0;
    while (i &amp;gt; 0) {
        f = f * invB;
        r = r + f * (i % b);
        i = i / b;
    }
    return r;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This low-discrepancy sequence generates more evenly distributed samples than pure random numbers, reducing noise in rendered images.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apple's Official Samples
&lt;/h3&gt;

&lt;p&gt;Apple also provides official ray tracing samples through the Apple Developer portal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Accelerating ray tracing using Metal"&lt;/strong&gt; — Demonstrates basic ray tracing with motion blur&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Rendering reflections in real time using ray tracing"&lt;/strong&gt; — Implements real-time reflections via ray-traced compute passes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Enhance visual quality with curves using Metal ray tracing"&lt;/strong&gt; — Uses ray tracing for curve rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These samples are accessible at: &lt;a href="https://developer.apple.com/metal/sample-code/" rel="noopener noreferrer"&gt;https://developer.apple.com/metal/sample-code/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;===&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Common Errors and Solutions
&lt;/h3&gt;

&lt;p&gt;| Error | Cause | Solution |&lt;br&gt;
|=======|=======|==========|&lt;br&gt;
| &lt;code&gt;MTLDevice does not support ray tracing&lt;/code&gt; | Running on unsupported hardware or old macOS | Verify Apple Silicon + macOS 13+ |&lt;br&gt;
| &lt;code&gt;Invalid argument&lt;/code&gt; during &lt;code&gt;build()&lt;/code&gt; | Mismatched buffer types or invalid descriptor | Ensure vertex/index buffers are &lt;code&gt;storageModeShared&lt;/code&gt; or &lt;code&gt;storageModePrivate&lt;/code&gt; |&lt;br&gt;
| &lt;code&gt;Function table not bound&lt;/code&gt; | Missing intersection function table setup | Call &lt;code&gt;setIntersectionFunctionTable()&lt;/code&gt; on the compute encoder |&lt;br&gt;
| &lt;code&gt;Shader compilation error&lt;/code&gt; | Invalid Metal Shading Language syntax | Use Xcode's built-in Metal compiler diagnostics |&lt;br&gt;
| Empty/black output image | Ray miss handling or incorrect dispatch | Verify ray bounds, check &lt;code&gt;thread_position_in_grid&lt;/code&gt;, validate output texture format |&lt;br&gt;
| Performance issues | Too many rays per frame, no multithreading | Tile-based dispatch, reduce samples per pixel, use temporal accumulation |&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging with Xcode GPU Frame Capture
&lt;/h3&gt;

&lt;p&gt;Xcode provides powerful tools for debugging ray tracing pipelines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable Metal Validation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Product → Scheme → Edit Scheme&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Run → Options → Metal Validation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Validate Render/Compute Commands&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GPU Frame Capture&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click the &lt;strong&gt;Debug → Start GPU Frame Capture&lt;/strong&gt; menu&lt;/li&gt;
&lt;li&gt;Run your application&lt;/li&gt;
&lt;li&gt;Xcode will capture the entire GPU command stream&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inspect the Command Buffer&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the GPU debugger, expand the command buffer hierarchy&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;code&gt;MTLAccelerationStructureCommandEncoder&lt;/code&gt; to inspect build parameters&lt;/li&gt;
&lt;li&gt;View the acceleration structure's internal BVH representation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Shader Debugger&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set breakpoints in your Metal shader functions&lt;/li&gt;
&lt;li&gt;Inspect thread groups, thread IDs, and resource bindings&lt;/li&gt;
&lt;li&gt;Watch variables like &lt;code&gt;hit&lt;/code&gt;, &lt;code&gt;barycentrics&lt;/code&gt;, and &lt;code&gt;primitiveId&lt;/code&gt; during ray intersection&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Counter Sampling&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;   &lt;span class="c1"&gt;// Sample GPU counters for performance profiling&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;counterSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MTLCounterSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deviceCounterSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;timestampCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counterSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
   &lt;span class="c1"&gt;// Attach counters to your command buffer for timing analysis&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verification Checklist
&lt;/h3&gt;

&lt;p&gt;Before deploying, verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Device supports &lt;code&gt;MTLGPUFamilyApple3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Acceleration structure build completed without errors&lt;/li&gt;
&lt;li&gt;[ ] Scratch buffer size was correctly queried&lt;/li&gt;
&lt;li&gt;[ ] Ray gen shader compiles successfully&lt;/li&gt;
&lt;li&gt;[ ] Threadgroup dimensions cover all pixels&lt;/li&gt;
&lt;li&gt;[ ] Output texture format matches display requirements&lt;/li&gt;
&lt;li&gt;[ ] All buffers are properly retained and released&lt;/li&gt;
&lt;li&gt;[ ] No race conditions between AS updates and ray queries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;===&lt;/p&gt;

&lt;h2&gt;
  
  
  7. References
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Official Apple Documentation
&lt;/h3&gt;

&lt;p&gt;| Resource | URL |&lt;br&gt;
|==========|=====|&lt;br&gt;
| Ray Tracing with Acceleration Structures | &lt;a href="https://developer.apple.com/documentation/metal/ray-tracing-with-acceleration-structures" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/ray-tracing-with-acceleration-structures&lt;/a&gt; |&lt;br&gt;
| Accelerating Ray Tracing Using Metal | &lt;a href="https://developer.apple.com/documentation/metal/accelerating-ray-tracing-using-metal" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/accelerating-ray-tracing-using-metal&lt;/a&gt; |&lt;br&gt;
| MTLAccelerationStructureCommandEncoder | &lt;a href="https://developer.apple.com/documentation/metal/mtlaccelerationstructurecommandencoder" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/mtlaccelerationstructurecommandencoder&lt;/a&gt; |&lt;br&gt;
| MTLAccelerationStructureTriangleGeometryDescriptor | &lt;a href="https://developer.apple.com/documentation/metal/mtlaccelerationstructuretrianglegeometrydescriptor" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/mtlaccelerationstructuretrianglegeometrydescriptor&lt;/a&gt; |&lt;br&gt;
| MTLAccelerationStructureUsage | &lt;a href="https://developer.apple.com/documentation/metal/mtlaccelerationstructureusage" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/mtlaccelerationstructureusage&lt;/a&gt; |&lt;br&gt;
| MTLDevice (supportsFamily) | &lt;a href="https://developer.apple.com/documentation/metal/mtldevice" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/mtldevice&lt;/a&gt; |&lt;br&gt;
| MPSAccelerationStructure | &lt;a href="https://developer.apple.com/documentation/metalperformanceshaders/mpsaccelerationstructure" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metalperformanceshaders/mpsaccelerationstructure&lt;/a&gt; |&lt;br&gt;
| Control Ray Tracing with Intersection Queries | &lt;a href="https://developer.apple.com/documentation/metal/control-the-ray-tracing-process-using-intersection-queries" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/control-the-ray-tracing-process-using-intersection-queries&lt;/a&gt; |&lt;/p&gt;

&lt;h3&gt;
  
  
  Official Sample Code
&lt;/h3&gt;

&lt;p&gt;| Sample | URL |&lt;br&gt;
|========|=====|&lt;br&gt;
| Metal Sample Code (Apple Developer) | &lt;a href="https://developer.apple.com/metal/sample-code/" rel="noopener noreferrer"&gt;https://developer.apple.com/metal/sample-code/&lt;/a&gt; |&lt;br&gt;
| Metal FX Samples | &lt;a href="https://developer.apple.com/metal/sample-code/" rel="noopener noreferrer"&gt;https://developer.apple.com/metal/sample-code/&lt;/a&gt; |&lt;br&gt;
| Rendering Reflections in Real Time | &lt;a href="https://developer.apple.com/documentation/metal/rendering-reflections-in-real-time-using-ray-tracing" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/rendering-reflections-in-real-time-using-ray-tracing&lt;/a&gt; |&lt;br&gt;
| Accelerating Ray Tracing and Motion Blur | &lt;a href="https://developer.apple.com/documentation/metal/accelerating-ray-tracing-and-motion-blur-using-metal" rel="noopener noreferrer"&gt;https://developer.apple.com/documentation/metal/accelerating-ray-tracing-and-motion-blur-using-metal&lt;/a&gt; |&lt;/p&gt;

&lt;h3&gt;
  
  
  Community Resources
&lt;/h3&gt;

&lt;p&gt;| Resource | URL |&lt;br&gt;
|==========|=====|&lt;br&gt;
| gfx-rs metal-rs Ray Tracing Sample | &lt;a href="https://github.com/gfx-rs/metal-rs/tree/master/examples/raytracing" rel="noopener noreferrer"&gt;https://github.com/gfx-rs/metal-rs/tree/master/examples/raytracing&lt;/a&gt; |&lt;br&gt;
| Apple Docs Mirror (livingston) | &lt;a href="https://github.com/livingston/apple-docs" rel="noopener noreferrer"&gt;https://github.com/livingston/apple-docs&lt;/a&gt; |&lt;br&gt;
| DeepWiki: Metal Ray Tracing | &lt;a href="https://deepwiki.com/apple/metal-cpp/3.9-ray-tracing-and-acceleration-structures" rel="noopener noreferrer"&gt;https://deepwiki.com/apple/metal-cpp/3.9-ray-tracing-and-acceleration-structures&lt;/a&gt; |&lt;br&gt;
| Metal by Example | &lt;a href="https://metalbyexample.com/" rel="noopener noreferrer"&gt;https://metalbyexample.com/&lt;/a&gt; |&lt;/p&gt;

&lt;h3&gt;
  
  
  WWDC Sessions
&lt;/h3&gt;

&lt;p&gt;| Session | Topic |&lt;br&gt;
|=========|=======|&lt;br&gt;
| WWDC22 | "Explore Metal 3" — Introduces hardware ray tracing |&lt;br&gt;
| WWDC22 | "Advance graphics with MetalFX" — Upscaling and anti-aliasing |&lt;br&gt;
| WWDC23 | "Improve rendering with Metal ray tracing" — Advanced techniques |&lt;/p&gt;

&lt;p&gt;===&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
