├── .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 | 
6 | 
7 | 
8 | 
9 |
10 | 
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 |
--------------------------------------------------------------------------------