├── .DS_Store ├── LICENSE ├── README.md ├── Screenshots ├── .DS_Store └── Screenshot.png └── SpatialMetal ├── .DS_Store ├── Metal ├── Earth.metal ├── ShaderTypes.h ├── ShaderTypes.swift └── Stars.metal ├── Resources └── Assets.xcassets │ ├── AccentColor.colorset │ └── Contents.json │ ├── AppIcon.solidimagestack │ ├── Back.solidimagestacklayer │ │ ├── Content.imageset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Contents.json │ ├── Front.solidimagestacklayer │ │ ├── Content.imageset │ │ │ └── Contents.json │ │ └── Contents.json │ └── Middle.solidimagestacklayer │ │ ├── Content.imageset │ │ └── Contents.json │ │ └── Contents.json │ ├── ColorMap.textureset │ ├── Contents.json │ └── Universal.mipmapset │ │ ├── ColorMap.png │ │ └── Contents.json │ ├── Contents.json │ ├── Earth.textureset │ ├── Contents.json │ └── Universal.mipmapset │ │ ├── Contents.json │ │ └── Earth.png │ └── Stars.textureset │ ├── Contents.json │ └── Universal.mipmapset │ ├── Contents.json │ └── Stars.jpg ├── SpatialMetal.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── warren.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── FullyImmersiveMetal.xcscheme └── xcuserdata │ └── warren.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist └── SpatialMetal ├── .DS_Store ├── App.swift ├── ContentView.swift ├── Info.plist ├── MeshTexture.swift ├── Renderer.swift ├── RendererProtocol.swift ├── SpatialRenderer.swift ├── UniformEyeBuf.swift ├── Utils.swift ├── extensions.swift └── studio.hdr /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Spatial Metal 2 | 3 | ![Example screenshot](Screenshots/Screenshot.png) 4 | 5 | Rendering two metal shaders in immersive space: Earth and Stars, which represent foreground and background. 6 | 7 | A fork of this project to allow for multiple uniform eye buffers is [here](https://github.com/musesum/SpatialMetal2) 8 | 9 | Started as a port of C++ version by Warren Moore, [here](https://github.com/metal-by-example/metal-spatial-rendering) 10 | 11 | Refactored to align with XCode Template: 12 | ``` 13 | File >> New Project >> visionOS >> App >> Window,Metal,Full 14 | ``` 15 | 16 | There was a previous iteration of this project that worked on a simulator but was missing key elements. This iteration is more likely to work, but not verified. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Screenshots/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/Screenshots/.DS_Store -------------------------------------------------------------------------------- /Screenshots/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/Screenshots/Screenshot.png -------------------------------------------------------------------------------- /SpatialMetal/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/.DS_Store -------------------------------------------------------------------------------- /SpatialMetal/Metal/Earth.metal: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "ShaderTypes.h" 5 | 6 | using namespace metal; 7 | 8 | struct EarthConstants { 9 | float4x4 earthMat; 10 | }; 11 | 12 | vertex VertexOut vertexEarth 13 | ( 14 | VertexIn in [[ stage_in ]], 15 | ushort ampId [[ amplification_id ]], 16 | constant UniformEyes &eyes [[ buffer(uniformEyei) ]]) 17 | { 18 | VertexOut out; 19 | 20 | Uniforms uniforms = eyes.eye[ampId]; 21 | 22 | out.position = (uniforms.projectionMat * 23 | uniforms.viewMat * 24 | float4(in.position.xyz, 1.0)); 25 | 26 | out.normal = (uniforms.viewMat * 27 | float4(in.normal, 0.0f)).xyz; 28 | 29 | out.texCoord = in.texCoord; 30 | out.texCoord.x = 1.0f - out.texCoord.x; // Flip uvs horizontally to match Model I/O 31 | return out; 32 | } 33 | 34 | fragment float4 fragmentEarth 35 | ( 36 | VertexOut out [[ stage_in ]], 37 | texture2d tex [[ texture(colori) ]]) 38 | { 39 | constexpr sampler samplr(coord::normalized, 40 | filter::linear, 41 | mip_filter::none, 42 | address::repeat); 43 | 44 | half4 color = tex.sample(samplr, out.texCoord); 45 | return float4(color); 46 | } 47 | -------------------------------------------------------------------------------- /SpatialMetal/Metal/ShaderTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShaderTypes.h 3 | 4 | #ifndef ShaderTypes_h 5 | #define ShaderTypes_h 6 | 7 | #ifdef __METAL_VERSION__ 8 | #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type 9 | typedef metal::int32_t EnumBackingType; 10 | #else 11 | #import 12 | typedef NSInteger EnumBackingType; 13 | #endif 14 | 15 | #include 16 | 17 | typedef enum { 18 | postitioni = 0, 19 | normali = 1, 20 | texcoordi = 2, 21 | uniformEyei = 3, 22 | } Bufferi; 23 | 24 | typedef enum { 25 | position = 0, 26 | texCoord = 1, 27 | normal = 2 28 | 29 | } Vertexi; 30 | 31 | typedef enum { 32 | colori = 0, 33 | } Texturei; 34 | 35 | struct VertexIn { 36 | float3 position [[ attribute(position) ]]; 37 | float3 normal [[ attribute(normal) ]]; 38 | float2 texCoord [[ attribute(texCoord) ]]; 39 | }; 40 | 41 | struct VertexOut { 42 | float4 position [[ position ]]; 43 | float3 normal; 44 | float2 texCoord; 45 | }; 46 | 47 | struct Uniforms { 48 | matrix_float4x4 projectionMat; 49 | matrix_float4x4 viewMat; 50 | }; 51 | struct UniformEyes { 52 | Uniforms eye[2]; 53 | }; 54 | 55 | #endif /* ShaderTypes_h */ 56 | 57 | -------------------------------------------------------------------------------- /SpatialMetal/Metal/ShaderTypes.swift: -------------------------------------------------------------------------------- 1 | // Created by musesum on 9/17/23. 2 | 3 | import simd 4 | 5 | struct Bufi { 6 | static let positioni = 0 7 | static let texcoordi = 1 8 | static let normali = 2 9 | static let uniformEyei = 3 10 | } 11 | 12 | struct Vertexi { 13 | static let position = 0 14 | static let texcoord = 1 15 | static let normal = 2 16 | } 17 | 18 | struct Texturei { 19 | static let colori = 0 20 | } 21 | 22 | enum RendererError: Error { 23 | case badVertex 24 | } 25 | 26 | public struct Uniforms { 27 | var projectionMat: matrix_float4x4 28 | var viewMat: matrix_float4x4 29 | } 30 | 31 | public struct UniformEyes { 32 | // a uniform for each eye 33 | var eye: (Uniforms, Uniforms) 34 | } 35 | -------------------------------------------------------------------------------- /SpatialMetal/Metal/Stars.metal: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "ShaderTypes.h" 4 | 5 | using namespace metal; 6 | 7 | vertex VertexOut vertexStars 8 | ( 9 | VertexIn in [[ stage_in ]], 10 | ushort amp_id [[ amplification_id ]], 11 | constant UniformEyes &eyes [[ buffer(uniformEyei) ]]) 12 | { 13 | VertexOut out; 14 | 15 | Uniforms uniforms = eyes.eye[amp_id]; 16 | float4 position = float4(in.position, 1.0); 17 | 18 | out.position = (uniforms.projectionMat * 19 | uniforms.viewMat * 20 | position); 21 | 22 | out.normal = -in.normal; 23 | out.texCoord = in.texCoord; 24 | return out; 25 | } 26 | 27 | fragment float4 fragmentStars 28 | ( 29 | VertexOut out [[ stage_in ]], 30 | texture2d tex [[ texture(colori) ]]) 31 | { 32 | constexpr sampler samplr(coord::normalized, 33 | filter::linear, 34 | mip_filter::none, 35 | address::repeat); 36 | 37 | float4 color = tex.sample(samplr, out.texCoord); 38 | return color; 39 | } 40 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.575", 9 | "green" : "0.106", 10 | "red" : "0.324" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.575", 27 | "green" : "0.106", 28 | "red" : "0.324" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "reality", 5 | "scale" : "2x" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.solidimagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.solidimagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.solidimagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "reality", 5 | "scale" : "2x" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "reality", 5 | "scale" : "2x" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/ColorMap.textureset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "properties" : { 7 | "interpretation" : "non-premultiplied-colors", 8 | "origin" : "bottom-left" 9 | }, 10 | "textures" : [ 11 | { 12 | "filename" : "Universal.mipmapset", 13 | "idiom" : "universal" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/ColorMap.textureset/Universal.mipmapset/ColorMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/Resources/Assets.xcassets/ColorMap.textureset/Universal.mipmapset/ColorMap.png -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/ColorMap.textureset/Universal.mipmapset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "levels" : [ 7 | { 8 | "filename" : "ColorMap.png", 9 | "mipmap-level" : "base" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Earth.textureset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "properties" : { 7 | "interpretation" : "non-premultiplied-colors", 8 | "origin" : "bottom-left" 9 | }, 10 | "textures" : [ 11 | { 12 | "filename" : "Universal.mipmapset", 13 | "idiom" : "universal" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Earth.textureset/Universal.mipmapset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "levels" : [ 7 | { 8 | "filename" : "Earth.png", 9 | "mipmap-level" : "base" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Earth.textureset/Universal.mipmapset/Earth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/Resources/Assets.xcassets/Earth.textureset/Universal.mipmapset/Earth.png -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Stars.textureset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "properties" : { 7 | "interpretation" : "non-premultiplied-colors", 8 | "origin" : "bottom-left" 9 | }, 10 | "textures" : [ 11 | { 12 | "filename" : "Universal.mipmapset", 13 | "idiom" : "universal" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Stars.textureset/Universal.mipmapset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "levels" : [ 7 | { 8 | "filename" : "Stars.jpg", 9 | "mipmap-level" : "base" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /SpatialMetal/Resources/Assets.xcassets/Stars.textureset/Universal.mipmapset/Stars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/Resources/Assets.xcassets/Stars.textureset/Universal.mipmapset/Stars.jpg -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8000B6EC2AB7FEB7002964B3 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 8000B6EB2AB7FEB7002964B3 /* README.md */; }; 11 | 8000B6EE2AB810CB002964B3 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8000B6ED2AB810CB002964B3 /* Utils.swift */; }; 12 | 8000B6F52AB909A7002964B3 /* SpatialRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8000B6F42AB909A7002964B3 /* SpatialRenderer.swift */; }; 13 | 8050FF1E2A7DDBF400015814 /* MeshTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8050FF1B2A7CA78400015814 /* MeshTexture.swift */; }; 14 | 8050FF222A7DE9AA00015814 /* ARKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8050FF212A7DE9AA00015814 /* ARKit.framework */; }; 15 | 8050FF4D2A7DF99C00015814 /* Renderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8050FF192A7C9CAD00015814 /* Renderer.swift */; }; 16 | 807649FC2AD3379200399B00 /* UniformEyeBuf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 807649FB2AD3379200399B00 /* UniformEyeBuf.swift */; }; 17 | 80ADA3092AB7F05900FCF8FF /* ShaderTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80ADA3082AB7F05900FCF8FF /* ShaderTypes.swift */; }; 18 | 80DB56E42ACB336C006DB2FF /* RendererProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80DB56E32ACB336C006DB2FF /* RendererProtocol.swift */; }; 19 | 830175B22A44AC87008CAD8B /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830175B12A44AC87008CAD8B /* App.swift */; }; 20 | 830175B42A44AC87008CAD8B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830175B32A44AC87008CAD8B /* ContentView.swift */; }; 21 | 830175BA2A44AC87008CAD8B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 830175B92A44AC87008CAD8B /* Assets.xcassets */; }; 22 | 830175CA2A44BE8C008CAD8B /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 830175C82A44BE8C008CAD8B /* Metal.framework */; }; 23 | 830175CB2A44BE8C008CAD8B /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 830175C92A44BE8C008CAD8B /* MetalKit.framework */; }; 24 | 830175CD2A44BE96008CAD8B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 830175CC2A44BE96008CAD8B /* Foundation.framework */; }; 25 | 830175CF2A44BE9B008CAD8B /* CompositorServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 830175CE2A44BE9B008CAD8B /* CompositorServices.framework */; }; 26 | 8394CE862A44D36D005A8B04 /* Earth.metal in Sources */ = {isa = PBXBuildFile; fileRef = 8394CE852A44D36D005A8B04 /* Earth.metal */; }; 27 | 8394CE8A2A44DD41005A8B04 /* Stars.metal in Sources */ = {isa = PBXBuildFile; fileRef = 8394CE892A44DD41005A8B04 /* Stars.metal */; }; 28 | 8394CE8C2A44E2D2005A8B04 /* ModelIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8394CE8B2A44E2D2005A8B04 /* ModelIO.framework */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 8000B6EB2AB7FEB7002964B3 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 33 | 8000B6ED2AB810CB002964B3 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 34 | 8000B6EF2AB8B9F2002964B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 35 | 8000B6F42AB909A7002964B3 /* SpatialRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpatialRenderer.swift; sourceTree = ""; }; 36 | 80299BBF2AC884CE000C441C /* ShaderTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShaderTypes.h; sourceTree = ""; }; 37 | 8050FF192A7C9CAD00015814 /* Renderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Renderer.swift; sourceTree = ""; }; 38 | 8050FF1B2A7CA78400015814 /* MeshTexture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshTexture.swift; sourceTree = ""; }; 39 | 8050FF212A7DE9AA00015814 /* ARKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ARKit.framework; path = System/Library/Frameworks/ARKit.framework; sourceTree = SDKROOT; }; 40 | 807649FB2AD3379200399B00 /* UniformEyeBuf.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniformEyeBuf.swift; sourceTree = ""; }; 41 | 80ADA3082AB7F05900FCF8FF /* ShaderTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShaderTypes.swift; sourceTree = ""; }; 42 | 80DB56E32ACB336C006DB2FF /* RendererProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RendererProtocol.swift; sourceTree = ""; }; 43 | 830175AA2A44AC87008CAD8B /* SpatialMetal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SpatialMetal.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 830175B12A44AC87008CAD8B /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; 45 | 830175B32A44AC87008CAD8B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 46 | 830175B92A44AC87008CAD8B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | 830175C82A44BE8C008CAD8B /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 48 | 830175C92A44BE8C008CAD8B /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 49 | 830175CC2A44BE96008CAD8B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 50 | 830175CE2A44BE9B008CAD8B /* CompositorServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CompositorServices.framework; path = System/Library/Frameworks/CompositorServices.framework; sourceTree = SDKROOT; }; 51 | 8394CE852A44D36D005A8B04 /* Earth.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Earth.metal; sourceTree = ""; }; 52 | 8394CE892A44DD41005A8B04 /* Stars.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Stars.metal; sourceTree = ""; }; 53 | 8394CE8B2A44E2D2005A8B04 /* ModelIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModelIO.framework; path = System/Library/Frameworks/ModelIO.framework; sourceTree = SDKROOT; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | 830175A72A44AC87008CAD8B /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | 8050FF222A7DE9AA00015814 /* ARKit.framework in Frameworks */, 62 | 830175CA2A44BE8C008CAD8B /* Metal.framework in Frameworks */, 63 | 830175CD2A44BE96008CAD8B /* Foundation.framework in Frameworks */, 64 | 830175CB2A44BE8C008CAD8B /* MetalKit.framework in Frameworks */, 65 | 830175CF2A44BE9B008CAD8B /* CompositorServices.framework in Frameworks */, 66 | 8394CE8C2A44E2D2005A8B04 /* ModelIO.framework in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | 80ADA3072AB7EE3600FCF8FF /* Metal */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 8394CE852A44D36D005A8B04 /* Earth.metal */, 77 | 8394CE892A44DD41005A8B04 /* Stars.metal */, 78 | 80ADA3082AB7F05900FCF8FF /* ShaderTypes.swift */, 79 | 80299BBF2AC884CE000C441C /* ShaderTypes.h */, 80 | ); 81 | path = Metal; 82 | sourceTree = ""; 83 | }; 84 | 80ADA30A2AB7F09B00FCF8FF /* Resources */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 830175B92A44AC87008CAD8B /* Assets.xcassets */, 88 | ); 89 | path = Resources; 90 | sourceTree = ""; 91 | }; 92 | 830175A12A44AC87008CAD8B = { 93 | isa = PBXGroup; 94 | children = ( 95 | 8000B6EB2AB7FEB7002964B3 /* README.md */, 96 | 830175AC2A44AC87008CAD8B /* SpatialMetal */, 97 | 80ADA3072AB7EE3600FCF8FF /* Metal */, 98 | 80ADA30A2AB7F09B00FCF8FF /* Resources */, 99 | 830175AB2A44AC87008CAD8B /* Products */, 100 | 830175C72A44BE8C008CAD8B /* Frameworks */, 101 | ); 102 | sourceTree = ""; 103 | }; 104 | 830175AB2A44AC87008CAD8B /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 830175AA2A44AC87008CAD8B /* SpatialMetal.app */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 830175AC2A44AC87008CAD8B /* SpatialMetal */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 830175B12A44AC87008CAD8B /* App.swift */, 116 | 830175B32A44AC87008CAD8B /* ContentView.swift */, 117 | 8000B6EF2AB8B9F2002964B3 /* Info.plist */, 118 | 8050FF192A7C9CAD00015814 /* Renderer.swift */, 119 | 80DB56E32ACB336C006DB2FF /* RendererProtocol.swift */, 120 | 807649FB2AD3379200399B00 /* UniformEyeBuf.swift */, 121 | 8000B6F42AB909A7002964B3 /* SpatialRenderer.swift */, 122 | 8050FF1B2A7CA78400015814 /* MeshTexture.swift */, 123 | 8000B6ED2AB810CB002964B3 /* Utils.swift */, 124 | ); 125 | path = SpatialMetal; 126 | sourceTree = ""; 127 | }; 128 | 830175C72A44BE8C008CAD8B /* Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 8050FF212A7DE9AA00015814 /* ARKit.framework */, 132 | 8394CE8B2A44E2D2005A8B04 /* ModelIO.framework */, 133 | 830175CE2A44BE9B008CAD8B /* CompositorServices.framework */, 134 | 830175CC2A44BE96008CAD8B /* Foundation.framework */, 135 | 830175C82A44BE8C008CAD8B /* Metal.framework */, 136 | 830175C92A44BE8C008CAD8B /* MetalKit.framework */, 137 | ); 138 | name = Frameworks; 139 | sourceTree = ""; 140 | }; 141 | /* End PBXGroup section */ 142 | 143 | /* Begin PBXNativeTarget section */ 144 | 830175A92A44AC87008CAD8B /* SpatialMetal */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = 830175C02A44AC87008CAD8B /* Build configuration list for PBXNativeTarget "SpatialMetal" */; 147 | buildPhases = ( 148 | 830175A62A44AC87008CAD8B /* Sources */, 149 | 830175A72A44AC87008CAD8B /* Frameworks */, 150 | 830175A82A44AC87008CAD8B /* Resources */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = SpatialMetal; 157 | packageProductDependencies = ( 158 | ); 159 | productName = FullyImmersiveMetal; 160 | productReference = 830175AA2A44AC87008CAD8B /* SpatialMetal.app */; 161 | productType = "com.apple.product-type.application"; 162 | }; 163 | /* End PBXNativeTarget section */ 164 | 165 | /* Begin PBXProject section */ 166 | 830175A22A44AC87008CAD8B /* Project object */ = { 167 | isa = PBXProject; 168 | attributes = { 169 | BuildIndependentTargetsInParallel = 1; 170 | LastSwiftUpdateCheck = 1500; 171 | LastUpgradeCheck = 1500; 172 | TargetAttributes = { 173 | 830175A92A44AC87008CAD8B = { 174 | CreatedOnToolsVersion = 15.0; 175 | LastSwiftMigration = 1500; 176 | }; 177 | }; 178 | }; 179 | buildConfigurationList = 830175A52A44AC87008CAD8B /* Build configuration list for PBXProject "SpatialMetal" */; 180 | compatibilityVersion = "Xcode 14.0"; 181 | developmentRegion = en; 182 | hasScannedForEncodings = 0; 183 | knownRegions = ( 184 | en, 185 | Base, 186 | ); 187 | mainGroup = 830175A12A44AC87008CAD8B; 188 | productRefGroup = 830175AB2A44AC87008CAD8B /* Products */; 189 | projectDirPath = ""; 190 | projectRoot = ""; 191 | targets = ( 192 | 830175A92A44AC87008CAD8B /* SpatialMetal */, 193 | ); 194 | }; 195 | /* End PBXProject section */ 196 | 197 | /* Begin PBXResourcesBuildPhase section */ 198 | 830175A82A44AC87008CAD8B /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | 8000B6EC2AB7FEB7002964B3 /* README.md in Resources */, 203 | 830175BA2A44AC87008CAD8B /* Assets.xcassets in Resources */, 204 | ); 205 | runOnlyForDeploymentPostprocessing = 0; 206 | }; 207 | /* End PBXResourcesBuildPhase section */ 208 | 209 | /* Begin PBXSourcesBuildPhase section */ 210 | 830175A62A44AC87008CAD8B /* Sources */ = { 211 | isa = PBXSourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | 8394CE862A44D36D005A8B04 /* Earth.metal in Sources */, 215 | 8394CE8A2A44DD41005A8B04 /* Stars.metal in Sources */, 216 | 830175B42A44AC87008CAD8B /* ContentView.swift in Sources */, 217 | 8050FF4D2A7DF99C00015814 /* Renderer.swift in Sources */, 218 | 80DB56E42ACB336C006DB2FF /* RendererProtocol.swift in Sources */, 219 | 8000B6F52AB909A7002964B3 /* SpatialRenderer.swift in Sources */, 220 | 807649FC2AD3379200399B00 /* UniformEyeBuf.swift in Sources */, 221 | 8000B6EE2AB810CB002964B3 /* Utils.swift in Sources */, 222 | 80ADA3092AB7F05900FCF8FF /* ShaderTypes.swift in Sources */, 223 | 8050FF1E2A7DDBF400015814 /* MeshTexture.swift in Sources */, 224 | 830175B22A44AC87008CAD8B /* App.swift in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXSourcesBuildPhase section */ 229 | 230 | /* Begin XCBuildConfiguration section */ 231 | 830175BE2A44AC87008CAD8B /* Debug */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | ALWAYS_SEARCH_USER_PATHS = NO; 235 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 236 | CLANG_ANALYZER_NONNULL = YES; 237 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 238 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 239 | CLANG_ENABLE_MODULES = YES; 240 | CLANG_ENABLE_OBJC_ARC = YES; 241 | CLANG_ENABLE_OBJC_WEAK = YES; 242 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 243 | CLANG_WARN_BOOL_CONVERSION = YES; 244 | CLANG_WARN_COMMA = YES; 245 | CLANG_WARN_CONSTANT_CONVERSION = YES; 246 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 248 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 258 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 259 | CLANG_WARN_STRICT_PROTOTYPES = YES; 260 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 261 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = dwarf; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | ENABLE_TESTABILITY = YES; 268 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu17; 270 | GCC_DYNAMIC_NO_PIC = NO; 271 | GCC_NO_COMMON_BLOCKS = YES; 272 | GCC_OPTIMIZATION_LEVEL = 0; 273 | GCC_PREPROCESSOR_DEFINITIONS = ( 274 | "DEBUG=1", 275 | "$(inherited)", 276 | ); 277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 279 | GCC_WARN_UNDECLARED_SELECTOR = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 281 | GCC_WARN_UNUSED_FUNCTION = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 284 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 285 | MTL_FAST_MATH = YES; 286 | ONLY_ACTIVE_ARCH = YES; 287 | SDKROOT = xros; 288 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 289 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 290 | XROS_DEPLOYMENT_TARGET = 1.0; 291 | }; 292 | name = Debug; 293 | }; 294 | 830175BF2A44AC87008CAD8B /* Release */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ALWAYS_SEARCH_USER_PATHS = NO; 298 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 299 | CLANG_ANALYZER_NONNULL = YES; 300 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 301 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 302 | CLANG_ENABLE_MODULES = YES; 303 | CLANG_ENABLE_OBJC_ARC = YES; 304 | CLANG_ENABLE_OBJC_WEAK = YES; 305 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 306 | CLANG_WARN_BOOL_CONVERSION = YES; 307 | CLANG_WARN_COMMA = YES; 308 | CLANG_WARN_CONSTANT_CONVERSION = YES; 309 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 311 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 312 | CLANG_WARN_EMPTY_BODY = YES; 313 | CLANG_WARN_ENUM_CONVERSION = YES; 314 | CLANG_WARN_INFINITE_RECURSION = YES; 315 | CLANG_WARN_INT_CONVERSION = YES; 316 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 317 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 318 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 319 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 320 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 322 | CLANG_WARN_STRICT_PROTOTYPES = YES; 323 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 324 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 325 | CLANG_WARN_UNREACHABLE_CODE = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | COPY_PHASE_STRIP = NO; 328 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 329 | ENABLE_NS_ASSERTIONS = NO; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 332 | GCC_C_LANGUAGE_STANDARD = gnu17; 333 | GCC_NO_COMMON_BLOCKS = YES; 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 341 | MTL_ENABLE_DEBUG_INFO = NO; 342 | MTL_FAST_MATH = YES; 343 | SDKROOT = xros; 344 | SWIFT_COMPILATION_MODE = wholemodule; 345 | VALIDATE_PRODUCT = YES; 346 | XROS_DEPLOYMENT_TARGET = 1.0; 347 | }; 348 | name = Release; 349 | }; 350 | 830175C12A44AC87008CAD8B /* Debug */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 354 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 355 | CLANG_ENABLE_MODULES = YES; 356 | CODE_SIGN_STYLE = Automatic; 357 | CURRENT_PROJECT_VERSION = 1; 358 | DEVELOPMENT_TEAM = 9AVP5GX45R; 359 | ENABLE_PREVIEWS = YES; 360 | GENERATE_INFOPLIST_FILE = YES; 361 | INFOPLIST_FILE = SpatialMetal/Info.plist; 362 | INFOPLIST_KEY_NSCameraUsageDescription = "This app uses the camera to get pose estimates for immersive AR experiences"; 363 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 364 | LD_RUNPATH_SEARCH_PATHS = ( 365 | "$(inherited)", 366 | "@executable_path/Frameworks", 367 | ); 368 | MARKETING_VERSION = 1.0; 369 | PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES; 370 | PRODUCT_BUNDLE_IDENTIFIER = com.deepmuse.spatialmetal; 371 | PRODUCT_NAME = "$(TARGET_NAME)"; 372 | SUPPORTED_PLATFORMS = "xros xrsimulator"; 373 | SWIFT_EMIT_LOC_STRINGS = YES; 374 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 375 | SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; 376 | SWIFT_VERSION = 5.0; 377 | TARGETED_DEVICE_FAMILY = "1,2,7"; 378 | }; 379 | name = Debug; 380 | }; 381 | 830175C22A44AC87008CAD8B /* Release */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 385 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 386 | CLANG_ENABLE_MODULES = YES; 387 | CODE_SIGN_STYLE = Automatic; 388 | CURRENT_PROJECT_VERSION = 1; 389 | DEVELOPMENT_TEAM = 9AVP5GX45R; 390 | ENABLE_PREVIEWS = YES; 391 | GENERATE_INFOPLIST_FILE = YES; 392 | INFOPLIST_FILE = SpatialMetal/Info.plist; 393 | INFOPLIST_KEY_NSCameraUsageDescription = "This app uses the camera to get pose estimates for immersive AR experiences"; 394 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 395 | LD_RUNPATH_SEARCH_PATHS = ( 396 | "$(inherited)", 397 | "@executable_path/Frameworks", 398 | ); 399 | MARKETING_VERSION = 1.0; 400 | PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = YES; 401 | PRODUCT_BUNDLE_IDENTIFIER = com.deepmuse.spatialmetal; 402 | PRODUCT_NAME = "$(TARGET_NAME)"; 403 | SUPPORTED_PLATFORMS = "xros xrsimulator"; 404 | SWIFT_EMIT_LOC_STRINGS = YES; 405 | SWIFT_PRECOMPILE_BRIDGING_HEADER = NO; 406 | SWIFT_VERSION = 5.0; 407 | TARGETED_DEVICE_FAMILY = "1,2,7"; 408 | }; 409 | name = Release; 410 | }; 411 | /* End XCBuildConfiguration section */ 412 | 413 | /* Begin XCConfigurationList section */ 414 | 830175A52A44AC87008CAD8B /* Build configuration list for PBXProject "SpatialMetal" */ = { 415 | isa = XCConfigurationList; 416 | buildConfigurations = ( 417 | 830175BE2A44AC87008CAD8B /* Debug */, 418 | 830175BF2A44AC87008CAD8B /* Release */, 419 | ); 420 | defaultConfigurationIsVisible = 0; 421 | defaultConfigurationName = Release; 422 | }; 423 | 830175C02A44AC87008CAD8B /* Build configuration list for PBXNativeTarget "SpatialMetal" */ = { 424 | isa = XCConfigurationList; 425 | buildConfigurations = ( 426 | 830175C12A44AC87008CAD8B /* Debug */, 427 | 830175C22A44AC87008CAD8B /* Release */, 428 | ); 429 | defaultConfigurationIsVisible = 0; 430 | defaultConfigurationName = Release; 431 | }; 432 | /* End XCConfigurationList section */ 433 | }; 434 | rootObject = 830175A22A44AC87008CAD8B /* Project object */; 435 | } 436 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/project.xcworkspace/xcuserdata/warren.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/SpatialMetal.xcodeproj/project.xcworkspace/xcuserdata/warren.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/xcshareddata/xcschemes/FullyImmersiveMetal.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 42 | 44 | 50 | 51 | 52 | 53 | 59 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/xcuserdata/warren.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 21 | 22 | 23 | 25 | 37 | 38 | 39 | 41 | 53 | 54 | 55 | 57 | 69 | 70 | 71 | 73 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal.xcodeproj/xcuserdata/warren.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FullyImmersiveMetal.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 830175A92A44AC87008CAD8B 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/SpatialMetal/.DS_Store -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/App.swift: -------------------------------------------------------------------------------- 1 | // modified by musesum 2 | 3 | import SwiftUI 4 | import CompositorServices 5 | 6 | @main 7 | struct SpatialApp: App { 8 | 9 | @State private var immersionStyle: ImmersionStyle = .full 10 | 11 | init() {} 12 | 13 | var body: some Scene { 14 | WindowGroup { 15 | ContentView() 16 | }.windowStyle(.automatic) 17 | ImmersiveSpace(id: "ImmersiveSpace") { 18 | CompositorLayer(configuration: ContentStageConfiguration()) { layerRenderer in 19 | _ = SpatialRenderer(layerRenderer) 20 | } 21 | } 22 | .immersionStyle(selection: .constant(.full), in: .full) 23 | } 24 | } 25 | 26 | struct ContentStageConfiguration: CompositorLayerConfiguration { 27 | func makeConfiguration(capabilities: LayerRenderer.Capabilities, 28 | configuration: inout LayerRenderer.Configuration) { 29 | configuration.depthFormat = .depth32Float 30 | configuration.colorFormat = .bgra8Unorm_srgb 31 | 32 | let foveationEnabled = capabilities.supportsFoveation 33 | configuration.isFoveationEnabled = foveationEnabled 34 | 35 | let options: LayerRenderer.Capabilities.SupportedLayoutsOptions = foveationEnabled ? [.foveationEnabled] : [] 36 | let supportedLayouts = capabilities.supportedLayouts(options: options) 37 | 38 | configuration.layout = supportedLayouts.contains(.layered) ? .layered : .dedicated 39 | } 40 | } 41 | 42 | extension LayerRenderer.Clock.Instant.Duration { 43 | var timeInterval: TimeInterval { 44 | let nanoseconds = TimeInterval(components.attoseconds / 1_000_000_000) 45 | return TimeInterval(components.seconds) + (nanoseconds / TimeInterval(NSEC_PER_SEC)) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import RealityKit 3 | 4 | struct ContentView: View { 5 | @State private var showImmersiveSpace = false 6 | @State private var immersiveSpaceIsShown = false 7 | 8 | @Environment(\.openImmersiveSpace) var openImmersiveSpace 9 | @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace 10 | 11 | var body: some View { 12 | 13 | VStack { 14 | Toggle(showImmersiveSpace ? "Exit Immersive Space" : "Launch Immersive Space", isOn: $showImmersiveSpace) 15 | .toggleStyle(.button) 16 | }.padding().glassBackgroundEffect() 17 | 18 | .onChange(of: showImmersiveSpace) { _, newValue in 19 | Task { 20 | if newValue { 21 | switch await openImmersiveSpace(id: "ImmersiveSpace") { 22 | case .opened: 23 | immersiveSpaceIsShown = true 24 | default: 25 | immersiveSpaceIsShown = false 26 | showImmersiveSpace = false 27 | } 28 | } else if immersiveSpaceIsShown { 29 | await dismissImmersiveSpace() 30 | immersiveSpaceIsShown = false 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationPreferredDefaultSceneSessionRole 8 | UIWindowSceneSessionRoleApplication 9 | UIApplicationSupportsMultipleScenes 10 | 11 | UISceneConfigurations 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/MeshTexture.swift: -------------------------------------------------------------------------------- 1 | // Created by musesum on 8/4/23. 2 | 3 | import MetalKit 4 | import Spatial 5 | 6 | class MeshTexture { 7 | 8 | var texName: String 9 | var texture: MTLTexture 10 | var metalVD: MTLVertexDescriptor 11 | var mesh: MTKMesh? 12 | var stencil: MTLDepthStencilState? 13 | var device: MTLDevice 14 | 15 | init(device : MTLDevice, 16 | texName : String, 17 | compare : MTLCompareFunction) throws { 18 | 19 | self.device = device 20 | self.texName = texName 21 | texture = loadTexture(device, texName) 22 | metalVD = MTLVertexDescriptor() 23 | 24 | let sd = MTLDepthStencilDescriptor() 25 | sd.isDepthWriteEnabled = true 26 | sd.depthCompareFunction = compare 27 | stencil = device.makeDepthStencilState(descriptor: sd) 28 | } 29 | 30 | func draw(_ renderCommand: MTLRenderCommandEncoder, 31 | _ pipeline: MTLRenderPipelineState, 32 | _ winding: MTLWinding) { 33 | 34 | guard let stencil else { return err("\(texName) stencil") } 35 | guard let mesh else { return err("\(texName) mesh") } 36 | 37 | renderCommand.setCullMode(.back) 38 | renderCommand.setRenderPipelineState(pipeline) 39 | renderCommand.setFrontFacing(winding) 40 | renderCommand.setDepthStencilState(stencil) 41 | 42 | for (index, element) in mesh.vertexDescriptor.layouts.enumerated() { 43 | guard let layout = element as? MDLVertexBufferLayout else { return } 44 | 45 | if layout.stride != 0 { 46 | let vb = mesh.vertexBuffers[index] 47 | renderCommand.setVertexBuffer(vb.buffer, offset: vb.offset, index: index) 48 | } 49 | } 50 | renderCommand.setFragmentTexture(texture, index: Texturei.colori) 51 | 52 | for submesh in mesh.submeshes { 53 | renderCommand.drawIndexedPrimitives( 54 | type : submesh.primitiveType, 55 | indexCount : submesh.indexCount, 56 | indexType : submesh.indexType, 57 | indexBuffer : submesh.indexBuffer.buffer, 58 | indexBufferOffset : submesh.indexBuffer.offset) 59 | } 60 | func err(_ msg: String) { 61 | print("⁉️ \(texName) Mesh::draw error : \(msg)") 62 | } 63 | } 64 | } 65 | 66 | class MeshEllipsoid: MeshTexture { 67 | 68 | var radius = CGFloat(1) 69 | var inward = false 70 | 71 | init(_ device : MTLDevice, 72 | _ texName : String, 73 | _ compare : MTLCompareFunction, 74 | radius : CGFloat, 75 | inward : Bool) throws { 76 | 77 | try super.init(device : device, 78 | texName : texName, 79 | compare : compare) 80 | 81 | self.radius = radius 82 | self.inward = inward 83 | 84 | guard let modelMesh = modelEllipsoid(device) else { 85 | throw RendererError.badVertex 86 | } 87 | mesh = try MTKMesh(mesh: modelMesh, device: device) 88 | 89 | func err(_ msg: String) { 90 | print("⁉️ \(texName) Mesh::draw error : \(msg)") 91 | } 92 | } 93 | 94 | func modelEllipsoid(_ device: MTLDevice) -> MDLMesh? { 95 | 96 | makeMetalVD() 97 | let allocator = MTKMeshBufferAllocator(device: device) 98 | let radii = SIMD3(repeating: Float(radius)) 99 | let modelMesh = MDLMesh.newEllipsoid( 100 | withRadii : radii, 101 | radialSegments : 24, 102 | verticalSegments : 24, 103 | geometryType : .triangles, 104 | inwardNormals : inward, 105 | hemisphere : false, 106 | allocator : allocator) 107 | 108 | let modelVD = MTKModelIOVertexDescriptorFromMetal(metalVD) 109 | guard let attributes = modelVD.attributes as? [MDLVertexAttribute] else { 110 | return nil 111 | } 112 | attributes[Vertexi.position].name = MDLVertexAttributePosition 113 | attributes[Vertexi.normal ].name = MDLVertexAttributeNormal 114 | attributes[Vertexi.texcoord].name = MDLVertexAttributeTextureCoordinate 115 | 116 | modelMesh.vertexDescriptor = modelVD 117 | return modelMesh 118 | } 119 | func makeMetalVD() { 120 | 121 | let vd = MTLVertexDescriptor() 122 | addVertexFormat(.float3, Vertexi.position, Bufi.positioni) 123 | addVertexFormat(.float2, Vertexi.normal , Bufi.normali ) 124 | addVertexFormat(.float3, Vertexi.texcoord, Bufi.texcoordi) 125 | 126 | func addVertexFormat(_ format: MTLVertexFormat, 127 | _ vertexi: Int, 128 | _ layouti: Int ) { 129 | let stride: Int 130 | switch format { 131 | case .float2: stride = MemoryLayout.size * 2 132 | case .float3: stride = MemoryLayout.size * 3 133 | default: return 134 | } 135 | vd.attributes[vertexi].format = format 136 | vd.attributes[vertexi].offset = 0 137 | vd.attributes[vertexi].bufferIndex = layouti 138 | vd.layouts[layouti].stride = stride 139 | vd.layouts[layouti].stepRate = 1 140 | vd.layouts[layouti].stepFunction = .perVertex 141 | } 142 | metalVD = vd 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/Renderer.swift: -------------------------------------------------------------------------------- 1 | // Created by musesum on 8/4/23. 2 | 3 | import MetalKit 4 | import ARKit 5 | import Spatial 6 | import CompositorServices 7 | import simd 8 | 9 | class Renderer { 10 | 11 | var delegate: RendererProtocol? 12 | let device: MTLDevice 13 | let commandQueue: MTLCommandQueue 14 | let inFlightSemaphore = DispatchSemaphore(value: tripleBufferCount) 15 | let arSession = ARKitSession() 16 | let worldTracking = WorldTrackingProvider() 17 | let layerRenderer: LayerRenderer 18 | var rotation: Float = 0 19 | 20 | init(_ layerRenderer: LayerRenderer) { 21 | 22 | self.layerRenderer = layerRenderer 23 | self.device = MTLCreateSystemDefaultDevice()! 24 | self.commandQueue = device.makeCommandQueue()! 25 | } 26 | func setDelegate(_ delegate: RendererProtocol) { 27 | self.delegate = delegate 28 | delegate.makeResources() 29 | delegate.makePipeline(layerRenderer) 30 | } 31 | 32 | func makeRenderPass(drawable: LayerRenderer.Drawable) -> MTLRenderPassDescriptor { 33 | 34 | let renderPass = MTLRenderPassDescriptor() 35 | renderPass.colorAttachments[0].texture = drawable.colorTextures[0] 36 | renderPass.colorAttachments[0].loadAction = .clear 37 | renderPass.colorAttachments[0].storeAction = .store 38 | renderPass.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0) 39 | 40 | renderPass.depthAttachment.texture = drawable.depthTextures[0] 41 | renderPass.depthAttachment.loadAction = .clear 42 | renderPass.depthAttachment.storeAction = .store 43 | renderPass.depthAttachment.clearDepth = 0.0 44 | 45 | renderPass.rasterizationRateMap = drawable.rasterizationRateMaps.first 46 | if layerRenderer.configuration.layout == .layered { 47 | renderPass.renderTargetArrayLength = drawable.views.count 48 | } 49 | return renderPass 50 | } 51 | 52 | func renderFrame() { 53 | 54 | guard let delegate else { return } 55 | guard let frame = layerRenderer.queryNextFrame() else { return } 56 | 57 | frame.startUpdate() 58 | // Perform frame independent work 59 | frame.endUpdate() 60 | 61 | guard let timing = frame.predictTiming() else { return } 62 | LayerRenderer.Clock().wait(until: timing.optimalInputTime) 63 | guard let drawable = frame.queryDrawable() else { return } 64 | 65 | // triple buffered commandBuf -- ?? completion moved up for readability 66 | _ = inFlightSemaphore.wait(timeout: DispatchTime.distantFuture) 67 | guard let commandBuf = commandQueue.makeCommandBuffer() else { fatalError("renderFrame::commandBuf") } 68 | let semaphore = inFlightSemaphore 69 | commandBuf.addCompletedHandler { (_ commandBuf)-> Swift.Void in 70 | semaphore.signal() 71 | } 72 | 73 | frame.startSubmission() 74 | 75 | let time = LayerRenderer.Clock.Instant.epoch.duration(to: drawable.frameTiming.presentationTime).timeInterval 76 | 77 | drawable.deviceAnchor = worldTracking.queryDeviceAnchor(atTimestamp: time) 78 | 79 | delegate.updateUniforms(drawable) 80 | delegate.drawAndPresent(commandBuf, frame, drawable) 81 | 82 | frame.endSubmission() 83 | 84 | 85 | } 86 | 87 | func startRenderLoop() { 88 | Task { 89 | do { 90 | try await arSession.run([worldTracking]) 91 | } catch { 92 | fatalError("Failed to initialize ARSession") 93 | } 94 | 95 | let renderThread = Thread { 96 | self.renderLoop() 97 | } 98 | renderThread.name = "RenderThread" 99 | renderThread.start() 100 | } 101 | } 102 | 103 | func renderLoop() { 104 | while true { 105 | switch layerRenderer.state { 106 | case .paused: layerRenderer.waitUntilRunning() 107 | case .running: autoreleasepool { renderFrame() } 108 | case .invalidated: break 109 | @unknown default: print("⁉️ Renderer::runLoop @unknown default") 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/RendererProtocol.swift: -------------------------------------------------------------------------------- 1 | // created by musesum. 2 | 3 | import Metal 4 | import CompositorServices 5 | 6 | public protocol RendererProtocol { 7 | 8 | func makeResources() 9 | 10 | func makePipeline(_ layoutRenderer: LayerRenderer) 11 | 12 | func updateUniforms(_ drawable: LayerRenderer.Drawable) 13 | 14 | func drawAndPresent(_ commandBuf: MTLCommandBuffer, 15 | _ frame: LayerRenderer.Frame, 16 | _ drawable: LayerRenderer.Drawable) 17 | } 18 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/SpatialRenderer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // created by musesum. 3 | 4 | import Metal 5 | import MetalKit 6 | import ARKit 7 | import Spatial 8 | import CompositorServices 9 | 10 | /// This is the example specific part of rendering metal within VisionOS. 11 | /// The example uses earth in the foreground and stars in the background. 12 | class SpatialRenderer: Renderer { 13 | 14 | var starsPipe: MTLRenderPipelineState? 15 | var earthPipe: MTLRenderPipelineState? 16 | var earthMesh: MeshEllipsoid? 17 | var starsMesh: MeshEllipsoid? 18 | var starsEyeBuf: UniformEyeBuf? 19 | var earthEyeBuf: UniformEyeBuf? 20 | 21 | override init(_ layerRenderer: LayerRenderer) { 22 | super.init(layerRenderer) 23 | setDelegate(self) 24 | startRenderLoop() 25 | } 26 | } 27 | 28 | extension SpatialRenderer: RendererProtocol { 29 | 30 | func makeResources() { 31 | // stars is from 8k_stars_milky_way.jpg via 32 | // https://www.solarsystemscope.com/textures/ -- CC Atribution 4.0 33 | starsEyeBuf = UniformEyeBuf(device, "stars", infinitelyFar: true) 34 | earthEyeBuf = UniformEyeBuf(device, "earth", infinitelyFar: false) 35 | do { 36 | try earthMesh = MeshEllipsoid(device, "Earth", .less, radius: 2.5, inward: false) 37 | try starsMesh = MeshEllipsoid(device, "Stars", .greater, radius: 3.0, inward: true) 38 | } catch { 39 | fatalError("\(#function) Error: \(error)") 40 | } 41 | } 42 | func makePipeline(_ layoutRenderer: LayerRenderer) { 43 | guard let library = device.makeDefaultLibrary() else { return err("library = nil")} 44 | guard let earthMesh else { return err("earthMesh")} 45 | guard let starsMesh else { return err("starsMesh")} 46 | do { 47 | let configuration = layerRenderer.configuration 48 | let pd = MTLRenderPipelineDescriptor() 49 | pd.colorAttachments[0].pixelFormat = configuration.colorFormat 50 | pd.depthAttachmentPixelFormat = configuration.depthFormat 51 | 52 | // earth.metal 53 | pd.vertexFunction = library.makeFunction(name: "vertexEarth") 54 | pd.fragmentFunction = library.makeFunction(name: "fragmentEarth") 55 | pd.vertexDescriptor = earthMesh.metalVD 56 | earthPipe = try device.makeRenderPipelineState(descriptor: pd) 57 | 58 | // stars.metal 59 | pd.vertexFunction = library.makeFunction(name: "vertexStars") 60 | pd.fragmentFunction = library.makeFunction(name: "fragmentStars") 61 | pd.vertexDescriptor = starsMesh.metalVD 62 | starsPipe = try device.makeRenderPipelineState(descriptor: pd) 63 | 64 | } catch let error { 65 | err("compile \(error.localizedDescription)") 66 | } 67 | 68 | func err(_ msg: String) { 69 | print("⁉️ SpatialRenderer::\(#function) error: \(msg)") 70 | } 71 | } 72 | 73 | /// Update projection and rotation 74 | func updateUniforms(_ drawable: LayerRenderer.Drawable) { 75 | 76 | let rotationAxis = SIMD3(0, 1, 0) 77 | let rotationEarth = rotateQuat(radians: rotation, 78 | axis: rotationAxis) 79 | 80 | let rotationStars = rotateQuat(radians: 0, 81 | axis: rotationAxis) 82 | rotation += 0.003 83 | 84 | starsEyeBuf?.updateUniforms(drawable, rotationStars) 85 | earthEyeBuf?.updateUniforms(drawable, rotationEarth) 86 | } 87 | 88 | func drawAndPresent(_ commandBuf: MTLCommandBuffer, 89 | _ frame: LayerRenderer.Frame, 90 | _ drawable: LayerRenderer.Drawable) { 91 | 92 | let renderPass = makeRenderPass(drawable: drawable) 93 | 94 | guard let starsMesh, let starsPipe, let starsEyeBuf, 95 | let earthMesh, let earthPipe, let earthEyeBuf, 96 | let renderCommand = commandBuf .makeRenderCommandEncoder( 97 | descriptor: renderPass) else { fatalError(#function) } 98 | 99 | renderCommand.label = "Spatial" 100 | renderCommand.pushDebugGroup("Spatial") 101 | 102 | let viewports = drawable.views.map { $0.textureMap.viewport } 103 | renderCommand.setViewports(viewports) 104 | 105 | starsEyeBuf.setMappings(drawable, viewports, renderCommand) 106 | starsMesh.draw(renderCommand, starsPipe, .clockwise) 107 | 108 | earthEyeBuf.setMappings(drawable, viewports, renderCommand) 109 | earthMesh.draw(renderCommand, earthPipe, .counterClockwise) 110 | 111 | renderCommand.popDebugGroup() 112 | renderCommand.endEncoding() 113 | drawable.encodePresent(commandBuffer: commandBuf) 114 | commandBuf.commit() 115 | } 116 | 117 | } 118 | 119 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/UniformEyeBuf.swift: -------------------------------------------------------------------------------- 1 | // created by musesum. 2 | 3 | import Spatial 4 | import CompositorServices 5 | 6 | // round up to multiple of 256 bytes 7 | let uniformEyesSize = (MemoryLayout.size + 0xFF) & -0x100 8 | 9 | // uniforms for 3 adjacent frames 10 | let tripleBufferCount = 3 11 | 12 | // size of 3 uniforms in shared contiguous memory 13 | let tripleUniformSize = uniformEyesSize * tripleBufferCount 14 | 15 | /// triple buffered Uniform for either 1 or 2 eyes 16 | class UniformEyeBuf { 17 | 18 | var uniformBuf: MTLBuffer 19 | var tripleUniformOffset = 0 20 | var tripleUniformIndex = 0 21 | var uniformEyes: UnsafeMutablePointer 22 | var infinitelyFar: Bool // infinit distance for stars (same background for both eyes) 23 | 24 | init(_ device: MTLDevice, 25 | _ label: String, 26 | infinitelyFar: Bool) { 27 | 28 | self.infinitelyFar = infinitelyFar 29 | 30 | self.uniformBuf = device.makeBuffer(length: tripleUniformSize, 31 | options: [.storageModeShared])! 32 | self.uniformBuf.label = label 33 | 34 | uniformEyes = UnsafeMutableRawPointer(uniformBuf.contents()) 35 | .bindMemory(to: UniformEyes.self, capacity: 1) 36 | } 37 | 38 | /// Update projection and rotation 39 | func updateUniforms(_ drawable: LayerRenderer.Drawable, 40 | _ rotationMat: simd_float4x4) { 41 | 42 | let anchor = drawable.deviceAnchor 43 | updateTripleBufferedUniform() 44 | 45 | let translateMat = translateQuat(x: 0.0, y: 0.0, z: -8.0) 46 | let modelMatrix = translateMat * rotationMat 47 | let simdDeviceAnchor = anchor?.originFromAnchorTransform ?? matrix_identity_float4x4 48 | 49 | self.uniformEyes[0].eye.0 = uniformForEyeIndex(0) 50 | if drawable.views.count > 1 { 51 | self.uniformEyes[0].eye.1 = uniformForEyeIndex(1) 52 | } 53 | 54 | func updateTripleBufferedUniform() { 55 | 56 | tripleUniformIndex = (tripleUniformIndex + 1) % tripleBufferCount 57 | tripleUniformOffset = uniformEyesSize * tripleUniformIndex 58 | let uniformPtr = uniformBuf.contents() + tripleUniformOffset 59 | uniformEyes = UnsafeMutableRawPointer(uniformPtr) 60 | .bindMemory(to: UniformEyes.self, capacity: 1) 61 | } 62 | 63 | func uniformForEyeIndex(_ index: Int) -> Uniforms { 64 | 65 | let view = drawable.views[index] 66 | let viewMatrix = (simdDeviceAnchor * view.transform).inverse 67 | let projection = ProjectiveTransform3D( 68 | leftTangent : Double(view.tangents[0]), 69 | rightTangent : Double(view.tangents[1]), 70 | topTangent : Double(view.tangents[2]), 71 | bottomTangent : Double(view.tangents[3]), 72 | nearZ : Double(drawable.depthRange.y), 73 | farZ : Double(drawable.depthRange.x), 74 | reverseZ : true) 75 | 76 | var viewMat = viewMatrix * modelMatrix 77 | if infinitelyFar { 78 | viewMat.columns.3 = simd_make_float4(0.0, 0.0, 0.0, 1.0) 79 | } 80 | return Uniforms(projectionMat: .init(projection), 81 | viewMat: viewMat) 82 | } 83 | } 84 | func setMappings(_ drawable: LayerRenderer.Drawable, 85 | _ viewports: [MTLViewport], 86 | _ renderCommand: MTLRenderCommandEncoder) { 87 | 88 | if drawable.views.count > 1 { 89 | var viewMappings = (0 ..< drawable.views.count).map { 90 | MTLVertexAmplificationViewMapping( 91 | viewportArrayIndexOffset: UInt32($0), 92 | renderTargetArrayIndexOffset: UInt32($0)) 93 | } 94 | renderCommand.setVertexAmplificationCount( 95 | viewports.count, 96 | viewMappings: &viewMappings) 97 | } 98 | renderCommand.setVertexBuffer(uniformBuf, 99 | offset: tripleUniformOffset, 100 | index: Bufi.uniformEyei) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/Utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // created by musesum. 3 | 4 | import MetalKit 5 | import simd 6 | 7 | func loadTexture(_ device: MTLDevice, 8 | _ textureName: String) -> MTLTexture { 9 | /// Load texture data with optimal parameters for sampling 10 | 11 | do { 12 | let textureLoader = MTKTextureLoader(device: device) 13 | 14 | let textureLoaderOptions = [ 15 | MTKTextureLoader.Option.textureUsage: NSNumber(value: MTLTextureUsage.shaderRead.rawValue), 16 | MTKTextureLoader.Option.textureStorageMode: NSNumber(value: MTLStorageMode.`private`.rawValue) 17 | ] 18 | 19 | return try textureLoader.newTexture(name: textureName, 20 | scaleFactor: 1.0, 21 | bundle: nil, 22 | options: textureLoaderOptions) 23 | } catch { 24 | fatalError("\(#function) Error: \(error)") 25 | } 26 | } 27 | 28 | 29 | // Generic matrix math utility functions 30 | func rotateQuat(radians: Float, axis: SIMD3) -> matrix_float4x4 { 31 | 32 | let unitAxis = normalize(axis) 33 | let ct = cosf(radians) 34 | let st = sinf(radians) 35 | let ci = 1 - ct 36 | let x = unitAxis.x, y = unitAxis.y, z = unitAxis.z 37 | let col0 = vector_float4(x*x*ci + ct , y*x*ci + z*st, z*x*ci - y*st, 0) 38 | let col1 = vector_float4(x*y*ci - z*st, y*y*ci + ct, z*y*ci + x*st, 0) 39 | let col2 = vector_float4(x*z*ci + y*st, y*z*ci - x*st, z*z*ci + ct , 0) 40 | let col3 = vector_float4( 0, 0, 0, 1) 41 | return matrix_float4x4.init(columns:(col0,col1,col2,col3)) 42 | } 43 | 44 | func translateQuat(x: Float, y: Float, z: Float) -> matrix_float4x4 { 45 | 46 | return matrix_float4x4.init( 47 | columns:(vector_float4(1, 0, 0, 0), 48 | vector_float4(0, 1, 0, 0), 49 | vector_float4(0, 0, 1, 0), 50 | vector_float4(x, y, z, 1))) 51 | } 52 | 53 | func radians_from_degrees(_ degrees: Float) -> Float { 54 | return (degrees / 180) * .pi 55 | } 56 | 57 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/extensions.swift: -------------------------------------------------------------------------------- 1 | // extensions.swift 2 | // FullyImmersiveMetal 3 | // 4 | // Created by musesum on 8/8/23. 5 | 6 | import CompositorServices 7 | 8 | extension LayerRenderer.Clock.Instant { 9 | func toTimeInterval() -> TimeInterval { 10 | let duration = LayerRenderer.Clock.Instant.epoch.duration(to: self) 11 | let secondsPart = Double(duration.components.seconds) 12 | let attosecondsPart = Double(duration.components.attoseconds) / 1e18 13 | return secondsPart + attosecondsPart 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SpatialMetal/SpatialMetal/studio.hdr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/musesum/SpatialMetal/347bf8317f87fe38820b15c8b3a1972eeb872832/SpatialMetal/SpatialMetal/studio.hdr --------------------------------------------------------------------------------