├── .gitignore ├── LICENSE ├── README.md ├── SwiftShaders.png ├── SwiftShaders.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── SwiftShaders.xcscheme ├── SwiftShaders ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── customTexture.imageset │ │ ├── Contents.json │ │ └── texture.png │ ├── diffuse.imageset │ │ ├── Contents.json │ │ └── diffuse.jpg │ ├── noiseTexture.imageset │ │ ├── Contents.json │ │ └── bbHK0.jpg │ └── normal.imageset │ │ ├── 1182OS_04_06.jpg │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── GLSL │ ├── GLSL_Notes.txt │ └── GLSL_Shaders.swift ├── Info.plist ├── Metal │ ├── Cloud.metal │ ├── Color.metal │ ├── GaussianBlur.metal │ ├── MetalNotes.txt │ ├── Pixelate.metal │ ├── TextureBrightness.metal │ ├── TextureSampler.metal │ ├── ThickRedLine.metal │ └── Triangles.metal ├── UI │ ├── GameViewController.swift │ ├── SCNGeometry+Line.swift │ ├── SCNNode+Effects.swift │ └── SwiftShadersScene.swift ├── art.scnassets │ ├── sharpNoise.png │ ├── ship.scn │ └── softNoise.png └── pixelate.plist ├── SwiftShadersTests ├── Info.plist └── SwiftShadersTests.swift └── SwiftShadersUITests ├── Info.plist └── SwiftShadersUITests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Malik Alayli 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftShaders 2 | 3 | SwiftShaders presents Shaders in Swift on iOS with GLSL, Metal and SceneKit frameworks. 4 | 5 | ![Platform](https://img.shields.io/badge/platform-ios-black.svg) 6 | ![Compatibility](https://img.shields.io/badge/iOS-+13.0-orange.svg) 7 | ![Compatibility](https://img.shields.io/badge/Swift-5.0-orange.svg) 8 | ![License](https://img.shields.io/badge/License-MIT-lightgrey.svg) 9 |

10 | ![Swift Shaders](SwiftShaders.png) 11 | -------------------------------------------------------------------------------- /SwiftShaders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders.png -------------------------------------------------------------------------------- /SwiftShaders.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1F2209E4235425A700DAF980 /* TextureSampler.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209DC235425A700DAF980 /* TextureSampler.metal */; }; 11 | 1F2209E5235425A700DAF980 /* ThickRedLine.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209DD235425A700DAF980 /* ThickRedLine.metal */; }; 12 | 1F2209E6235425A700DAF980 /* Color.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209DE235425A700DAF980 /* Color.metal */; }; 13 | 1F2209E7235425A700DAF980 /* Triangles.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209DF235425A700DAF980 /* Triangles.metal */; }; 14 | 1F2209E9235425A700DAF980 /* GLSL_Shaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209E2235425A700DAF980 /* GLSL_Shaders.swift */; }; 15 | 1F2209EC235425D900DAF980 /* Cloud.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209EA235425D900DAF980 /* Cloud.metal */; }; 16 | 1F2209ED235425D900DAF980 /* Pixelate.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209EB235425D900DAF980 /* Pixelate.metal */; }; 17 | 1F2209F12354262500DAF980 /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209EF2354262500DAF980 /* GameViewController.swift */; }; 18 | 1F2209F22354262500DAF980 /* SwiftShadersScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209F02354262500DAF980 /* SwiftShadersScene.swift */; }; 19 | 1F2209F4235428FD00DAF980 /* TextureBrightness.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209F3235428FD00DAF980 /* TextureBrightness.metal */; }; 20 | 1F2209F623542C9700DAF980 /* SCNGeometry+Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209F523542C9700DAF980 /* SCNGeometry+Line.swift */; }; 21 | 1F2209F823542CBD00DAF980 /* SCNNode+Effects.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209F723542CBD00DAF980 /* SCNNode+Effects.swift */; }; 22 | 1F2209FA23547E1400DAF980 /* GaussianBlur.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1F2209F923547E1400DAF980 /* GaussianBlur.metal */; }; 23 | 1FE5FD69234997D1009DF72F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE5FD68234997D1009DF72F /* AppDelegate.swift */; }; 24 | 1FE5FD6B234997D1009DF72F /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 1FE5FD6A234997D1009DF72F /* art.scnassets */; }; 25 | 1FE5FD70234997D1009DF72F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1FE5FD6E234997D1009DF72F /* Main.storyboard */; }; 26 | 1FE5FD72234997D2009DF72F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1FE5FD71234997D2009DF72F /* Assets.xcassets */; }; 27 | 1FE5FD75234997D2009DF72F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1FE5FD73234997D2009DF72F /* LaunchScreen.storyboard */; }; 28 | 1FE5FD80234997D2009DF72F /* SwiftShadersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE5FD7F234997D2009DF72F /* SwiftShadersTests.swift */; }; 29 | 1FE5FD8B234997D2009DF72F /* SwiftShadersUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FE5FD8A234997D2009DF72F /* SwiftShadersUITests.swift */; }; 30 | 3A4B2C64235573F400ED6939 /* MetalNotes.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3A4B2C63235573F400ED6939 /* MetalNotes.txt */; }; 31 | 3A562579235578D700848C7D /* GLSL_Notes.txt in Resources */ = {isa = PBXBuildFile; fileRef = 3A562578235578D700848C7D /* GLSL_Notes.txt */; }; 32 | 3A766273234ECF0A009649F8 /* pixelate.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3A766272234ECF0A009649F8 /* pixelate.plist */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXContainerItemProxy section */ 36 | 1FE5FD7C234997D2009DF72F /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 1FE5FD5D234997D1009DF72F /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 1FE5FD64234997D1009DF72F; 41 | remoteInfo = SwiftShaders; 42 | }; 43 | 1FE5FD87234997D2009DF72F /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 1FE5FD5D234997D1009DF72F /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = 1FE5FD64234997D1009DF72F; 48 | remoteInfo = SwiftShaders; 49 | }; 50 | /* End PBXContainerItemProxy section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 1F2209DC235425A700DAF980 /* TextureSampler.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = TextureSampler.metal; sourceTree = ""; }; 54 | 1F2209DD235425A700DAF980 /* ThickRedLine.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = ThickRedLine.metal; sourceTree = ""; }; 55 | 1F2209DE235425A700DAF980 /* Color.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = Color.metal; sourceTree = ""; }; 56 | 1F2209DF235425A700DAF980 /* Triangles.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = Triangles.metal; sourceTree = ""; }; 57 | 1F2209E2235425A700DAF980 /* GLSL_Shaders.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GLSL_Shaders.swift; sourceTree = ""; }; 58 | 1F2209EA235425D900DAF980 /* Cloud.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = Cloud.metal; sourceTree = ""; }; 59 | 1F2209EB235425D900DAF980 /* Pixelate.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = Pixelate.metal; sourceTree = ""; }; 60 | 1F2209EF2354262500DAF980 /* GameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 61 | 1F2209F02354262500DAF980 /* SwiftShadersScene.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftShadersScene.swift; sourceTree = ""; }; 62 | 1F2209F3235428FD00DAF980 /* TextureBrightness.metal */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.metal; path = TextureBrightness.metal; sourceTree = ""; }; 63 | 1F2209F523542C9700DAF980 /* SCNGeometry+Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SCNGeometry+Line.swift"; sourceTree = ""; }; 64 | 1F2209F723542CBD00DAF980 /* SCNNode+Effects.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SCNNode+Effects.swift"; sourceTree = ""; }; 65 | 1F2209F923547E1400DAF980 /* GaussianBlur.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = GaussianBlur.metal; sourceTree = ""; }; 66 | 1FE5FD65234997D1009DF72F /* SwiftShaders.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftShaders.app; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 1FE5FD68234997D1009DF72F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 68 | 1FE5FD6A234997D1009DF72F /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = ""; }; 69 | 1FE5FD6F234997D1009DF72F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 70 | 1FE5FD71234997D2009DF72F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | 1FE5FD74234997D2009DF72F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 72 | 1FE5FD76234997D2009DF72F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 1FE5FD7B234997D2009DF72F /* SwiftShadersTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftShadersTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 1FE5FD7F234997D2009DF72F /* SwiftShadersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftShadersTests.swift; sourceTree = ""; }; 75 | 1FE5FD81234997D2009DF72F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 1FE5FD86234997D2009DF72F /* SwiftShadersUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftShadersUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | 1FE5FD8A234997D2009DF72F /* SwiftShadersUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftShadersUITests.swift; sourceTree = ""; }; 78 | 1FE5FD8C234997D2009DF72F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 79 | 3A4B2C63235573F400ED6939 /* MetalNotes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = MetalNotes.txt; sourceTree = ""; }; 80 | 3A562578235578D700848C7D /* GLSL_Notes.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GLSL_Notes.txt; sourceTree = ""; }; 81 | 3A766272234ECF0A009649F8 /* pixelate.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = pixelate.plist; sourceTree = ""; }; 82 | /* End PBXFileReference section */ 83 | 84 | /* Begin PBXFrameworksBuildPhase section */ 85 | 1FE5FD62234997D1009DF72F /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | 1FE5FD78234997D2009DF72F /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 1FE5FD83234997D2009DF72F /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | 1F2209DA235425A700DAF980 /* Metal */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 1F2209EA235425D900DAF980 /* Cloud.metal */, 113 | 1F2209DE235425A700DAF980 /* Color.metal */, 114 | 1F2209F923547E1400DAF980 /* GaussianBlur.metal */, 115 | 3A4B2C63235573F400ED6939 /* MetalNotes.txt */, 116 | 1F2209EB235425D900DAF980 /* Pixelate.metal */, 117 | 1F2209F3235428FD00DAF980 /* TextureBrightness.metal */, 118 | 1F2209DC235425A700DAF980 /* TextureSampler.metal */, 119 | 1F2209DD235425A700DAF980 /* ThickRedLine.metal */, 120 | 1F2209DF235425A700DAF980 /* Triangles.metal */, 121 | ); 122 | path = Metal; 123 | sourceTree = ""; 124 | }; 125 | 1F2209E1235425A700DAF980 /* GLSL */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 3A562578235578D700848C7D /* GLSL_Notes.txt */, 129 | 1F2209E2235425A700DAF980 /* GLSL_Shaders.swift */, 130 | ); 131 | path = GLSL; 132 | sourceTree = ""; 133 | }; 134 | 1F2209EE2354262500DAF980 /* UI */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 1F2209EF2354262500DAF980 /* GameViewController.swift */, 138 | 1F2209F523542C9700DAF980 /* SCNGeometry+Line.swift */, 139 | 1F2209F723542CBD00DAF980 /* SCNNode+Effects.swift */, 140 | 1F2209F02354262500DAF980 /* SwiftShadersScene.swift */, 141 | ); 142 | path = UI; 143 | sourceTree = ""; 144 | }; 145 | 1FE5FD5C234997D1009DF72F = { 146 | isa = PBXGroup; 147 | children = ( 148 | 1FE5FD67234997D1009DF72F /* SwiftShaders */, 149 | 1FE5FD7E234997D2009DF72F /* SwiftShadersTests */, 150 | 1FE5FD89234997D2009DF72F /* SwiftShadersUITests */, 151 | 1FE5FD66234997D1009DF72F /* Products */, 152 | ); 153 | sourceTree = ""; 154 | }; 155 | 1FE5FD66234997D1009DF72F /* Products */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | 1FE5FD65234997D1009DF72F /* SwiftShaders.app */, 159 | 1FE5FD7B234997D2009DF72F /* SwiftShadersTests.xctest */, 160 | 1FE5FD86234997D2009DF72F /* SwiftShadersUITests.xctest */, 161 | ); 162 | name = Products; 163 | sourceTree = ""; 164 | }; 165 | 1FE5FD67234997D1009DF72F /* SwiftShaders */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 1FE5FD68234997D1009DF72F /* AppDelegate.swift */, 169 | 1FE5FD6A234997D1009DF72F /* art.scnassets */, 170 | 1FE5FD71234997D2009DF72F /* Assets.xcassets */, 171 | 1F2209E1235425A700DAF980 /* GLSL */, 172 | 1FE5FD76234997D2009DF72F /* Info.plist */, 173 | 1FE5FD73234997D2009DF72F /* LaunchScreen.storyboard */, 174 | 1FE5FD6E234997D1009DF72F /* Main.storyboard */, 175 | 1F2209DA235425A700DAF980 /* Metal */, 176 | 3A766272234ECF0A009649F8 /* pixelate.plist */, 177 | 1F2209EE2354262500DAF980 /* UI */, 178 | ); 179 | path = SwiftShaders; 180 | sourceTree = ""; 181 | }; 182 | 1FE5FD7E234997D2009DF72F /* SwiftShadersTests */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 1FE5FD7F234997D2009DF72F /* SwiftShadersTests.swift */, 186 | 1FE5FD81234997D2009DF72F /* Info.plist */, 187 | ); 188 | path = SwiftShadersTests; 189 | sourceTree = ""; 190 | }; 191 | 1FE5FD89234997D2009DF72F /* SwiftShadersUITests */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 1FE5FD8A234997D2009DF72F /* SwiftShadersUITests.swift */, 195 | 1FE5FD8C234997D2009DF72F /* Info.plist */, 196 | ); 197 | path = SwiftShadersUITests; 198 | sourceTree = ""; 199 | }; 200 | /* End PBXGroup section */ 201 | 202 | /* Begin PBXNativeTarget section */ 203 | 1FE5FD64234997D1009DF72F /* SwiftShaders */ = { 204 | isa = PBXNativeTarget; 205 | buildConfigurationList = 1FE5FD8F234997D2009DF72F /* Build configuration list for PBXNativeTarget "SwiftShaders" */; 206 | buildPhases = ( 207 | 1FE5FD61234997D1009DF72F /* Sources */, 208 | 1FE5FD62234997D1009DF72F /* Frameworks */, 209 | 1FE5FD63234997D1009DF72F /* Resources */, 210 | ); 211 | buildRules = ( 212 | ); 213 | dependencies = ( 214 | ); 215 | name = SwiftShaders; 216 | productName = SwiftShaders; 217 | productReference = 1FE5FD65234997D1009DF72F /* SwiftShaders.app */; 218 | productType = "com.apple.product-type.application"; 219 | }; 220 | 1FE5FD7A234997D2009DF72F /* SwiftShadersTests */ = { 221 | isa = PBXNativeTarget; 222 | buildConfigurationList = 1FE5FD92234997D2009DF72F /* Build configuration list for PBXNativeTarget "SwiftShadersTests" */; 223 | buildPhases = ( 224 | 1FE5FD77234997D2009DF72F /* Sources */, 225 | 1FE5FD78234997D2009DF72F /* Frameworks */, 226 | 1FE5FD79234997D2009DF72F /* Resources */, 227 | ); 228 | buildRules = ( 229 | ); 230 | dependencies = ( 231 | 1FE5FD7D234997D2009DF72F /* PBXTargetDependency */, 232 | ); 233 | name = SwiftShadersTests; 234 | productName = SwiftShadersTests; 235 | productReference = 1FE5FD7B234997D2009DF72F /* SwiftShadersTests.xctest */; 236 | productType = "com.apple.product-type.bundle.unit-test"; 237 | }; 238 | 1FE5FD85234997D2009DF72F /* SwiftShadersUITests */ = { 239 | isa = PBXNativeTarget; 240 | buildConfigurationList = 1FE5FD95234997D2009DF72F /* Build configuration list for PBXNativeTarget "SwiftShadersUITests" */; 241 | buildPhases = ( 242 | 1FE5FD82234997D2009DF72F /* Sources */, 243 | 1FE5FD83234997D2009DF72F /* Frameworks */, 244 | 1FE5FD84234997D2009DF72F /* Resources */, 245 | ); 246 | buildRules = ( 247 | ); 248 | dependencies = ( 249 | 1FE5FD88234997D2009DF72F /* PBXTargetDependency */, 250 | ); 251 | name = SwiftShadersUITests; 252 | productName = SwiftShadersUITests; 253 | productReference = 1FE5FD86234997D2009DF72F /* SwiftShadersUITests.xctest */; 254 | productType = "com.apple.product-type.bundle.ui-testing"; 255 | }; 256 | /* End PBXNativeTarget section */ 257 | 258 | /* Begin PBXProject section */ 259 | 1FE5FD5D234997D1009DF72F /* Project object */ = { 260 | isa = PBXProject; 261 | attributes = { 262 | LastSwiftUpdateCheck = 1100; 263 | LastUpgradeCheck = 1100; 264 | ORGANIZATIONNAME = MalikAlayli; 265 | TargetAttributes = { 266 | 1FE5FD64234997D1009DF72F = { 267 | CreatedOnToolsVersion = 11.0; 268 | }; 269 | 1FE5FD7A234997D2009DF72F = { 270 | CreatedOnToolsVersion = 11.0; 271 | TestTargetID = 1FE5FD64234997D1009DF72F; 272 | }; 273 | 1FE5FD85234997D2009DF72F = { 274 | CreatedOnToolsVersion = 11.0; 275 | TestTargetID = 1FE5FD64234997D1009DF72F; 276 | }; 277 | }; 278 | }; 279 | buildConfigurationList = 1FE5FD60234997D1009DF72F /* Build configuration list for PBXProject "SwiftShaders" */; 280 | compatibilityVersion = "Xcode 9.3"; 281 | developmentRegion = en; 282 | hasScannedForEncodings = 0; 283 | knownRegions = ( 284 | en, 285 | Base, 286 | ); 287 | mainGroup = 1FE5FD5C234997D1009DF72F; 288 | productRefGroup = 1FE5FD66234997D1009DF72F /* Products */; 289 | projectDirPath = ""; 290 | projectRoot = ""; 291 | targets = ( 292 | 1FE5FD64234997D1009DF72F /* SwiftShaders */, 293 | 1FE5FD7A234997D2009DF72F /* SwiftShadersTests */, 294 | 1FE5FD85234997D2009DF72F /* SwiftShadersUITests */, 295 | ); 296 | }; 297 | /* End PBXProject section */ 298 | 299 | /* Begin PBXResourcesBuildPhase section */ 300 | 1FE5FD63234997D1009DF72F /* Resources */ = { 301 | isa = PBXResourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | 1FE5FD6B234997D1009DF72F /* art.scnassets in Resources */, 305 | 1FE5FD75234997D2009DF72F /* LaunchScreen.storyboard in Resources */, 306 | 1FE5FD72234997D2009DF72F /* Assets.xcassets in Resources */, 307 | 3A766273234ECF0A009649F8 /* pixelate.plist in Resources */, 308 | 3A562579235578D700848C7D /* GLSL_Notes.txt in Resources */, 309 | 3A4B2C64235573F400ED6939 /* MetalNotes.txt in Resources */, 310 | 1FE5FD70234997D1009DF72F /* Main.storyboard in Resources */, 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | }; 314 | 1FE5FD79234997D2009DF72F /* Resources */ = { 315 | isa = PBXResourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | ); 319 | runOnlyForDeploymentPostprocessing = 0; 320 | }; 321 | 1FE5FD84234997D2009DF72F /* Resources */ = { 322 | isa = PBXResourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | /* End PBXResourcesBuildPhase section */ 329 | 330 | /* Begin PBXSourcesBuildPhase section */ 331 | 1FE5FD61234997D1009DF72F /* Sources */ = { 332 | isa = PBXSourcesBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | 1F2209F623542C9700DAF980 /* SCNGeometry+Line.swift in Sources */, 336 | 1F2209E7235425A700DAF980 /* Triangles.metal in Sources */, 337 | 1F2209F823542CBD00DAF980 /* SCNNode+Effects.swift in Sources */, 338 | 1F2209E4235425A700DAF980 /* TextureSampler.metal in Sources */, 339 | 1F2209EC235425D900DAF980 /* Cloud.metal in Sources */, 340 | 1F2209E6235425A700DAF980 /* Color.metal in Sources */, 341 | 1F2209FA23547E1400DAF980 /* GaussianBlur.metal in Sources */, 342 | 1F2209F12354262500DAF980 /* GameViewController.swift in Sources */, 343 | 1F2209F4235428FD00DAF980 /* TextureBrightness.metal in Sources */, 344 | 1F2209E9235425A700DAF980 /* GLSL_Shaders.swift in Sources */, 345 | 1FE5FD69234997D1009DF72F /* AppDelegate.swift in Sources */, 346 | 1F2209E5235425A700DAF980 /* ThickRedLine.metal in Sources */, 347 | 1F2209ED235425D900DAF980 /* Pixelate.metal in Sources */, 348 | 1F2209F22354262500DAF980 /* SwiftShadersScene.swift in Sources */, 349 | ); 350 | runOnlyForDeploymentPostprocessing = 0; 351 | }; 352 | 1FE5FD77234997D2009DF72F /* Sources */ = { 353 | isa = PBXSourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 1FE5FD80234997D2009DF72F /* SwiftShadersTests.swift in Sources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | 1FE5FD82234997D2009DF72F /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 1FE5FD8B234997D2009DF72F /* SwiftShadersUITests.swift in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | /* End PBXSourcesBuildPhase section */ 369 | 370 | /* Begin PBXTargetDependency section */ 371 | 1FE5FD7D234997D2009DF72F /* PBXTargetDependency */ = { 372 | isa = PBXTargetDependency; 373 | target = 1FE5FD64234997D1009DF72F /* SwiftShaders */; 374 | targetProxy = 1FE5FD7C234997D2009DF72F /* PBXContainerItemProxy */; 375 | }; 376 | 1FE5FD88234997D2009DF72F /* PBXTargetDependency */ = { 377 | isa = PBXTargetDependency; 378 | target = 1FE5FD64234997D1009DF72F /* SwiftShaders */; 379 | targetProxy = 1FE5FD87234997D2009DF72F /* PBXContainerItemProxy */; 380 | }; 381 | /* End PBXTargetDependency section */ 382 | 383 | /* Begin PBXVariantGroup section */ 384 | 1FE5FD6E234997D1009DF72F /* Main.storyboard */ = { 385 | isa = PBXVariantGroup; 386 | children = ( 387 | 1FE5FD6F234997D1009DF72F /* Base */, 388 | ); 389 | name = Main.storyboard; 390 | sourceTree = ""; 391 | }; 392 | 1FE5FD73234997D2009DF72F /* LaunchScreen.storyboard */ = { 393 | isa = PBXVariantGroup; 394 | children = ( 395 | 1FE5FD74234997D2009DF72F /* Base */, 396 | ); 397 | name = LaunchScreen.storyboard; 398 | sourceTree = ""; 399 | }; 400 | /* End PBXVariantGroup section */ 401 | 402 | /* Begin XCBuildConfiguration section */ 403 | 1FE5FD8D234997D2009DF72F /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_ANALYZER_NONNULL = YES; 408 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 409 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 410 | CLANG_CXX_LIBRARY = "libc++"; 411 | CLANG_ENABLE_MODULES = YES; 412 | CLANG_ENABLE_OBJC_ARC = YES; 413 | CLANG_ENABLE_OBJC_WEAK = YES; 414 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 415 | CLANG_WARN_BOOL_CONVERSION = YES; 416 | CLANG_WARN_COMMA = YES; 417 | CLANG_WARN_CONSTANT_CONVERSION = YES; 418 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 419 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 420 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 421 | CLANG_WARN_EMPTY_BODY = YES; 422 | CLANG_WARN_ENUM_CONVERSION = YES; 423 | CLANG_WARN_INFINITE_RECURSION = YES; 424 | CLANG_WARN_INT_CONVERSION = YES; 425 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 426 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 427 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 428 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 429 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 430 | CLANG_WARN_STRICT_PROTOTYPES = YES; 431 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 432 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 433 | CLANG_WARN_UNREACHABLE_CODE = YES; 434 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 435 | COPY_PHASE_STRIP = NO; 436 | DEBUG_INFORMATION_FORMAT = dwarf; 437 | ENABLE_STRICT_OBJC_MSGSEND = YES; 438 | ENABLE_TESTABILITY = YES; 439 | GCC_C_LANGUAGE_STANDARD = gnu11; 440 | GCC_DYNAMIC_NO_PIC = NO; 441 | GCC_NO_COMMON_BLOCKS = YES; 442 | GCC_OPTIMIZATION_LEVEL = 0; 443 | GCC_PREPROCESSOR_DEFINITIONS = ( 444 | "DEBUG=1", 445 | "$(inherited)", 446 | ); 447 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 448 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 449 | GCC_WARN_UNDECLARED_SELECTOR = YES; 450 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 451 | GCC_WARN_UNUSED_FUNCTION = YES; 452 | GCC_WARN_UNUSED_VARIABLE = YES; 453 | IPHONEOS_DEPLOYMENT_TARGET = 12.4; 454 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 455 | MTL_FAST_MATH = YES; 456 | ONLY_ACTIVE_ARCH = YES; 457 | SDKROOT = iphoneos; 458 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 459 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 460 | }; 461 | name = Debug; 462 | }; 463 | 1FE5FD8E234997D2009DF72F /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ALWAYS_SEARCH_USER_PATHS = NO; 467 | CLANG_ANALYZER_NONNULL = YES; 468 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 469 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 470 | CLANG_CXX_LIBRARY = "libc++"; 471 | CLANG_ENABLE_MODULES = YES; 472 | CLANG_ENABLE_OBJC_ARC = YES; 473 | CLANG_ENABLE_OBJC_WEAK = YES; 474 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 475 | CLANG_WARN_BOOL_CONVERSION = YES; 476 | CLANG_WARN_COMMA = YES; 477 | CLANG_WARN_CONSTANT_CONVERSION = YES; 478 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 479 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 480 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 481 | CLANG_WARN_EMPTY_BODY = YES; 482 | CLANG_WARN_ENUM_CONVERSION = YES; 483 | CLANG_WARN_INFINITE_RECURSION = YES; 484 | CLANG_WARN_INT_CONVERSION = YES; 485 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 486 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 487 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 488 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 489 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 490 | CLANG_WARN_STRICT_PROTOTYPES = YES; 491 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 492 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 493 | CLANG_WARN_UNREACHABLE_CODE = YES; 494 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 495 | COPY_PHASE_STRIP = NO; 496 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 497 | ENABLE_NS_ASSERTIONS = NO; 498 | ENABLE_STRICT_OBJC_MSGSEND = YES; 499 | GCC_C_LANGUAGE_STANDARD = gnu11; 500 | GCC_NO_COMMON_BLOCKS = YES; 501 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 502 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 503 | GCC_WARN_UNDECLARED_SELECTOR = YES; 504 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 505 | GCC_WARN_UNUSED_FUNCTION = YES; 506 | GCC_WARN_UNUSED_VARIABLE = YES; 507 | IPHONEOS_DEPLOYMENT_TARGET = 12.4; 508 | MTL_ENABLE_DEBUG_INFO = NO; 509 | MTL_FAST_MATH = YES; 510 | SDKROOT = iphoneos; 511 | SWIFT_COMPILATION_MODE = wholemodule; 512 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 513 | VALIDATE_PRODUCT = YES; 514 | }; 515 | name = Release; 516 | }; 517 | 1FE5FD90234997D2009DF72F /* Debug */ = { 518 | isa = XCBuildConfiguration; 519 | buildSettings = { 520 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 521 | CODE_SIGN_IDENTITY = "iPhone Developer"; 522 | CODE_SIGN_STYLE = Automatic; 523 | DEVELOPMENT_TEAM = 6ZQLTEG662; 524 | INFOPLIST_FILE = SwiftShaders/Info.plist; 525 | LD_RUNPATH_SEARCH_PATHS = ( 526 | "$(inherited)", 527 | "@executable_path/Frameworks", 528 | ); 529 | PRODUCT_BUNDLE_IDENTIFIER = com.malikalayli.SwiftShaders; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | PROVISIONING_PROFILE_SPECIFIER = ""; 532 | SWIFT_VERSION = 5.0; 533 | TARGETED_DEVICE_FAMILY = "1,2"; 534 | }; 535 | name = Debug; 536 | }; 537 | 1FE5FD91234997D2009DF72F /* Release */ = { 538 | isa = XCBuildConfiguration; 539 | buildSettings = { 540 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 541 | CODE_SIGN_IDENTITY = "iPhone Developer"; 542 | CODE_SIGN_STYLE = Automatic; 543 | DEVELOPMENT_TEAM = 6ZQLTEG662; 544 | INFOPLIST_FILE = SwiftShaders/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = ( 546 | "$(inherited)", 547 | "@executable_path/Frameworks", 548 | ); 549 | PRODUCT_BUNDLE_IDENTIFIER = com.malikalayli.SwiftShaders; 550 | PRODUCT_NAME = "$(TARGET_NAME)"; 551 | PROVISIONING_PROFILE_SPECIFIER = ""; 552 | SWIFT_VERSION = 5.0; 553 | TARGETED_DEVICE_FAMILY = "1,2"; 554 | }; 555 | name = Release; 556 | }; 557 | 1FE5FD93234997D2009DF72F /* Debug */ = { 558 | isa = XCBuildConfiguration; 559 | buildSettings = { 560 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 561 | BUNDLE_LOADER = "$(TEST_HOST)"; 562 | CODE_SIGN_STYLE = Automatic; 563 | DEVELOPMENT_TEAM = 6ZQLTEG662; 564 | INFOPLIST_FILE = SwiftShadersTests/Info.plist; 565 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 566 | LD_RUNPATH_SEARCH_PATHS = ( 567 | "$(inherited)", 568 | "@executable_path/Frameworks", 569 | "@loader_path/Frameworks", 570 | ); 571 | PRODUCT_BUNDLE_IDENTIFIER = com.malikalayli.SwiftShadersTests; 572 | PRODUCT_NAME = "$(TARGET_NAME)"; 573 | SWIFT_VERSION = 5.0; 574 | TARGETED_DEVICE_FAMILY = "1,2"; 575 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftShaders.app/SwiftShaders"; 576 | }; 577 | name = Debug; 578 | }; 579 | 1FE5FD94234997D2009DF72F /* Release */ = { 580 | isa = XCBuildConfiguration; 581 | buildSettings = { 582 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 583 | BUNDLE_LOADER = "$(TEST_HOST)"; 584 | CODE_SIGN_STYLE = Automatic; 585 | DEVELOPMENT_TEAM = 6ZQLTEG662; 586 | INFOPLIST_FILE = SwiftShadersTests/Info.plist; 587 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 588 | LD_RUNPATH_SEARCH_PATHS = ( 589 | "$(inherited)", 590 | "@executable_path/Frameworks", 591 | "@loader_path/Frameworks", 592 | ); 593 | PRODUCT_BUNDLE_IDENTIFIER = com.malikalayli.SwiftShadersTests; 594 | PRODUCT_NAME = "$(TARGET_NAME)"; 595 | SWIFT_VERSION = 5.0; 596 | TARGETED_DEVICE_FAMILY = "1,2"; 597 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftShaders.app/SwiftShaders"; 598 | }; 599 | name = Release; 600 | }; 601 | 1FE5FD96234997D2009DF72F /* Debug */ = { 602 | isa = XCBuildConfiguration; 603 | buildSettings = { 604 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 605 | CODE_SIGN_STYLE = Automatic; 606 | DEVELOPMENT_TEAM = 6ZQLTEG662; 607 | INFOPLIST_FILE = SwiftShadersUITests/Info.plist; 608 | LD_RUNPATH_SEARCH_PATHS = ( 609 | "$(inherited)", 610 | "@executable_path/Frameworks", 611 | "@loader_path/Frameworks", 612 | ); 613 | PRODUCT_BUNDLE_IDENTIFIER = com.malikalayli.SwiftShadersUITests; 614 | PRODUCT_NAME = "$(TARGET_NAME)"; 615 | SWIFT_VERSION = 5.0; 616 | TARGETED_DEVICE_FAMILY = "1,2"; 617 | TEST_TARGET_NAME = SwiftShaders; 618 | }; 619 | name = Debug; 620 | }; 621 | 1FE5FD97234997D2009DF72F /* Release */ = { 622 | isa = XCBuildConfiguration; 623 | buildSettings = { 624 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 625 | CODE_SIGN_STYLE = Automatic; 626 | DEVELOPMENT_TEAM = 6ZQLTEG662; 627 | INFOPLIST_FILE = SwiftShadersUITests/Info.plist; 628 | LD_RUNPATH_SEARCH_PATHS = ( 629 | "$(inherited)", 630 | "@executable_path/Frameworks", 631 | "@loader_path/Frameworks", 632 | ); 633 | PRODUCT_BUNDLE_IDENTIFIER = com.malikalayli.SwiftShadersUITests; 634 | PRODUCT_NAME = "$(TARGET_NAME)"; 635 | SWIFT_VERSION = 5.0; 636 | TARGETED_DEVICE_FAMILY = "1,2"; 637 | TEST_TARGET_NAME = SwiftShaders; 638 | }; 639 | name = Release; 640 | }; 641 | /* End XCBuildConfiguration section */ 642 | 643 | /* Begin XCConfigurationList section */ 644 | 1FE5FD60234997D1009DF72F /* Build configuration list for PBXProject "SwiftShaders" */ = { 645 | isa = XCConfigurationList; 646 | buildConfigurations = ( 647 | 1FE5FD8D234997D2009DF72F /* Debug */, 648 | 1FE5FD8E234997D2009DF72F /* Release */, 649 | ); 650 | defaultConfigurationIsVisible = 0; 651 | defaultConfigurationName = Release; 652 | }; 653 | 1FE5FD8F234997D2009DF72F /* Build configuration list for PBXNativeTarget "SwiftShaders" */ = { 654 | isa = XCConfigurationList; 655 | buildConfigurations = ( 656 | 1FE5FD90234997D2009DF72F /* Debug */, 657 | 1FE5FD91234997D2009DF72F /* Release */, 658 | ); 659 | defaultConfigurationIsVisible = 0; 660 | defaultConfigurationName = Release; 661 | }; 662 | 1FE5FD92234997D2009DF72F /* Build configuration list for PBXNativeTarget "SwiftShadersTests" */ = { 663 | isa = XCConfigurationList; 664 | buildConfigurations = ( 665 | 1FE5FD93234997D2009DF72F /* Debug */, 666 | 1FE5FD94234997D2009DF72F /* Release */, 667 | ); 668 | defaultConfigurationIsVisible = 0; 669 | defaultConfigurationName = Release; 670 | }; 671 | 1FE5FD95234997D2009DF72F /* Build configuration list for PBXNativeTarget "SwiftShadersUITests" */ = { 672 | isa = XCConfigurationList; 673 | buildConfigurations = ( 674 | 1FE5FD96234997D2009DF72F /* Debug */, 675 | 1FE5FD97234997D2009DF72F /* Release */, 676 | ); 677 | defaultConfigurationIsVisible = 0; 678 | defaultConfigurationName = Release; 679 | }; 680 | /* End XCConfigurationList section */ 681 | }; 682 | rootObject = 1FE5FD5D234997D1009DF72F /* Project object */; 683 | } 684 | -------------------------------------------------------------------------------- /SwiftShaders.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftShaders.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftShaders.xcodeproj/xcshareddata/xcschemes/SwiftShaders.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /SwiftShaders/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftShaders 4 | // 5 | // Created by Malik Alayli on 06/10/2019. 6 | // Copyright © 2019 MalikAlayli. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | final class AppDelegate: UIResponder, UIApplicationDelegate { 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/customTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "texture.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/customTexture.imageset/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/Assets.xcassets/customTexture.imageset/texture.png -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/diffuse.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "diffuse.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/diffuse.imageset/diffuse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/Assets.xcassets/diffuse.imageset/diffuse.jpg -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/noiseTexture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "bbHK0.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/noiseTexture.imageset/bbHK0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/Assets.xcassets/noiseTexture.imageset/bbHK0.jpg -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/normal.imageset/1182OS_04_06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/Assets.xcassets/normal.imageset/1182OS_04_06.jpg -------------------------------------------------------------------------------- /SwiftShaders/Assets.xcassets/normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1182OS_04_06.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SwiftShaders/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /SwiftShaders/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftShaders/GLSL/GLSL_Notes.txt: -------------------------------------------------------------------------------- 1 | // 2 | // API 3 | // 4 | //iOS 5 | // 6 | // https://developer.apple.com/documentation/scenekit/scnshadable 7 | // 8 | // Unity 9 | // 10 | // https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html?_ga=2.58238190.574435706.1570166606-1567286478.1570166606 11 | // 12 | 13 | /*! 14 | @property shaderModifiers 15 | @abstract Dictionary of shader modifiers snippets, targeting entry points. The valid keys are the entry points described in the "Shader Modifier Entry Point" constants. The values are the code snippets formatted as described below. 16 | @discussion Shader modifiers allow you to inject shader code in the standard shaders of SceneKit. This injection is allowed in few controlled entry points, allowing specific kind of tasks in specific context. Each modifier can operate on specific structures along with access to global uniforms, that could be the standard SceneKit uniforms or its own declared uniforms. 17 | 18 | Shader modifiers can be used to tweak SceneKit rendering by adding custom code at the following entry points: 19 | 1. vertex (SCNShaderModifierEntryPointGeometry) 20 | 2. surface (SCNShaderModifierEntryPointSurface) 21 | 3. lighting (SCNShaderModifierEntryPointLightingModel) 22 | 4. fragment (SCNShaderModifierEntryPointFragment) 23 | See below for a detailed explanation of these entry points and the context they provide. 24 | 25 | Shader modifiers can be written in either GLSL or the Metal Shading Language. Metal shaders won't run on iOS 8 and macOS 10.10 or earlier. 26 | 27 | The structure of a shader modifier is: 28 | 29 | GLSL 30 | | uniform float myGrayAmount = 3.0; // Custom GLSL uniforms declarations are of the form `[uniform type uniformName [= defaultValue]]` 31 | | 32 | | // Optional global function definitions (for Metal: references to uniforms in global functions are not supported). 33 | | float mySin(float t) { 34 | | return sin(t); 35 | | } 36 | | 37 | | [#pragma transparent | opaque] 38 | | [#pragma body] 39 | | 40 | | // the shader modifier code snippet itself 41 | | vec3 myColor = myGrayAmount; 42 | | _output.color.rgb += myColor; 43 | 44 | Metal Shading Language 45 | | #pragma arguments 46 | | float myGrayAmount; // Custom Metal uniforms declarations require a #pragma and are of the form `[type name]` 47 | | 48 | | // Optional global function definitions (for Metal: references to uniforms in global functions are not supported). 49 | | float mySin(float t) { 50 | | return sin(t); 51 | | } 52 | | 53 | | [#pragma transparent | opaque] 54 | | [#pragma body] 55 | | 56 | | // the shader modifier code snippet itself 57 | | float3 myColor = myGrayAmount; 58 | | _output.color.rgb += myColor; 59 | 60 | The `#pragma body` directive 61 | Is only needed if you declared functions that must not be included in the shader code itself. 62 | 63 | The `#pragma transparent` directive 64 | Forces the rendering to be blended using the following equation: 65 | _output.color.rgb + (1 - _output.color.a) * dst.rgb; 66 | where `dst` represents the current fragment color. The rgb components must be premultiplied. 67 | 68 | The `#pragma opaque` directive 69 | Forces the rendering to be opaque. It then ignores the alpha component of the fragment. 70 | 71 | When using Metal, you can also transfer varying values from the vertex shader (geometry shader modifier) to the fragment shader (surface and/or fragment shader modifier): 72 | 1. Start by declaring the varying values in at least one of the shader modifiers: 73 | 74 | Metal Shading Language 75 | | #pragma varyings 76 | | half3 myVec; 77 | 78 | 2. Then write the varying values from the vertex shader (geometry shader modifier): 79 | 80 | Metal Shading Language 81 | | #pragma body 82 | | out.myVec = _geometry.normal.xyz * 0.5h + 0.5h; 83 | 84 | 3. Finally read the varying values from the fragment shader (surface and/or fragment shader modifier): 85 | 86 | Metal Shading Language 87 | | _output.color.rgb = saturate(in.myVec); 88 | 89 | SceneKit declares the following built-in uniforms: 90 | 91 | GLSL | Metal Shading Language | 92 | --------------------------------------------┼-------------------------------------------------------┤ 93 | float u_time | float scn_frame.time | The current time, in seconds 94 | vec2 u_inverseResolution | float2 scn_frame.inverseResolution | 1.0 / screen size 95 | --------------------------------------------┼-------------------------------------------------------┤ 96 | mat4 u_viewTransform | float4x4 scn_frame.viewTransform | See SCNViewTransform 97 | mat4 u_inverseViewTransform | float4x4 scn_frame.inverseViewTransform | 98 | mat4 u_projectionTransform | float4x4 scn_frame.projectionTransform | See SCNProjectionTransform 99 | mat4 u_inverseProjectionTransform | float4x4 scn_frame.inverseProjectionTransform | 100 | --------------------------------------------┼-------------------------------------------------------┤ 101 | mat4 u_normalTransform | float4x4 scn_node.normalTransform | See SCNNormalTransform 102 | mat4 u_modelTransform | float4x4 scn_node.modelTransform | See SCNModelTransform 103 | mat4 u_inverseModelTransform | float4x4 scn_node.inverseModelTransform | 104 | mat4 u_modelViewTransform | float4x4 scn_node.modelViewTransform | See SCNModelViewTransform 105 | mat4 u_inverseModelViewTransform | float4x4 scn_node.inverseModelViewTransform | 106 | mat4 u_modelViewProjectionTransform | float4x4 scn_node.modelViewProjectionTransform | See SCNModelViewProjectionTransform 107 | mat4 u_inverseModelViewProjectionTransform | float4x4 scn_node.inverseModelViewProjectionTransform | 108 | --------------------------------------------┼-------------------------------------------------------┤ 109 | mat2x3 u_boundingBox; | float2x3 scn_node.boundingBox | The bounding box of the current geometry, in model space, u_boundingBox[0].xyz and u_boundingBox[1].xyz being respectively the minimum and maximum corner of the box. 110 | mat2x3 u_worldBoundingBox; | float2x3 scn_node.worldBoundingBox | The bounding box of the current geometry, in world space. 111 | 112 | When writing shaders using the Metal Shading Language a complete description of the type of the scn_frame variable (SCNSceneBuffer) can be found in the header file. 113 | The type of the scn_node variable is generated at compile time and there's no corresponding header file in the framework. 114 | 115 | In addition to these built-in uniforms, it is possible to use custom uniforms: 116 | 117 | The SCNGeometry and SCNMaterial classes are key-value coding compliant classes, which means that you can set values for arbitrary keys. Even if the key `myAmplitude` is not a declared property of the class, you can still set a value for it. 118 | Declaring a `myAmplitude` uniform in the shader modifier makes SceneKit observe the reveiver's `myAmplitude` key. Any change to that key will make SceneKit bind the uniform with the new value. 119 | 120 | The following GLSL and Metal Shading Language types (and their Objective-C counterparts) can be used to declare (and bind) custom uniforms: 121 | 122 | GLSL | Metal Shading Language | Objective-C | 123 | ------------┼------------------------┼---------------------------------------┤ 124 | int | int | NSNumber, NSInteger, int | 125 | float | float | NSNumber, CGFloat, float, double | 126 | vec2 | float2 | CGPoint | 127 | vec3 | float3 | SCNVector3 | 128 | vec4 | float4 | SCNVector4 | 129 | mat4, mat44 | float4x4 | SCNMatrix4 | 130 | sampler2D | texture2d | SCNMaterialProperty | 131 | samplerCube | texturecube | SCNMaterialProperty (with a cube map) | 132 | - | device const T* | MTLBuffer | Feature introduced in macOS 10.13, iOS 11.0 and tvOS 11.0 133 | - | struct {...} | NSData | The entire struct can be set using NSData but it is also possible to set individual members using the member's name as a key and a value compatible with the member's type 134 | 135 | Common scalar types wrapped into a NSValue are also supported. 136 | 137 | The following prefixes are reserved by SceneKit and should not be used in custom names: 138 | 1. u_ 139 | 2. a_ 140 | 3. v_ 141 | 142 | Custom uniforms can be animated using explicit animations. 143 | */ 144 | 145 | /*! 146 | @constant SCNShaderModifierEntryPointSurface 147 | @abstract This is the entry point to alter the surface representation of the material, before the lighting has taken place. 148 | 149 | Structures available from the SCNShaderModifierEntryPointSurface entry point: 150 | 151 | | struct SCNShaderSurface { 152 | | float3 view; // Direction from the point on the surface toward the camera (V) 153 | | float3 position; // Position of the fragment 154 | | float3 normal; // Normal of the fragment (N) 155 | | float3 geometryNormal; // Geometric normal of the fragment (normal map is ignored) 156 | | float3 tangent; // Tangent of the fragment 157 | | float3 bitangent; // Bitangent of the fragment 158 | | float4 ambient; // Ambient property of the fragment 159 | | float2 ambientTexcoord; // Ambient texture coordinates 160 | | float4 diffuse; // Diffuse property of the fragment. Alpha contains the opacity. 161 | | float2 diffuseTexcoord; // Diffuse texture coordinates 162 | | float4 specular; // Specular property of the fragment 163 | | float2 specularTexcoord; // Specular texture coordinates 164 | | float4 emission; // Emission property of the fragment 165 | | float2 emissionTexcoord; // Emission texture coordinates 166 | | float4 multiply; // Multiply property of the fragment 167 | | float2 multiplyTexcoord; // Multiply texture coordinates 168 | | float4 transparent; // Transparent property of the fragment 169 | | float2 transparentTexcoord; // Transparent texture coordinates 170 | | float4 reflective; // Reflective property of the fragment 171 | | float metalness; // Metalness property of the fragment 172 | | float2 metalnessTexcoord; // Metalness texture coordinates 173 | | float roughness; // Roughness property of the fragment 174 | | float2 roughnessTexcoord; // Roughness texture coordinates 175 | | float4 selfIllumination; // Self Illumination property of the fragment. Available since macOS 10.13, iOS 11, tvOS 11 and watchOS 4. Available as `emission` in previous versions. 176 | | float2 selfIlluminationTexcoord; // Self Illumination texture coordinates. Available since macOS 10.13, iOS 11, tvOS 11 and watchOS 4. Available as `emissionTexcoord` in previous versions. 177 | | float ambientOcclusion; // Ambient Occlusion property of the fragment. Available macOS 10.13, iOS 11, tvOS 11 and watchOS 4. Available as `multiply` in previous versions. 178 | | float2 ambientOcclusionTexcoord; // Ambient Occlusion texture coordinates. Available since macOS 10.13, iOS 11, tvOS 11 and watchOS 4. Available as `multiplyTexcoord` in previous versions. 179 | | float shininess; // Shininess property of the fragment 180 | | float fresnel; // Fresnel property of the fragment 181 | | } _surface; 182 | | 183 | | Access: ReadWrite 184 | | Stages: Fragment shader only 185 | 186 | All geometric fields are in view space. 187 | All the other properties will be colors (texture have already been sampled at this stage) or floats. You can however do an extra sampling of standard textures if you want. 188 | In this case the naming pattern is u_Texture. For example u_diffuseTexture or u_reflectiveTexture. Note that you have to be sure that the material do have a texture 189 | set for this property, otherwise you'll trigger a shader compilation error. 190 | 191 | Example: Procedural black and white stripes 192 | 193 | GLSL 194 | | uniform float Scale = 12.0; 195 | | uniform float Width = 0.25; 196 | | uniform float Blend = 0.3; 197 | | 198 | | vec2 position = fract(_surface.diffuseTexcoord * Scale); 199 | | float f1 = clamp(position.y / Blend, 0.0, 1.0); 200 | | float f2 = clamp((position.y - Width) / Blend, 0.0, 1.0); 201 | | f1 = f1 * (1.0 - f2); 202 | | f1 = f1 * f1 * 2.0 * (3. * 2. * f1); 203 | | _surface.diffuse = mix(vec4(1.0), vec4(0.0), f1); 204 | 205 | Metal Shading Language 206 | | #pragma arguments 207 | | float Scale; 208 | | float Width; 209 | | float Blend; 210 | | 211 | | float2 position = fract(_surface.diffuseTexcoord * Scale); 212 | | float f1 = clamp(position.y / Blend, 0.0, 1.0); 213 | | float f2 = clamp((position.y - Width) / Blend, 0.0, 1.0); 214 | | f1 = f1 * (1.0 - f2); 215 | | f1 = f1 * f1 * 2.0 * (3. * 2. * f1); 216 | | _surface.diffuse = mix(float4(1.0), float4(0.0), f1); 217 | 218 | */ 219 | -------------------------------------------------------------------------------- /SwiftShaders/GLSL/GLSL_Shaders.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // iOS GLSL Shaders 4 | 5 | // MARK: - Surface 6 | 7 | let simpleHalfColoringSurfaceShader = """ 8 | vec4 orig = _surface.diffuse; 9 | vec4 transformed_position = u_inverseModelTransform * u_inverseViewTransform * vec4(_surface.position, 1.0); 10 | if (transformed_position.x < 0.0) { 11 | _surface.diffuse = mix(vec4(1.0,0.0,0.0,1.0), orig, 0.5); 12 | } 13 | """ 14 | 15 | let simpleHalfColoringFromScreenSizeSurfaceShader = """ 16 | if (_surface.position.x < 0.0) { 17 | _surface.diffuse = vec4(0.0, 0.0, 1.0, 1.0); 18 | } else { 19 | _surface.diffuse = vec4(1.0, 0.8, 0.2, 1.0); 20 | } 21 | """ 22 | 23 | let coloringSurfaceShader = "float flakeSize = sin(u_time * 0.2);\n" 24 | + "float flakeIntensity = 0.7;\n" 25 | + "vec3 paintColor0 = vec3(1, 1, 1);\n" 26 | + "vec3 paintColor1 = vec3(0, 1, 1);\n" 27 | + "vec3 flakeColor = vec3(flakeIntensity, flakeIntensity, flakeIntensity);\n" 28 | + "vec3 rnd = texture2D(u_diffuseTexture, _surface.diffuseTexcoord * vec2(1.0) * sin(u_time*0.1) ).rgb;\n" 29 | + "vec3 nrm1 = normalize(0.05 * rnd + 0.95 * _surface.normal);\n" 30 | + "vec3 nrm2 = normalize(0.3 * rnd + 0.4 * _surface.normal);\n" 31 | + "float fresnel1 = clamp(dot(nrm1, _surface.view), 0.0, 1.0);\n" 32 | + "float fresnel2 = clamp(dot(nrm2, _surface.view), 0.0, 1.0);\n" 33 | + "vec3 col = mix(paintColor0, paintColor1, fresnel1);\n" 34 | + "col += pow(fresnel2, 106.0) * flakeColor;\n" 35 | + "_surface.normal = nrm1;\n" 36 | + "_surface.diffuse = vec4(col.r,col.b,col.g, 1.0);\n" 37 | + "_surface.emission = (_surface.reflective * _surface.reflective) * 2.0;\n" 38 | + "_surface.reflective = vec4(0.0);\n" 39 | 40 | // MARK: - Geometry 41 | 42 | let twistingGeometryShader = """ 43 | // a function that creates a rotation transform matrix around X 44 | mat4 rotationAroundX(float angle) 45 | { 46 | return mat4(1.0, 0.0, 0.0, 0.0, 47 | 0.0, cos(angle), -sin(angle), 0.0, 48 | 0.0, sin(angle), cos(angle), 0.0, 49 | 0.0, 0.0, 0.0, 1.0); 50 | } 51 | 52 | #pragma body 53 | 54 | float rotationAngle = _geometry.position.x * sin(u_time); 55 | mat4 rotationMatrix = rotationAroundX(rotationAngle); 56 | 57 | // position is a vec4 58 | _geometry.position *= rotationMatrix; 59 | 60 | // normal is a vec3 61 | vec4 twistedNormal = vec4(_geometry.normal, 1.0) * rotationMatrix; 62 | _geometry.normal = twistedNormal.xyz; 63 | """ 64 | 65 | // MARK: - Fragment 66 | 67 | let coloringFragmentShader = """ 68 | // Normalized pixel coordinates (from 0 to 1) 69 | vec2 uv = gl_FragCoord.xy * u_inverseResolution.xy; 70 | 71 | // Time varying pixel color 72 | vec3 col = 0.5 + 0.5*cos(u_time+uv.xyx+vec3(0,2,4)); 73 | 74 | // Output to screen 75 | _output.color.rgba = vec4(col,1); 76 | """ 77 | 78 | let appearingFragmentShader = 79 | """ 80 | #pragma arguments 81 | 82 | float revealage; 83 | texture2d noiseTexture; 84 | 85 | #pragma transparent 86 | #pragma body 87 | 88 | const float edgeWidth = 0.02; 89 | const float edgeBrightness = 2; 90 | const float3 innerColor = float3(0.4, 0.8, 1); 91 | const float3 outerColor = float3(0, 0.5, 1); 92 | const float noiseScale = 3; 93 | 94 | constexpr sampler noiseSampler(filter::linear, address::repeat); 95 | float2 noiseCoords = noiseScale * _surface.ambientTexcoord; 96 | float noiseValue = noiseTexture.sample(noiseSampler, noiseCoords).r; 97 | 98 | if (noiseValue > revealage) { 99 | discard_fragment(); 100 | } 101 | 102 | float edgeDist = revealage - noiseValue; 103 | if (edgeDist < edgeWidth) { 104 | float t = edgeDist / edgeWidth; 105 | float3 edgeColor = edgeBrightness * mix(outerColor, innerColor, t); 106 | _output.color.rgb = edgeColor; 107 | } 108 | """ 109 | 110 | let discoveringFragment = """ 111 | // Normalized pixel coordinates (from 0 to 1) 112 | vec2 uv = gl_FragCoord.xy * u_inverseResolution.xy; 113 | 114 | // Time varying pixel color 115 | vec3 col = texture2D(u_diffuseTexture, uv).rgb; 116 | 117 | // Output to screen 118 | _output.color.rgba = vec4(col,1); 119 | """ 120 | 121 | let gaussianFragment = """ 122 | vec2 uv = _surface.diffuseTexcoord.xy; 123 | 124 | float xValue = u_inverseResolution.x * 3.0; 125 | float yValue = u_inverseResolution.y * 2.0; 126 | 127 | float blur = 5.2; 128 | 129 | // Apply Gaussian Blur 130 | vec3 col = texture2D(u_diffuseTexture, vec2(uv.x - 4.0 * xValue * blur, uv.y - 4.0 * yValue * blur)).rgb * 0.01621621621; 131 | col += texture2D(u_diffuseTexture, vec2(uv.x - 3.0 * xValue * blur, uv.y - 3.0 * yValue * blur)).rgb * 0.0540540541; 132 | col += texture2D(u_diffuseTexture, vec2(uv.x - 2.0 * xValue * blur, uv.y - 2.0 * yValue * blur)).rgb * 0.1216216216; 133 | col += texture2D(u_diffuseTexture, vec2(uv.x - 1.0 * xValue * blur, uv.y - 1.0 * yValue * blur)).rgb * 0.1945945946; 134 | col += texture2D(u_diffuseTexture, vec2(uv.x, uv.y)).rgb * 0.2270270270; 135 | col += texture2D(u_diffuseTexture, vec2(uv.x + 1.0 * xValue * blur, uv.y + 1.0 * yValue * blur)).rgb * 0.1945945946; 136 | col += texture2D(u_diffuseTexture, vec2(uv.x + 2.0 * xValue * blur, uv.y + 2.0 * yValue * blur)).rgb * 0.1216216216; 137 | col += texture2D(u_diffuseTexture, vec2(uv.x + 3.0 * xValue * blur, uv.y + 3.0 * yValue * blur)).rgb * 0.0540540541; 138 | col += texture2D(u_diffuseTexture, vec2(uv.x + 4.0 * xValue * blur, uv.y + 4.0 * yValue * blur)).rgb * 0.01621621621; 139 | 140 | // Output to screen 141 | _output.color.rgba = vec4(col,1); 142 | """ 143 | 144 | let wavingFragment = """ 145 | vec2 uv = _surface.diffuseTexcoord.xy; 146 | float speed = 4.0; 147 | float turbulence = 10.0; 148 | float dist = length(uv); 149 | vec2 center = vec2(0.5, 0.5); 150 | uv += uv / dist * cos(dist * turbulence - u_time * speed) * 0.008; 151 | uv = uv * 0.5; 152 | vec3 col = texture2D(u_diffuseTexture, uv).rgb; 153 | _output.color.rgba = vec4(col,1); 154 | """ 155 | 156 | let dropEffectFragment = """ 157 | vec2 center = vec2(0.5,0.5); 158 | float speed = 0.035; 159 | vec2 uv = _surface.diffuseTexcoord.xy; 160 | vec3 col = vec4(uv,0.5+0.5*sin(u_time),1.0).xyz; 161 | vec3 texcol; 162 | float invAr = u_inverseResolution.x / u_inverseResolution.y; 163 | float x = (center.x-uv.x); 164 | float y = (center.y-uv.y) * invAr; 165 | float r = -(x*x + y*y); 166 | float z = 1.0 + 0.5*sin((r+u_time*speed)/0.013); 167 | texcol.x = z; 168 | texcol.y = z; 169 | texcol.z = z; 170 | _output.color.rgba = vec4(col*texcol, 1.0); 171 | """ 172 | -------------------------------------------------------------------------------- /SwiftShaders/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarHidden 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/Cloud.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | //Information about the node, passed to the vertex function 6 | struct NodeBuffer { 7 | float4x4 modelTransform; 8 | float4x4 inverseModelTransform; 9 | float4x4 modelViewTransform; 10 | float4x4 inverseModelViewTransform; 11 | float4x4 normalTransform; 12 | float4x4 modelViewProjectionTransform; 13 | float4x4 inverseModelViewProjectionTransform; 14 | float2x3 boundingBox; 15 | }; 16 | 17 | //Information about the vertex, passed to the vertex function 18 | typedef struct { 19 | float3 position [[attribute(SCNVertexSemanticPosition)]]; 20 | float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]]; 21 | } VertexInput; 22 | 23 | //Vertex function output, passed to the fragment function 24 | struct VertexOut 25 | { 26 | float4 position [[position]]; 27 | float4 fragmentModelCoordinates; 28 | float4 nodePosition; 29 | float4 cameraCoordinates; 30 | float4 cameraPosition; 31 | float2 texCoords; 32 | float time; 33 | }; 34 | 35 | //MARK: - Vertex Function 36 | //used to pass positions in node-space to the fragment function, in order to do per-pixel ray marching. 37 | vertex VertexOut cloudVertex(VertexInput in [[stage_in]], 38 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 39 | constant NodeBuffer& scn_node [[buffer(1)]]) 40 | { 41 | VertexOut vert; 42 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 43 | vert.texCoords = in.texCoords; 44 | 45 | //define raymarching transforms in node(model) space, so that the output 46 | //can be repostioned/rotated/scaled using the node's transform 47 | vert.fragmentModelCoordinates = float4(in.position, 1.0); 48 | vert.cameraCoordinates = scn_node.modelViewTransform * float4(in.position, 1.0); 49 | vert.nodePosition = float4(0,0,0, 1.0); 50 | vert.cameraPosition = scn_node.inverseModelViewTransform * float4(0,0,0, 1.0); 51 | 52 | //define animation parameters 53 | vert.time = scn_frame.time; 54 | return vert; 55 | } 56 | 57 | //MARK: - Ray Marching 58 | 59 | //MARK: Ray Marching utilities 60 | struct Ray { 61 | float3 origin; 62 | float3 direction; 63 | Ray(float3 o, float3 d) { 64 | origin = o; 65 | direction = d; 66 | } 67 | }; 68 | 69 | float3 IntersectionOnPlane( float3 offsetOrthogonalToPlane, float3 rayDirection) 70 | { 71 | float dotToSurface = dot(normalize(offsetOrthogonalToPlane), rayDirection); 72 | if( dotToSurface <= 0.0) 73 | { 74 | return float3(0); 75 | } 76 | return rayDirection * length(offsetOrthogonalToPlane) / dotToSurface; 77 | }; 78 | 79 | //MARK: Ray Marching Function 80 | /// For a given ray(ray) and volume position(nodePosition) step through the input textures(noiseTexture, interferenceTexture, densityMap) to output a final pixel color. 81 | /// 82 | /// - Parameters: 83 | /// - ray: origin and direction of view for a single fragment 84 | /// - nodePosition: the center of the final rendered volume 85 | /// - time: scn_frame.time passed from the vertex function, used to animate the noise textures 86 | /// - noiseTexture: texture that provides soft noise distortion to the final cloud volume, tiled and animated 87 | /// - interferenceTexture: texture that creates harsher distortions, tiled and animated 88 | /// - densityMap: real cloud data, white is denser cloud cover, black is thinner. 89 | 90 | float4 RayMarch(Ray ray, float4 nodePosition, float time, texture2d noiseTexture, texture2d interferenceTexture, texture2d densityMap) 91 | { 92 | float3 initialDirection = ray.direction; 93 | float3 initialPosition = ray.origin; 94 | float3 samplePosition = initialPosition; 95 | 96 | // Raymarching parameters 97 | //initial direction, *0.01 to make the skipstep values easier to modify/experiment with 98 | float3 offset = initialDirection * 0.01; 99 | //skipstep: the distance travelled at each step. Larger numbers are more performant, but lower quality. 100 | float skipStep = 8.0; 101 | //scale for the noise samples, larger numbers scale up the noise texture. 102 | float tileScale = 1; 103 | 104 | //animation parameters, these could be made into shader inputs, or even become data-driven by textures 105 | float2 windDirection = normalize(float2(.5,.5)); 106 | float3 baseColor = float3(.85, .8, .7); //the color to add per-step. 107 | float opacityModifier = .2; //scale for the opacity contribution per-step, higher numbers make thicker clouds. 108 | float cloudDensityModifier = 4.0; //scale factor for cloud density, higher numbers makes the density map more pronounced in the output. 109 | 110 | //cloud bounds 111 | float cloudSizeVertical = .5; 112 | float cloudCenterBounds = nodePosition.y; 113 | float cloudUpperBounds = cloudCenterBounds + cloudSizeVertical; 114 | float cloudLowerBounds = cloudCenterBounds - cloudSizeVertical; 115 | 116 | //place the initial sample on cloud bounds (defined above) 117 | if(samplePosition.y > cloudUpperBounds) 118 | { 119 | float3 orthoOffset = float3(samplePosition.x, cloudUpperBounds, samplePosition.z) - samplePosition; 120 | float3 offsetToBounds = IntersectionOnPlane(orthoOffset, initialDirection); 121 | samplePosition += offsetToBounds; 122 | } 123 | if(samplePosition.y < cloudLowerBounds) 124 | { 125 | float3 orthoOffset = float3(samplePosition.x, cloudLowerBounds, samplePosition.z) - samplePosition; 126 | float3 offsetToBounds = IntersectionOnPlane(orthoOffset, initialDirection); 127 | samplePosition += offsetToBounds; 128 | } 129 | 130 | //final pixel color from raymarching 131 | float4 outputColor = float4(0.0); 132 | 133 | //measure initial position from the sampleposition snapped to cloud boundaries 134 | initialPosition = samplePosition; 135 | 136 | //initialize offset before loop, in case we want to apply a default 137 | float3 newOffset = offset; 138 | 139 | //define multiple samplers, one for each texture 140 | //density: the opacity of the volume. samples the satellite cloud texture 141 | constexpr sampler densitySampler(coord::normalized, filter::nearest, address::clamp_to_zero); 142 | //noise: adds some interference to the volume, creating more realistic, animated final visuals 143 | constexpr sampler softNoiseSampler(coord::normalized, filter::linear, address::repeat); 144 | constexpr sampler sharpNoiseSampler(coord::normalized, filter::linear, address::repeat); 145 | 146 | 147 | //MARK: Ray Marching Loop 148 | //takes up to 30 texture samples per-pixel, moving by the offset*stepsize in node-space every loop. 149 | for(int i = int(0); i < 30; i++) 150 | { 151 | 152 | //stop marching if the ray has left the cloud volume 153 | if(samplePosition.y > cloudUpperBounds + 0.01) 154 | { 155 | break; 156 | } 157 | if(samplePosition.y < cloudLowerBounds - 0.01) 158 | { 159 | break; 160 | } 161 | 162 | //get distance from the cloud's center plane 163 | float dist = (samplePosition.y - cloudCenterBounds) / cloudSizeVertical; 164 | float absDist = abs(dist); 165 | 166 | //use node-space coordinates to define UVs, so that the volume responds to positions/scale/rotation changes 167 | float2 nodeUV = (samplePosition.xz - nodePosition.xz) / tileScale; 168 | 169 | //cheap modulo here is faster than feeding large uv positions to the sampler 170 | float2 moduloNodeUV = nodeUV; 171 | moduloNodeUV = moduloNodeUV - floor(moduloNodeUV); 172 | 173 | //offset the UVs from node center to match normalized texture coordinate space (0-1). 174 | nodeUV += 0.5; 175 | 176 | //check density using the red component - standard when sampling greyscale images 177 | float4 densitySample = densityMap.sample(densitySampler, nodeUV ); 178 | float density = densitySample.r * cloudDensityModifier; 179 | 180 | //animate the noise textures over time 181 | float2 softNoiseAnimation = time * 0.01 * windDirection; 182 | float2 noiseUV = moduloNodeUV - softNoiseAnimation; 183 | float4 softNoiseSample = noiseTexture.sample(softNoiseSampler, noiseUV ); 184 | softNoiseSample.a = softNoiseSample.r; 185 | 186 | //create a copy to interfere with the original noise sample, causing clouds to distort over time 187 | float2 interferenceAnimation = softNoiseAnimation; 188 | interferenceAnimation.x *= -2; 189 | float2 interferenceUV = moduloNodeUV + float2(.5,.5) - (interferenceAnimation); 190 | float4 interferenceSample = interferenceTexture.sample(sharpNoiseSampler, interferenceUV); 191 | interferenceSample.a = interferenceSample.r; 192 | 193 | //create final texture sample by mixing base, interference samples and density 194 | float4 textureSample = saturate((density) - (softNoiseSample * 0.6 - interferenceSample * 0.6 )); 195 | 196 | //blend with previous samples if the sample alpha is high enough 197 | if( textureSample.a >= absDist ) 198 | { 199 | //use the texture sample to add some opacity to the output color 200 | float opacityGain = textureSample.a * opacityModifier; 201 | outputColor.a += opacityGain; 202 | 203 | //color the output based on the height of sample - higher samples are lighter. 204 | float3 baseSampleColor = mix(1.0, dist * 0.5 + 0.5, baseColor) * opacityGain; 205 | outputColor.rgb += baseSampleColor; 206 | } 207 | 208 | //move the sample position to the new offset based on the skipstep and the opacity of the current sample 209 | //more opaque samples step less, to create better definition around the edges. 210 | newOffset = offset * (skipStep) * ( 1.0 - (outputColor.a * 0.8)); 211 | samplePosition += newOffset; 212 | 213 | //set a max opacity for the output color, and stop marching if it's reached. 214 | if(outputColor.a >= .8) 215 | break; 216 | 217 | }; 218 | 219 | return outputColor; 220 | }; 221 | 222 | //MARK: - Fragment Function 223 | fragment half4 cloudFragment(VertexOut in [[stage_in]], 224 | constant NodeBuffer& scn_node [[buffer(1)]], 225 | texture2d noiseTexture [[texture(0)]], 226 | texture2d interferenceTexture [[texture(1)]], 227 | texture2d densityMap [[texture(2)]]) 228 | { 229 | 230 | //construct ray pointing into the cloud volume 231 | float3 rayDirection = normalize(float3( in.fragmentModelCoordinates.xyz - in.cameraPosition.xyz)); 232 | float3 rayOrigin = in.fragmentModelCoordinates.xyz; 233 | Ray ray = Ray(rayOrigin, rayDirection); 234 | 235 | //output the ray marching result 236 | float4 output = RayMarch(ray, in.nodePosition, in.time, noiseTexture, interferenceTexture, densityMap); 237 | return half4(output); 238 | 239 | }; 240 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/Color.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | struct NodeBuffer { 6 | float4x4 modelTransform; 7 | float4x4 modelViewTransform; 8 | float4x4 normalTransform; 9 | float4x4 modelViewProjectionTransform; 10 | float2x3 boundingBox; 11 | }; 12 | 13 | struct VertexInput { 14 | float3 position [[attribute(SCNVertexSemanticPosition)]]; 15 | float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]]; 16 | }; 17 | 18 | struct VertexOut 19 | { 20 | float4 position [[position]]; 21 | float2 uv; 22 | }; 23 | 24 | struct FragmentUniforms { 25 | float red; 26 | float green; 27 | float blue; 28 | float alpha; 29 | }; 30 | 31 | vertex VertexOut colorVertex(VertexInput in [[stage_in]], constant NodeBuffer& scn_node [[buffer(1)]]) { 32 | VertexOut out; 33 | out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 34 | out.uv = in.texCoords; 35 | return out; 36 | } 37 | 38 | fragment float4 colorFragment(VertexOut vertexOut [[stage_in]], constant FragmentUniforms &uniforms [[buffer(0)]]) { 39 | return float4(uniforms.red, uniforms.green, uniforms.blue, uniforms.alpha); 40 | } 41 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/GaussianBlur.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | using namespace metal; 6 | 7 | struct NodeBuffer { 8 | float4x4 modelTransform; 9 | float4x4 modelViewProjectionTransform; 10 | float4x4 modelViewTransform; 11 | float4x4 normalTransform; 12 | float2x3 boundingBox; 13 | }; 14 | 15 | struct VertexInput { 16 | float3 position [[attribute(SCNVertexSemanticPosition)]]; 17 | float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]]; 18 | }; 19 | 20 | struct VertexOut { 21 | float4 position [[position]]; 22 | float2 uv; 23 | }; 24 | 25 | struct FragmentUniforms { 26 | float blur; 27 | }; 28 | 29 | vertex VertexOut gaussianBlurVertex(VertexInput in [[stage_in]], constant NodeBuffer& scn_node [[buffer(1)]]) { 30 | VertexOut out; 31 | out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 32 | out.uv = in.texCoords; 33 | return out; 34 | } 35 | 36 | fragment float4 gaussianBlurFragment(VertexOut fragmentIn [[stage_in]], texture2d customTexture [[texture(0)]], constant FragmentUniforms &uniforms [[buffer(0)]]) { 37 | float2 offset = fragmentIn.uv; 38 | constexpr sampler qsampler(coord::normalized,address::clamp_to_edge); 39 | float width = customTexture.get_width(); 40 | float height = customTexture.get_width(); 41 | float xPixel = (1 / width) * 3; 42 | float yPixel = (1 / height) * 2; 43 | 44 | float3 sum = float3(0.0, 0.0, 0.0); 45 | 46 | float blur = uniforms.blur; 47 | 48 | // code from https://github.com/mattdesl/lwjgl-basics/wiki/ShaderLesson5 49 | 50 | // 9 tap filter 51 | sum += customTexture.sample(qsampler, float2(offset.x - 4.0*xPixel*blur, offset.y - 4.0*yPixel*blur)).rgb * 0.0162162162; 52 | sum += customTexture.sample(qsampler, float2(offset.x - 3.0*xPixel*blur, offset.y - 3.0*yPixel*blur)).rgb * 0.0540540541; 53 | sum += customTexture.sample(qsampler, float2(offset.x - 2.0*xPixel*blur, offset.y - 2.0*yPixel*blur)).rgb * 0.1216216216; 54 | sum += customTexture.sample(qsampler, float2(offset.x - 1.0*xPixel*blur, offset.y - 1.0*yPixel*blur)).rgb * 0.1945945946; 55 | 56 | sum += customTexture.sample(qsampler, offset).rgb * 0.2270270270; 57 | 58 | sum += customTexture.sample(qsampler, float2(offset.x + 1.0*xPixel*blur, offset.y + 1.0*yPixel*blur)).rgb * 0.1945945946; 59 | sum += customTexture.sample(qsampler, float2(offset.x + 2.0*xPixel*blur, offset.y + 2.0*yPixel*blur)).rgb * 0.1216216216; 60 | sum += customTexture.sample(qsampler, float2(offset.x + 3.0*xPixel*blur, offset.y + 3.0*yPixel*blur)).rgb * 0.0540540541; 61 | sum += customTexture.sample(qsampler, float2(offset.x + 4.0*xPixel*blur, offset.y + 4.0*yPixel*blur)).rgb * 0.0162162162; 62 | 63 | float4 adjusted; 64 | adjusted.rgb = sum; 65 | adjusted.a = 1; 66 | return adjusted; 67 | } 68 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/MetalNotes.txt: -------------------------------------------------------------------------------- 1 | //struct SCNSceneBuffer { 2 | // float4x4 viewTransform; 3 | // float4x4 inverseViewTransform; // view space to world space 4 | // float4x4 projectionTransform; 5 | // float4x4 viewProjectionTransform; 6 | // float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 7 | // float4 ambientLightingColor; 8 | // float4 fogColor; 9 | // float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 10 | // float time; // system time elapsed since first render with this shader 11 | // float sinTime; // precalculated sin(time) 12 | // float cosTime; // precalculated cos(time) 13 | // float random01; // random value between 0.0 and 1.0 14 | //}; 15 | 16 | //enum { 17 | //SCNVertexSemanticPosition, 18 | //SCNVertexSemanticNormal, 19 | //SCNVertexSemanticTangent, 20 | //SCNVertexSemanticColor, 21 | //SCNVertexSemanticBoneIndices, 22 | //SCNVertexSemanticBoneWeights, 23 | //SCNVertexSemanticTexcoord0, 24 | //SCNVertexSemanticTexcoord1, 25 | //SCNVertexSemanticTexcoord2, 26 | //SCNVertexSemanticTexcoord3 27 | //}; 28 | 29 | // In custom shaders or in shader modifiers, you also have access to node relative information. 30 | // This is done using an argument named "scn_node", which must be a struct with only the necessary fields 31 | // among the following list: 32 | // 33 | // float4x4 modelTransform; 34 | // float4x4 inverseModelTransform; 35 | // float4x4 modelViewTransform; 36 | // float4x4 inverseModelViewTransform; 37 | // float4x4 normalTransform; // This is the inverseTransposeModelViewTransform, need for normal transformation 38 | // float4x4 modelViewProjectionTransform; 39 | // float4x4 inverseModelViewProjectionTransform; 40 | // float2x3 boundingBox; 41 | // float2x3 worldBoundingBox; 42 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/Pixelate.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | struct custom_vertex_t 6 | { 7 | float4 position [[attribute(SCNVertexSemanticPosition)]]; 8 | }; 9 | 10 | constexpr sampler s = sampler(coord::normalized, 11 | address::repeat, 12 | filter::nearest); 13 | 14 | struct out_vertex_t 15 | { 16 | float4 position [[position]]; 17 | float2 uv; 18 | }; 19 | 20 | vertex out_vertex_t pixelate_pass_through_vertex(custom_vertex_t in [[stage_in]], 21 | constant SCNSceneBuffer& scn_frame [[buffer(0)]]) 22 | { 23 | out_vertex_t out; 24 | out.position = in.position; 25 | out.uv = float2((in.position.x + 1.0) * 0.5 , (in.position.y + 1.0) * -0.5); 26 | return out; 27 | }; 28 | 29 | fragment half4 pixelate_pass_through_fragment(out_vertex_t vert [[stage_in]], 30 | texture2d colorSampler [[texture(0)]]) 31 | { 32 | float4 fragment_color = colorSampler.sample( s, vert.uv); 33 | return half4(fragment_color); 34 | }; 35 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/TextureBrightness.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | using namespace metal; 6 | 7 | struct NodeBuffer { 8 | float4x4 modelTransform; 9 | float4x4 modelViewProjectionTransform; 10 | float4x4 modelViewTransform; 11 | float4x4 normalTransform; 12 | float2x3 boundingBox; 13 | }; 14 | 15 | struct VertexInput { 16 | float3 position [[attribute(SCNVertexSemanticPosition)]]; 17 | float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]]; 18 | }; 19 | 20 | struct VertexOut { 21 | float4 position [[position]]; 22 | float2 uv; 23 | }; 24 | 25 | struct FragmentUniforms { 26 | float brightness; 27 | }; 28 | 29 | vertex VertexOut textureBrightnessSamplerVertex(VertexInput in [[stage_in]], constant NodeBuffer& scn_node [[buffer(1)]]) { 30 | VertexOut out; 31 | out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 32 | out.uv = in.texCoords; 33 | return out; 34 | } 35 | 36 | fragment float4 textureBrightnessSamplerFragment(VertexOut out [[stage_in]], texture2d customTexture [[texture(0)]], constant FragmentUniforms &uniforms [[buffer(0)]]) { 37 | constexpr sampler textureSampler(coord::normalized, filter::linear, address::repeat); 38 | return customTexture.sample(textureSampler, out.uv).rgba * uniforms.brightness; 39 | } 40 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/TextureSampler.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | struct NodeBuffer { 6 | float4x4 modelTransform; 7 | float4x4 modelViewProjectionTransform; 8 | float4x4 modelViewTransform; 9 | float4x4 normalTransform; 10 | float2x3 boundingBox; 11 | }; 12 | 13 | struct VertexInput { 14 | float3 position [[attribute(SCNVertexSemanticPosition)]]; 15 | float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]]; 16 | }; 17 | 18 | struct VertexOut { 19 | float4 position [[position]]; 20 | float2 uv; 21 | }; 22 | 23 | vertex VertexOut textureSamplerVertex(VertexInput in [[stage_in]], constant NodeBuffer& scn_node [[buffer(1)]]) { 24 | VertexOut out; 25 | out.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 26 | out.uv = in.texCoords; 27 | return out; 28 | } 29 | 30 | fragment float4 textureSamplerFragment(VertexOut out [[stage_in]], texture2d customTexture [[texture(0)]]) { 31 | constexpr sampler textureSampler(coord::normalized, filter::linear, address::repeat); 32 | return customTexture.sample(textureSampler, out.uv).rgba; 33 | } 34 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/ThickRedLine.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | struct MyNodeBuffer { 6 | float4x4 modelViewProjectionTransform; 7 | }; 8 | 9 | struct lineDataBuffer { 10 | int width; 11 | int verticleCount; 12 | int miter; 13 | int loop; 14 | }; 15 | 16 | struct SimpleVertex 17 | { 18 | float4 position [[position]]; 19 | float4 color; 20 | }; 21 | 22 | vertex SimpleVertex thickLinesVertex(constant SCNSceneBuffer& scn_frame [[buffer(0)]], 23 | constant MyNodeBuffer& scn_node [[buffer(1)]], 24 | constant float3* vertices [[buffer(2)]], 25 | constant lineDataBuffer& lineData [[buffer(3)]], 26 | constant float4* color [[buffer(4)]], 27 | uint v_id [[vertex_id]]) 28 | { 29 | 30 | uint point_id = v_id/4; //line point id (not vertex) 31 | float sign = v_id%2?-1:1; //should point be up or down in line 32 | 33 | SimpleVertex vert; 34 | vert.color = *color; //pass the color data to fragment shader 35 | 36 | float2 aspect = float2( scn_frame.viewportSize.x / scn_frame.viewportSize.y, 1); //aspect ratio 37 | 38 | vert.position = scn_node.modelViewProjectionTransform * float4(vertices[v_id], 1.0); //position of the point 39 | 40 | if (lineData.miter == 0 || point_id == 0 || point_id + 1 == uint(lineData.verticleCount)){ 41 | //Active when there it's first point, last point or no mitter middle point 42 | //TODO: get rid of conditionals 43 | 44 | uint currentPointToProcess; 45 | uint nextPointToProcess; 46 | 47 | int lineToNext = 0; //should line be calcualted from current point to next, or from current to previous 48 | lineToNext |= point_id == 0 && !lineData.loop; //always go to next if its first point 49 | lineToNext |= point_id*4+2 == v_id; //always go to next if its third or fourth vertex of current point 50 | lineToNext |= point_id*4+3 == v_id; 51 | lineToNext &= point_id + 1 != uint(lineData.verticleCount) || lineData.loop; //always go to prevous if its a last point 52 | 53 | currentPointToProcess = (point_id-1+lineToNext + lineData.verticleCount) % lineData.verticleCount; 54 | nextPointToProcess = (point_id+lineToNext) % lineData.verticleCount; 55 | 56 | //calculate MVP transform for both points 57 | float4 currentProjection = scn_node.modelViewProjectionTransform * float4(vertices[currentPointToProcess*4], 1.0); 58 | float4 nextProjection = scn_node.modelViewProjectionTransform * float4(vertices[nextPointToProcess*4], 1.0); 59 | 60 | //get 2d position in screen space 61 | float2 currentScreen = currentProjection.xy / currentProjection.w * aspect; 62 | float2 nextScreen = nextProjection.xy / nextProjection.w * aspect; 63 | 64 | //get vector of the line 65 | float2 dir = normalize(nextScreen - currentScreen); 66 | //vector of diretion of thickness 67 | float2 normal = float2(-dir.y, dir.x); 68 | normal /= aspect; 69 | 70 | //get thickness in pixels in screen space 71 | float thickness = float(lineData.width)/scn_frame.viewportSize.y; 72 | 73 | //move current point up or down, by thickness, with the same distance independent on depth 74 | vert.position += float4(sign*normal*thickness*vert.position.w, 0, 0 ); 75 | 76 | }else { 77 | //TODO: Switch to normal mode of miter size is to big 78 | //other points, calculate mitter 79 | 80 | //Similar to previus case, but looking always at 3 points - current, prevoius and next 81 | 82 | float4 previousProjection= scn_node.modelViewProjectionTransform * float4(vertices[(point_id - 1)*4], 1.0); 83 | float4 currentProjection= scn_node.modelViewProjectionTransform * float4(vertices[point_id*4], 1.0); 84 | float4 nextProjection = scn_node.modelViewProjectionTransform * float4(vertices[(point_id + 1)*4], 1.0); 85 | 86 | float2 previousScreen = previousProjection.xy / previousProjection.w * aspect; 87 | float2 currentScreen = currentProjection.xy / currentProjection.w * aspect; 88 | float2 nextScreen = nextProjection.xy / nextProjection.w * aspect; 89 | 90 | //vector tangential to the joint 91 | float2 tangent = normalize( normalize(nextScreen-currentScreen) + normalize(currentScreen-previousScreen) ); 92 | 93 | float2 dir = normalize(nextScreen - currentScreen); 94 | float2 normal = float2(-dir.y, dir.x); 95 | 96 | //mitter line - normal to the tangent 97 | float2 miter = float2( -tangent.y, tangent.x ); 98 | 99 | float thickness = float(lineData.width)/scn_frame.viewportSize.y; 100 | 101 | //mitter length - crossing of one of the edges with mitter line 102 | float miterLength = thickness / dot( miter, normal ); 103 | miter /= aspect; 104 | 105 | vert.position += float4(sign*miter*miterLength*vert.position.w, 0,0 ); 106 | } 107 | 108 | return vert; 109 | } 110 | 111 | fragment float4 thickLinesFragment(SimpleVertex in [[stage_in]]) 112 | { 113 | float4 color; 114 | color = in.color; 115 | return color; 116 | } 117 | -------------------------------------------------------------------------------- /SwiftShaders/Metal/Triangles.metal: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace metal; 3 | #include 4 | 5 | struct myPlaneNodeBuffer { 6 | float4x4 modelTransform; 7 | float4x4 modelViewTransform; 8 | float4x4 normalTransform; 9 | float4x4 modelViewProjectionTransform; 10 | float2x3 boundingBox; 11 | }; 12 | 13 | typedef struct { 14 | float3 position [[attribute(SCNVertexSemanticPosition)]]; 15 | float2 texCoords [[attribute(SCNVertexSemanticTexcoord0)]]; 16 | } VertexInput; 17 | 18 | static float rand(float2 uv) 19 | { 20 | return fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453); 21 | } 22 | 23 | static float2 uv2tri(float2 uv) 24 | { 25 | float sx = uv.x - uv.y / 2; 26 | float sxf = fract(sx); 27 | float offs = step(fract(1 - uv.y), sxf); 28 | return float2(floor(sx) * 2 + sxf + offs, uv.y); 29 | } 30 | 31 | struct SimpleVertexWithUV 32 | { 33 | float4 position [[position]]; 34 | float2 uv; 35 | }; 36 | 37 | vertex SimpleVertexWithUV trianglequiltVertex(VertexInput in [[stage_in]], 38 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 39 | constant myPlaneNodeBuffer& scn_node [[buffer(1)]]) 40 | { 41 | SimpleVertexWithUV vert; 42 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 43 | vert.uv = in.texCoords; 44 | return vert; 45 | } 46 | 47 | fragment float4 trianglequiltFragment(SimpleVertexWithUV in [[stage_in]], 48 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 49 | constant myPlaneNodeBuffer& scn_node [[buffer(1)]]) 50 | { 51 | float4 fragColor; 52 | float2 uv = in.uv*10; 53 | float timer = scn_frame.time; 54 | uv.y += timer; 55 | 56 | float t = timer * 0.8; 57 | float tc = floor(t); 58 | float tp = smoothstep(0, 0.8, fract(t)); 59 | 60 | float2 r1 = float2(floor(uv.y), tc); 61 | float2 r2 = float2(floor(uv.y), tc + 1); 62 | float offs = mix(rand(r1), rand(r2), tp); 63 | 64 | uv.x += offs * 8; 65 | 66 | float2 p = uv2tri(uv); 67 | float ph = rand(floor(p)) * 6.3 + p.y * 0.2; 68 | float c = abs(sin(ph + timer)); 69 | 70 | fragColor = float4(c, c, c, 1); 71 | return(fragColor); 72 | } 73 | -------------------------------------------------------------------------------- /SwiftShaders/UI/GameViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import SpriteKit 3 | import GameplayKit 4 | import SceneKit 5 | 6 | enum SceneState { 7 | case standard, pixelized 8 | } 9 | 10 | final class GameViewController: UIViewController { 11 | private var sceneState = SceneState.standard 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | addScene() 16 | } 17 | 18 | private func addScene() { 19 | guard let scnView = view as? SCNView else { 20 | return 21 | } 22 | 23 | scnView.scene = SwiftShadersScene() as SwiftShadersScene 24 | 25 | let camera = SCNCamera() 26 | camera.wantsHDR = true 27 | camera.bloomThreshold = 0.8 28 | camera.bloomIntensity = 2 29 | camera.bloomBlurRadius = 16.0 30 | camera.wantsExposureAdaptation = false 31 | 32 | // create and add a camera to the scene 33 | let cameraNode = SCNNode() 34 | cameraNode.position = SCNVector3(x: 0, y: 0, z: 10) 35 | cameraNode.camera = camera 36 | 37 | scnView.pointOfView = cameraNode 38 | scnView.autoenablesDefaultLighting = false 39 | scnView.allowsCameraControl = true // allows the user to manipulate the camera 40 | scnView.showsStatistics = true // show statistics such as fps and timing information 41 | scnView.backgroundColor = .clear 42 | 43 | switch sceneState { 44 | case .standard: () 45 | 46 | case .pixelized: 47 | if let path = Bundle.main.path(forResource: "pixelate", ofType: "plist"), 48 | let plistDict = NSDictionary(contentsOfFile: path), 49 | let plistStrDict = plistDict as? [String : AnyObject] { 50 | let pixelateTechnique = SCNTechnique(dictionary:plistStrDict) 51 | scnView.technique = pixelateTechnique 52 | } 53 | } 54 | 55 | scnView.play(nil) 56 | } 57 | 58 | func shouldAutorotate() -> Bool { 59 | return true 60 | } 61 | 62 | func prefersStatusBarHidden() -> Bool { 63 | return true 64 | } 65 | 66 | func supportedInterfaceOrientations() -> Int { 67 | if UIDevice.current.userInterfaceIdiom == .phone { 68 | return Int(UIInterfaceOrientationMask.allButUpsideDown.rawValue) 69 | } else { 70 | return Int(UIInterfaceOrientationMask.all.rawValue) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /SwiftShaders/UI/SCNGeometry+Line.swift: -------------------------------------------------------------------------------- 1 | import SceneKit 2 | 3 | extension SCNGeometry { 4 | class func lineThrough(points: [SCNVector3], width:Int = 20, closed: Bool = false, color: CGColor = UIColor.black.cgColor, mitter: Bool = false) -> SCNGeometry? { 5 | 6 | // Becouse we cannot use geometry shaders in metal, every point on the line has to be changed into 4 verticles 7 | let vertices: [SCNVector3] = points.flatMap { p in [p, p, p, p] } 8 | 9 | // Create Geometry Source object 10 | let source = SCNGeometrySource(vertices: vertices) 11 | 12 | // Create Geometry Element object 13 | var indices = Array((0...size*lineData.count), forKeyPath: "lineData") 25 | 26 | // map verticles into float3 27 | let floatPoints = vertices.map { SIMD3($0) } 28 | geometry.setValue(NSData(bytes: floatPoints, length: MemoryLayout>.size * floatPoints.count), forKeyPath: "vertices") 29 | 30 | // map color into float 31 | guard let components = color.components else { 32 | return nil 33 | } 34 | 35 | let colorFloat = components.map { Float($0) } 36 | 37 | geometry.setValue(NSData(bytes: colorFloat, length: MemoryLayout.size * color.numberOfComponents), forKey: "color") 38 | 39 | // Set the shader program 40 | let program = SCNProgram() 41 | program.fragmentFunctionName = "thickLinesFragment" 42 | program.vertexFunctionName = "thickLinesVertex" 43 | geometry.program = program 44 | 45 | return geometry 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SwiftShaders/UI/SCNNode+Effects.swift: -------------------------------------------------------------------------------- 1 | import SceneKit 2 | 3 | // MARK: - Cube 4 | 5 | extension SCNNode { 6 | convenience init(position p: SCNVector3, shaders: [SCNShaderModifierEntryPoint: String]) { 7 | self.init() 8 | 9 | castsShadow = false 10 | position = p 11 | geometry = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0) 12 | 13 | let material = SCNMaterial() 14 | material.shaderModifiers = shaders 15 | material.lightingModel = .constant 16 | geometry?.materials = [material] 17 | } 18 | } 19 | 20 | // MARK: - Texture 21 | 22 | extension SCNNode { 23 | func addTexture(_ imageName: String) { 24 | geometry?.firstMaterial?.diffuse.contents = UIImage(named: imageName) 25 | } 26 | } 27 | 28 | // MARK: - Animations 29 | 30 | extension SCNNode { 31 | func addAnimation(beginTime: CFTimeInterval = 0.0, duration: CFTimeInterval, from: NSValue, to: NSValue, key: String) { 32 | let animation = CABasicAnimation(keyPath: "rotation") 33 | animation.beginTime = beginTime 34 | animation.duration = duration 35 | animation.fromValue = from 36 | animation.toValue = to 37 | animation.repeatCount = .greatestFiniteMagnitude 38 | addAnimation(animation, forKey: key) 39 | } 40 | 41 | func addRevealAnimation() { 42 | let revealAnimation = CABasicAnimation(keyPath: "revealage") 43 | revealAnimation.timingFunction = CAMediaTimingFunction(name: .linear) 44 | revealAnimation.beginTime = CACurrentMediaTime() + 5 45 | revealAnimation.duration = 2.5 46 | revealAnimation.fromValue = 0.0 47 | revealAnimation.toValue = 1.0 48 | revealAnimation.fillMode = .forwards 49 | revealAnimation.isRemovedOnCompletion = false 50 | 51 | let scnRevealAnimation = SCNAnimation(caAnimation: revealAnimation) 52 | geometry?.firstMaterial?.addAnimation(scnRevealAnimation, forKey: "Reveal") 53 | } 54 | } 55 | 56 | // MARK: - CIFilter 57 | 58 | extension SCNNode { 59 | func addFilters(_ names: [String]) { 60 | filters = names.compactMap { name -> CIFilter? in 61 | let filter = CIFilter(name: name) 62 | filter?.name = name 63 | return filter 64 | } 65 | } 66 | } 67 | 68 | // MARK: - Metal 69 | 70 | extension SCNNode { 71 | func addCloudEffect() { 72 | let program = SCNProgram() 73 | program.vertexFunctionName = "cloudVertex" 74 | program.fragmentFunctionName = "cloudFragment" 75 | program.isOpaque = false 76 | geometry?.firstMaterial?.program = program 77 | 78 | guard let noiseImage = UIImage(named: "art.scnassets/softNoise.png"), 79 | let intImage = UIImage(named: "art.scnassets/sharpNoise.png") else { 80 | return 81 | } 82 | let noiseImageProperty = SCNMaterialProperty(contents: noiseImage) 83 | geometry?.firstMaterial?.setValue(noiseImageProperty, forKey: "noiseTexture") 84 | let intImageProperty = SCNMaterialProperty(contents: intImage) 85 | geometry?.firstMaterial?.setValue(intImageProperty, forKey: "interferenceTexture") 86 | } 87 | 88 | func addTrianglesEffect() { 89 | let program = SCNProgram() 90 | program.vertexFunctionName = "trianglequiltVertex" 91 | program.fragmentFunctionName = "trianglequiltFragment" 92 | 93 | let gradientMaterial = SCNMaterial() 94 | gradientMaterial.program = program 95 | gradientMaterial.specular.contents = UIColor.black 96 | gradientMaterial.locksAmbientWithDiffuse = true 97 | geometry?.materials = [gradientMaterial] 98 | geometry?.firstMaterial?.lightingModel = .constant 99 | } 100 | 101 | func addColorEffect(red: Float, green: Float, blue: Float, alpha: Float) { 102 | let program = SCNProgram() 103 | program.vertexFunctionName = "colorVertex" 104 | program.fragmentFunctionName = "colorFragment" 105 | program.isOpaque = false 106 | geometry?.firstMaterial?.program = program 107 | 108 | struct FragmentUniforms { 109 | var red: Float = 1.0 110 | var green: Float = 1.0 111 | var blue: Float = 1.0 112 | var alpha: Float = 1.0 113 | } 114 | 115 | var uniforms = FragmentUniforms() 116 | uniforms.red = red/255.0 117 | uniforms.green = green/255.0 118 | uniforms.blue = blue/255.0 119 | uniforms.alpha = alpha/255.0 120 | 121 | program.handleBinding(ofBufferNamed: "uniforms", frequency: .perFrame) { (bufferStream, node, shadable, renderer) in 122 | bufferStream.writeBytes(&uniforms, count: MemoryLayout.stride) 123 | } 124 | } 125 | 126 | func addProgramWithTexture(_ name: String) { 127 | let program = SCNProgram() 128 | program.vertexFunctionName = "textureSamplerVertex" 129 | program.fragmentFunctionName = "textureSamplerFragment" 130 | geometry?.firstMaterial?.program = program 131 | 132 | guard let customTextureImage = UIImage(named: name) else { 133 | return 134 | } 135 | let materialProperty = SCNMaterialProperty(contents: customTextureImage) 136 | geometry?.firstMaterial?.setValue(materialProperty, forKey: "customTexture") 137 | } 138 | 139 | func addProgramWithTexture(_ name: String, key: String, brightness: Float) { 140 | let program = SCNProgram() 141 | program.vertexFunctionName = "textureBrightnessSamplerVertex" 142 | program.fragmentFunctionName = "textureBrightnessSamplerFragment" 143 | geometry?.firstMaterial?.program = program 144 | 145 | addMaterialWithTexture(name, for: key) 146 | 147 | struct FragmentUniforms { 148 | var brightness: Float = 1.0 149 | } 150 | 151 | var uniforms = FragmentUniforms() 152 | uniforms.brightness = brightness 153 | 154 | program.handleBinding(ofBufferNamed: "uniforms", frequency: .perFrame) { (bufferStream, node, shadable, renderer) in 155 | bufferStream.writeBytes(&uniforms, count: MemoryLayout.stride) 156 | } 157 | } 158 | 159 | func addMaterialWithTexture(_ name: String, for key: String) { 160 | guard let customTextureImage = UIImage(named: name) else { 161 | return 162 | } 163 | let materialProperty = SCNMaterialProperty(contents: customTextureImage) 164 | geometry?.firstMaterial?.setValue(materialProperty, forKey: key) 165 | } 166 | 167 | func addGaussianBlurEffect(_ name: String, blur: Float) { 168 | let program = SCNProgram() 169 | program.vertexFunctionName = "gaussianBlurVertex" 170 | program.fragmentFunctionName = "gaussianBlurFragment" 171 | geometry?.firstMaterial?.program = program 172 | 173 | guard let customTextureImage = UIImage(named: name) else { 174 | return 175 | } 176 | let materialProperty = SCNMaterialProperty(contents: customTextureImage) 177 | geometry?.firstMaterial?.setValue(materialProperty, forKey: "customTexture") 178 | 179 | struct FragmentUniforms { 180 | var blur: Float = 1.0 181 | } 182 | 183 | var uniforms = FragmentUniforms() 184 | uniforms.blur = blur 185 | 186 | program.handleBinding(ofBufferNamed: "uniforms", frequency: .perFrame) { (bufferStream, node, shadable, renderer) in 187 | bufferStream.writeBytes(&uniforms, count: MemoryLayout.stride) 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /SwiftShaders/UI/SwiftShadersScene.swift: -------------------------------------------------------------------------------- 1 | import SceneKit 2 | 3 | final class SwiftShadersScene: SCNScene { 4 | required init(coder aDecoder: NSCoder) { 5 | fatalError("init(coder:) has not been implemented") 6 | } 7 | 8 | override init () { 9 | super.init() 10 | 11 | rootNode.castsShadow = false 12 | 13 | // Content Node 14 | 15 | let contentNode = SCNNode() 16 | contentNode.castsShadow = false 17 | rootNode.addChildNode(contentNode) 18 | 19 | // Bum Mapping 20 | // Resources: http://planetpixelemporium.com/earth.html 21 | 22 | let earthGeometry = SCNSphere(radius: 1) 23 | //earthGeometry.firstMaterial?.diffuse.contents = UIImage(named: "diffuse") 24 | earthGeometry.firstMaterial?.normal.contents = UIImage(named: "normal") 25 | earthGeometry.firstMaterial?.lightingModel = .lambert 26 | let earthNode = SCNNode(geometry: earthGeometry) 27 | earthNode.castsShadow = false 28 | earthNode.position = SCNVector3(0, 4, 0) 29 | contentNode.addChildNode(earthNode) 30 | 31 | let lightNode = SCNNode() 32 | lightNode.castsShadow = false 33 | lightNode.light = SCNLight() 34 | lightNode.light?.type = .omni 35 | lightNode.light?.color = UIColor.white 36 | lightNode.position = SCNVector3(0, 4, 10) 37 | lightNode.look(at: earthNode.position) 38 | contentNode.addChildNode(lightNode) 39 | 40 | // First Line: SceneKit Shaders 41 | 42 | contentNode.addChildNode(SCNNode(position: SCNVector3(-6, 2, 0), shaders: [.surface: simpleHalfColoringFromScreenSizeSurfaceShader])) 43 | 44 | contentNode.addChildNode(SCNNode(position: SCNVector3(-4, 2, 0), shaders: [.surface: simpleHalfColoringSurfaceShader])) 45 | 46 | let borgNode = SCNNode(position: SCNVector3(-2, 2, 0), shaders: [.fragment: appearingFragmentShader]) 47 | borgNode.addMaterialWithTexture("noiseTexture", for: "noiseTexture") 48 | borgNode.addRevealAnimation() 49 | contentNode.addChildNode(borgNode) 50 | 51 | contentNode.addChildNode(SCNNode(position: SCNVector3(0, 2, 0), shaders: [.surface: coloringSurfaceShader])) 52 | 53 | contentNode.addChildNode(SCNNode(position: SCNVector3(2, 2, 0), shaders: [.geometry: twistingGeometryShader])) 54 | 55 | contentNode.addChildNode(SCNNode(position: SCNVector3(4, 2, 0), shaders: [.fragment: coloringFragmentShader])) 56 | 57 | let discoveringCubeNode = SCNNode(position: SCNVector3(6, 2, 0), shaders: [.fragment: discoveringFragment]) 58 | discoveringCubeNode.addTexture("customTexture") 59 | contentNode.addChildNode(discoveringCubeNode) 60 | 61 | let gaussianBlurredCubeNode = SCNNode(position: SCNVector3(8, 2, 0), shaders: [.fragment: gaussianFragment]) 62 | gaussianBlurredCubeNode.addTexture("customTexture") 63 | contentNode.addChildNode(gaussianBlurredCubeNode) 64 | 65 | let wavedCubeNode = SCNNode(position: SCNVector3(10, 2, 0), shaders: [.fragment: wavingFragment]) 66 | wavedCubeNode.addTexture("customTexture") 67 | contentNode.addChildNode(wavedCubeNode) 68 | 69 | let dropEffectCubeNode = SCNNode(position: SCNVector3(12, 2, 0), shaders: [.fragment: dropEffectFragment]) 70 | contentNode.addChildNode(dropEffectCubeNode) 71 | 72 | // Second Line: Filters 73 | 74 | let texturedCubeNode = SCNNode(position: SCNVector3(-6, 0, 0), shaders: [:]) 75 | texturedCubeNode.addTexture("customTexture") 76 | contentNode.addChildNode(texturedCubeNode) 77 | 78 | let blurredCubeNode = SCNNode(position: SCNVector3(-4, 0, 0), shaders: [:]) 79 | blurredCubeNode.addTexture("customTexture") 80 | blurredCubeNode.addFilters(["CIGaussianBlur"]) 81 | contentNode.addChildNode(blurredCubeNode) 82 | 83 | let bloomCubeNode = SCNNode(position: SCNVector3(-2, 0, 0), shaders: [:]) 84 | bloomCubeNode.addTexture("customTexture") 85 | bloomCubeNode.addFilters(["CIBloom"]) 86 | contentNode.addChildNode(bloomCubeNode) 87 | 88 | let pixellatedCubeNode = SCNNode(position: SCNVector3(0, 0, 0), shaders: [:]) 89 | pixellatedCubeNode.addTexture("customTexture") 90 | pixellatedCubeNode.addFilters(["CIPixellate"]) 91 | contentNode.addChildNode(pixellatedCubeNode) 92 | 93 | let kaleidoscopeCubeNode = SCNNode(position: SCNVector3(2, 0, 0), shaders: [:]) 94 | kaleidoscopeCubeNode.addTexture("customTexture") 95 | kaleidoscopeCubeNode.addFilters(["CIThermal"]) 96 | contentNode.addChildNode(kaleidoscopeCubeNode) 97 | 98 | // Third Line: Metal Shaders 99 | 100 | // let geometry = SCNGeometry.lineThrough(points: [SCNVector3(-10, 0,0), SCNVector3(-10, 10, 0), SCNVector3(10, 10, 0), SCNVector3(10, 0, 0)], 101 | // width: 20, 102 | // closed: false, 103 | // color: UIColor.red.cgColor) 104 | // let node = SCNNode(geometry: geometry) 105 | // contentNode.addChildNode(node) 106 | 107 | let textureSamplerNode = SCNNode(position: SCNVector3(-6, -2, 0), shaders: [:]) 108 | textureSamplerNode.addProgramWithTexture("customTexture") 109 | contentNode.addChildNode(textureSamplerNode) 110 | 111 | let blurNode = SCNNode(position: SCNVector3(-4, -2, 0), shaders: [:]) 112 | blurNode.addGaussianBlurEffect("customTexture", blur: 4) 113 | contentNode.addChildNode(blurNode) 114 | 115 | let textureBrightnessSamplerNode = SCNNode(position: SCNVector3(-2, -2, 0), shaders: [:]) 116 | textureBrightnessSamplerNode.addProgramWithTexture("customTexture", key: "customTexture", brightness: 2.0) 117 | contentNode.addChildNode(textureBrightnessSamplerNode) 118 | 119 | let cloudNode = SCNNode(position: SCNVector3(0, -2, 0), shaders: [:]) 120 | cloudNode.addCloudEffect() 121 | contentNode.addChildNode(cloudNode) 122 | 123 | let trianglesNode = SCNNode(position: SCNVector3(2, -2, 0), shaders: [:]) 124 | trianglesNode.addTrianglesEffect() 125 | contentNode.addChildNode(trianglesNode) 126 | 127 | let colorNode = SCNNode(position: SCNVector3(4, -2, 0), shaders: [:]) 128 | colorNode.addColorEffect(red: 40, green: 80, blue: 160, alpha: 128) 129 | contentNode.addChildNode(colorNode) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /SwiftShaders/art.scnassets/sharpNoise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/art.scnassets/sharpNoise.png -------------------------------------------------------------------------------- /SwiftShaders/art.scnassets/ship.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/art.scnassets/ship.scn -------------------------------------------------------------------------------- /SwiftShaders/art.scnassets/softNoise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malayli/SwiftShaders/17d9cbc81b0c8df9d054ffb8f78ab6d01ea1f21d/SwiftShaders/art.scnassets/softNoise.png -------------------------------------------------------------------------------- /SwiftShaders/pixelate.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | passes 6 | 7 | 8 | pixelate_scene 9 | 10 | draw 11 | DRAW_SCENE 12 | inputs 13 | 14 | outputs 15 | 16 | color 17 | color_scene 18 | 19 | colorStates 20 | 21 | clear 22 | 23 | clearColor 24 | sceneBackground 25 | 26 | 27 | 28 | resample_pixelation 29 | 30 | draw 31 | DRAW_QUAD 32 | program 33 | doesntexist 34 | metalVertexShader 35 | pixelate_pass_through_vertex 36 | metalFragmentShader 37 | pixelate_pass_through_fragment 38 | inputs 39 | 40 | colorSampler 41 | color_scene 42 | 43 | outputs 44 | 45 | color 46 | COLOR 47 | 48 | 49 | 50 | 51 | 52 | sequence 53 | 54 | pixelate_scene 55 | resample_pixelation 56 | 57 | targets 58 | 59 | color_scene 60 | 61 | type 62 | color 63 | size 64 | 75x75 65 | 66 | 67 | symbols 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /SwiftShadersTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftShadersTests/SwiftShadersTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftShadersTests.swift 3 | // SwiftShadersTests 4 | // 5 | // Created by Malik Alayli on 06/10/2019. 6 | // Copyright © 2019 MalikAlayli. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftShaders 11 | 12 | class SwiftShadersTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /SwiftShadersUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftShadersUITests/SwiftShadersUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftShadersUITests.swift 3 | // SwiftShadersUITests 4 | // 5 | // Created by Malik Alayli on 06/10/2019. 6 | // Copyright © 2019 MalikAlayli. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class SwiftShadersUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testExample() { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use recording to get started writing UI tests. 32 | // Use XCTAssert and related functions to verify your tests produce the correct results. 33 | } 34 | 35 | func testLaunchPerformance() { 36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 37 | // This measures how long it takes to launch your application. 38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 39 | XCUIApplication().launch() 40 | } 41 | } 42 | } 43 | } 44 | --------------------------------------------------------------------------------