├── .gitignore ├── README.md ├── SceneKit-MeshLine.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── SceneKit-MeshLine_Demo-macOS ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── GameViewController.swift ├── Info.plist ├── SceneKit_MeshLine_Demo_macOS.entitlements └── art.scnassets │ ├── ship.scn │ └── texture.png ├── SceneKit-MeshLine_Demo_iOS ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── GameViewController.swift └── Info.plist ├── SceneKit_MeshLine ├── Info.plist └── SceneKit_MeshLine.h └── Sources ├── Functions.metal ├── MeshLine.swift └── MeshLineMaterial.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 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | .DS_Store 70 | Swift-ImGui-iOS Example/SFMono-Regular.ttf 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MeshLine for SceneKit [wip] 2 | 3 | Super rough SceneKit port of [@thespite](https://twitter.com/thespite)'s [THREE.MeshLine](https://github.com/spite/THREE.MeshLine/) 4 | 5 | ![](http://c.mnmly.com/mLMy/MeshLineDemo.gif) 6 | 7 | ![](http://c.mnmly.com/mUck/mesh-line-other.gif) 8 | 9 | ### Usage 10 | 11 | ```swift 12 | let node = MeshLineNode() 13 | let material = MeshLineMaterial() 14 | var _vertices: [SCNVector3] = [] 15 | for i in 0..<360 { 16 | let phase = Float(i) / Float(360) 17 | let x = CGFloat(i) / 300.0; 18 | let y = CGFloat(sin( phase * 20.0 ) * 0.1); 19 | let z = CGFloat(cos( phase * 30.0) * 1.0 ); 20 | _vertices.append(SCNVector3(x: x, y: y, z: z)) 21 | } 22 | node.setVertices(vertices: _vertices) 23 | node.geometry?.materials = [material] 24 | ``` 25 | 26 | *Since it's in Metal, it only works on iOS Device and macOS* 27 | -------------------------------------------------------------------------------- /SceneKit-MeshLine.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 99234F881F5F6B520006ABAD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99234F871F5F6B520006ABAD /* AppDelegate.swift */; }; 11 | 99234F8C1F5F6B520006ABAD /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99234F8B1F5F6B520006ABAD /* GameViewController.swift */; }; 12 | 99234F8F1F5F6B520006ABAD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 99234F8D1F5F6B520006ABAD /* Main.storyboard */; }; 13 | 99234F911F5F6B520006ABAD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 99234F901F5F6B520006ABAD /* Assets.xcassets */; }; 14 | 99234F941F5F6B520006ABAD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 99234F921F5F6B520006ABAD /* LaunchScreen.storyboard */; }; 15 | 992814181F5F6FBF00B8CA9D /* MeshLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99234F7B1F5F64F40006ABAD /* MeshLine.swift */; }; 16 | 992814191F5F6FBF00B8CA9D /* MeshLineMaterial.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99234F7C1F5F64F40006ABAD /* MeshLineMaterial.swift */; }; 17 | 9928141A1F5F6FBF00B8CA9D /* Functions.metal in Sources */ = {isa = PBXBuildFile; fileRef = 99234F7D1F5F64F40006ABAD /* Functions.metal */; }; 18 | 992814221F5F701F00B8CA9D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 992814211F5F701F00B8CA9D /* AppDelegate.swift */; }; 19 | 992814241F5F701F00B8CA9D /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 992814231F5F701F00B8CA9D /* GameViewController.swift */; }; 20 | 992814261F5F701F00B8CA9D /* art.scnassets in Resources */ = {isa = PBXBuildFile; fileRef = 992814251F5F701F00B8CA9D /* art.scnassets */; }; 21 | 992814281F5F701F00B8CA9D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 992814271F5F701F00B8CA9D /* Assets.xcassets */; }; 22 | 9928142B1F5F701F00B8CA9D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 992814291F5F701F00B8CA9D /* Main.storyboard */; }; 23 | 992814311F5F702F00B8CA9D /* MeshLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99234F7B1F5F64F40006ABAD /* MeshLine.swift */; }; 24 | 992814321F5F702F00B8CA9D /* MeshLineMaterial.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99234F7C1F5F64F40006ABAD /* MeshLineMaterial.swift */; }; 25 | 992814331F5F702F00B8CA9D /* Functions.metal in Sources */ = {isa = PBXBuildFile; fileRef = 99234F7D1F5F64F40006ABAD /* Functions.metal */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXCopyFilesBuildPhase section */ 29 | 992814131F5F6DE000B8CA9D /* Embed Frameworks */ = { 30 | isa = PBXCopyFilesBuildPhase; 31 | buildActionMask = 2147483647; 32 | dstPath = ""; 33 | dstSubfolderSpec = 10; 34 | files = ( 35 | ); 36 | name = "Embed Frameworks"; 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXCopyFilesBuildPhase section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 99234F7B1F5F64F40006ABAD /* MeshLine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLine.swift; sourceTree = ""; }; 43 | 99234F7C1F5F64F40006ABAD /* MeshLineMaterial.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLineMaterial.swift; sourceTree = ""; }; 44 | 99234F7D1F5F64F40006ABAD /* Functions.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Functions.metal; sourceTree = ""; }; 45 | 99234F851F5F6B510006ABAD /* SceneKit-MeshLine_iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SceneKit-MeshLine_iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 99234F871F5F6B520006ABAD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | 99234F8B1F5F6B520006ABAD /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 48 | 99234F8E1F5F6B520006ABAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 49 | 99234F901F5F6B520006ABAD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 99234F931F5F6B520006ABAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | 99234F951F5F6B520006ABAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | 992814091F5F6DE000B8CA9D /* SceneKit_MeshLine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneKit_MeshLine.h; sourceTree = ""; }; 53 | 9928140A1F5F6DE000B8CA9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 54 | 9928141F1F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SceneKit-MeshLine_Demo-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 992814211F5F701F00B8CA9D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 56 | 992814231F5F701F00B8CA9D /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; }; 57 | 992814251F5F701F00B8CA9D /* art.scnassets */ = {isa = PBXFileReference; lastKnownFileType = wrapper.scnassets; path = art.scnassets; sourceTree = ""; }; 58 | 992814271F5F701F00B8CA9D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 59 | 9928142A1F5F701F00B8CA9D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | 9928142C1F5F701F00B8CA9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 9928142D1F5F701F00B8CA9D /* SceneKit_MeshLine_Demo_macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SceneKit_MeshLine_Demo_macOS.entitlements; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | 99234F821F5F6B510006ABAD /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | 9928141C1F5F701F00B8CA9D /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | /* End PBXFrameworksBuildPhase section */ 80 | 81 | /* Begin PBXGroup section */ 82 | 99234F5C1F5F64DF0006ABAD = { 83 | isa = PBXGroup; 84 | children = ( 85 | 99234F7A1F5F64F40006ABAD /* Sources */, 86 | 99234F861F5F6B520006ABAD /* SceneKit-MeshLine_Demo_iOS */, 87 | 992814081F5F6DE000B8CA9D /* SceneKit_MeshLine */, 88 | 992814201F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS */, 89 | 99234F661F5F64DF0006ABAD /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | 99234F661F5F64DF0006ABAD /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 99234F851F5F6B510006ABAD /* SceneKit-MeshLine_iOS.app */, 97 | 9928141F1F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 99234F7A1F5F64F40006ABAD /* Sources */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 99234F7B1F5F64F40006ABAD /* MeshLine.swift */, 106 | 99234F7C1F5F64F40006ABAD /* MeshLineMaterial.swift */, 107 | 99234F7D1F5F64F40006ABAD /* Functions.metal */, 108 | ); 109 | path = Sources; 110 | sourceTree = ""; 111 | }; 112 | 99234F861F5F6B520006ABAD /* SceneKit-MeshLine_Demo_iOS */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 99234F871F5F6B520006ABAD /* AppDelegate.swift */, 116 | 99234F8B1F5F6B520006ABAD /* GameViewController.swift */, 117 | 99234F8D1F5F6B520006ABAD /* Main.storyboard */, 118 | 99234F901F5F6B520006ABAD /* Assets.xcassets */, 119 | 99234F921F5F6B520006ABAD /* LaunchScreen.storyboard */, 120 | 99234F951F5F6B520006ABAD /* Info.plist */, 121 | ); 122 | path = "SceneKit-MeshLine_Demo_iOS"; 123 | sourceTree = ""; 124 | }; 125 | 992814081F5F6DE000B8CA9D /* SceneKit_MeshLine */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 992814091F5F6DE000B8CA9D /* SceneKit_MeshLine.h */, 129 | 9928140A1F5F6DE000B8CA9D /* Info.plist */, 130 | ); 131 | path = SceneKit_MeshLine; 132 | sourceTree = ""; 133 | }; 134 | 992814201F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 992814211F5F701F00B8CA9D /* AppDelegate.swift */, 138 | 992814231F5F701F00B8CA9D /* GameViewController.swift */, 139 | 992814251F5F701F00B8CA9D /* art.scnassets */, 140 | 992814271F5F701F00B8CA9D /* Assets.xcassets */, 141 | 992814291F5F701F00B8CA9D /* Main.storyboard */, 142 | 9928142C1F5F701F00B8CA9D /* Info.plist */, 143 | 9928142D1F5F701F00B8CA9D /* SceneKit_MeshLine_Demo_macOS.entitlements */, 144 | ); 145 | path = "SceneKit-MeshLine_Demo-macOS"; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXNativeTarget section */ 151 | 99234F841F5F6B510006ABAD /* SceneKit-MeshLine_iOS */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 99234F961F5F6B520006ABAD /* Build configuration list for PBXNativeTarget "SceneKit-MeshLine_iOS" */; 154 | buildPhases = ( 155 | 99234F811F5F6B510006ABAD /* Sources */, 156 | 99234F821F5F6B510006ABAD /* Frameworks */, 157 | 99234F831F5F6B510006ABAD /* Resources */, 158 | 992814131F5F6DE000B8CA9D /* Embed Frameworks */, 159 | ); 160 | buildRules = ( 161 | ); 162 | dependencies = ( 163 | ); 164 | name = "SceneKit-MeshLine_iOS"; 165 | productName = "SceneKit-MeshLine_Demo_iOS"; 166 | productReference = 99234F851F5F6B510006ABAD /* SceneKit-MeshLine_iOS.app */; 167 | productType = "com.apple.product-type.application"; 168 | }; 169 | 9928141E1F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS */ = { 170 | isa = PBXNativeTarget; 171 | buildConfigurationList = 9928142E1F5F701F00B8CA9D /* Build configuration list for PBXNativeTarget "SceneKit-MeshLine_Demo-macOS" */; 172 | buildPhases = ( 173 | 9928141B1F5F701F00B8CA9D /* Sources */, 174 | 9928141C1F5F701F00B8CA9D /* Frameworks */, 175 | 9928141D1F5F701F00B8CA9D /* Resources */, 176 | ); 177 | buildRules = ( 178 | ); 179 | dependencies = ( 180 | ); 181 | name = "SceneKit-MeshLine_Demo-macOS"; 182 | productName = "SceneKit-MeshLine_Demo-macOS"; 183 | productReference = 9928141F1F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS.app */; 184 | productType = "com.apple.product-type.application"; 185 | }; 186 | /* End PBXNativeTarget section */ 187 | 188 | /* Begin PBXProject section */ 189 | 99234F5D1F5F64DF0006ABAD /* Project object */ = { 190 | isa = PBXProject; 191 | attributes = { 192 | LastSwiftUpdateCheck = 0900; 193 | LastUpgradeCheck = 0900; 194 | ORGANIZATIONNAME = "Hiroaki Yamane"; 195 | TargetAttributes = { 196 | 99234F841F5F6B510006ABAD = { 197 | CreatedOnToolsVersion = 9.0; 198 | ProvisioningStyle = Automatic; 199 | }; 200 | 9928141E1F5F701F00B8CA9D = { 201 | CreatedOnToolsVersion = 9.0; 202 | ProvisioningStyle = Automatic; 203 | }; 204 | }; 205 | }; 206 | buildConfigurationList = 99234F601F5F64DF0006ABAD /* Build configuration list for PBXProject "SceneKit-MeshLine" */; 207 | compatibilityVersion = "Xcode 8.0"; 208 | developmentRegion = en; 209 | hasScannedForEncodings = 0; 210 | knownRegions = ( 211 | en, 212 | Base, 213 | ); 214 | mainGroup = 99234F5C1F5F64DF0006ABAD; 215 | productRefGroup = 99234F661F5F64DF0006ABAD /* Products */; 216 | projectDirPath = ""; 217 | projectRoot = ""; 218 | targets = ( 219 | 99234F841F5F6B510006ABAD /* SceneKit-MeshLine_iOS */, 220 | 9928141E1F5F701F00B8CA9D /* SceneKit-MeshLine_Demo-macOS */, 221 | ); 222 | }; 223 | /* End PBXProject section */ 224 | 225 | /* Begin PBXResourcesBuildPhase section */ 226 | 99234F831F5F6B510006ABAD /* Resources */ = { 227 | isa = PBXResourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | 99234F941F5F6B520006ABAD /* LaunchScreen.storyboard in Resources */, 231 | 99234F911F5F6B520006ABAD /* Assets.xcassets in Resources */, 232 | 99234F8F1F5F6B520006ABAD /* Main.storyboard in Resources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | 9928141D1F5F701F00B8CA9D /* Resources */ = { 237 | isa = PBXResourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 9928142B1F5F701F00B8CA9D /* Main.storyboard in Resources */, 241 | 992814281F5F701F00B8CA9D /* Assets.xcassets in Resources */, 242 | 992814261F5F701F00B8CA9D /* art.scnassets in Resources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | /* End PBXResourcesBuildPhase section */ 247 | 248 | /* Begin PBXSourcesBuildPhase section */ 249 | 99234F811F5F6B510006ABAD /* Sources */ = { 250 | isa = PBXSourcesBuildPhase; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | 99234F8C1F5F6B520006ABAD /* GameViewController.swift in Sources */, 254 | 992814191F5F6FBF00B8CA9D /* MeshLineMaterial.swift in Sources */, 255 | 9928141A1F5F6FBF00B8CA9D /* Functions.metal in Sources */, 256 | 99234F881F5F6B520006ABAD /* AppDelegate.swift in Sources */, 257 | 992814181F5F6FBF00B8CA9D /* MeshLine.swift in Sources */, 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | 9928141B1F5F701F00B8CA9D /* Sources */ = { 262 | isa = PBXSourcesBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | 992814241F5F701F00B8CA9D /* GameViewController.swift in Sources */, 266 | 992814321F5F702F00B8CA9D /* MeshLineMaterial.swift in Sources */, 267 | 992814331F5F702F00B8CA9D /* Functions.metal in Sources */, 268 | 992814221F5F701F00B8CA9D /* AppDelegate.swift in Sources */, 269 | 992814311F5F702F00B8CA9D /* MeshLine.swift in Sources */, 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | }; 273 | /* End PBXSourcesBuildPhase section */ 274 | 275 | /* Begin PBXVariantGroup section */ 276 | 99234F8D1F5F6B520006ABAD /* Main.storyboard */ = { 277 | isa = PBXVariantGroup; 278 | children = ( 279 | 99234F8E1F5F6B520006ABAD /* Base */, 280 | ); 281 | name = Main.storyboard; 282 | sourceTree = ""; 283 | }; 284 | 99234F921F5F6B520006ABAD /* LaunchScreen.storyboard */ = { 285 | isa = PBXVariantGroup; 286 | children = ( 287 | 99234F931F5F6B520006ABAD /* Base */, 288 | ); 289 | name = LaunchScreen.storyboard; 290 | sourceTree = ""; 291 | }; 292 | 992814291F5F701F00B8CA9D /* Main.storyboard */ = { 293 | isa = PBXVariantGroup; 294 | children = ( 295 | 9928142A1F5F701F00B8CA9D /* Base */, 296 | ); 297 | name = Main.storyboard; 298 | sourceTree = ""; 299 | }; 300 | /* End PBXVariantGroup section */ 301 | 302 | /* Begin XCBuildConfiguration section */ 303 | 99234F751F5F64DF0006ABAD /* Debug */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | CLANG_ANALYZER_NONNULL = YES; 308 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 309 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 310 | CLANG_CXX_LIBRARY = "libc++"; 311 | CLANG_ENABLE_MODULES = YES; 312 | CLANG_ENABLE_OBJC_ARC = YES; 313 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 314 | CLANG_WARN_BOOL_CONVERSION = YES; 315 | CLANG_WARN_COMMA = YES; 316 | CLANG_WARN_CONSTANT_CONVERSION = YES; 317 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 318 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INFINITE_RECURSION = YES; 322 | CLANG_WARN_INT_CONVERSION = YES; 323 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 325 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 326 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 327 | CLANG_WARN_STRICT_PROTOTYPES = YES; 328 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 329 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 330 | CLANG_WARN_UNREACHABLE_CODE = YES; 331 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 332 | CODE_SIGN_IDENTITY = "Mac Developer"; 333 | COPY_PHASE_STRIP = NO; 334 | DEBUG_INFORMATION_FORMAT = dwarf; 335 | ENABLE_STRICT_OBJC_MSGSEND = YES; 336 | ENABLE_TESTABILITY = YES; 337 | GCC_C_LANGUAGE_STANDARD = gnu11; 338 | GCC_DYNAMIC_NO_PIC = NO; 339 | GCC_NO_COMMON_BLOCKS = YES; 340 | GCC_OPTIMIZATION_LEVEL = 0; 341 | GCC_PREPROCESSOR_DEFINITIONS = ( 342 | "DEBUG=1", 343 | "$(inherited)", 344 | ); 345 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 346 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 347 | GCC_WARN_UNDECLARED_SELECTOR = YES; 348 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 349 | GCC_WARN_UNUSED_FUNCTION = YES; 350 | GCC_WARN_UNUSED_VARIABLE = YES; 351 | MACOSX_DEPLOYMENT_TARGET = 10.13; 352 | MTL_ENABLE_DEBUG_INFO = YES; 353 | ONLY_ACTIVE_ARCH = YES; 354 | SDKROOT = macosx; 355 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 356 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 357 | }; 358 | name = Debug; 359 | }; 360 | 99234F761F5F64DF0006ABAD /* Release */ = { 361 | isa = XCBuildConfiguration; 362 | buildSettings = { 363 | ALWAYS_SEARCH_USER_PATHS = NO; 364 | CLANG_ANALYZER_NONNULL = YES; 365 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_COMMA = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 375 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INFINITE_RECURSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 384 | CLANG_WARN_STRICT_PROTOTYPES = YES; 385 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 386 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 387 | CLANG_WARN_UNREACHABLE_CODE = YES; 388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 389 | CODE_SIGN_IDENTITY = "Mac Developer"; 390 | COPY_PHASE_STRIP = NO; 391 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 392 | ENABLE_NS_ASSERTIONS = NO; 393 | ENABLE_STRICT_OBJC_MSGSEND = YES; 394 | GCC_C_LANGUAGE_STANDARD = gnu11; 395 | GCC_NO_COMMON_BLOCKS = YES; 396 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 397 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 398 | GCC_WARN_UNDECLARED_SELECTOR = YES; 399 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 400 | GCC_WARN_UNUSED_FUNCTION = YES; 401 | GCC_WARN_UNUSED_VARIABLE = YES; 402 | MACOSX_DEPLOYMENT_TARGET = 10.13; 403 | MTL_ENABLE_DEBUG_INFO = NO; 404 | SDKROOT = macosx; 405 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 406 | }; 407 | name = Release; 408 | }; 409 | 99234F971F5F6B520006ABAD /* Debug */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CODE_SIGN_IDENTITY = "iPhone Developer"; 414 | CODE_SIGN_STYLE = Automatic; 415 | DEVELOPMENT_TEAM = GP3ES2Y53G; 416 | INFOPLIST_FILE = "SceneKit-MeshLine_Demo_iOS/Info.plist"; 417 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 418 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 419 | PRODUCT_BUNDLE_IDENTIFIER = "com.mnmly.SceneKit-MeshLine-Demo-iOS"; 420 | PRODUCT_NAME = "$(TARGET_NAME)"; 421 | SDKROOT = iphoneos; 422 | SWIFT_VERSION = 4.0; 423 | TARGETED_DEVICE_FAMILY = "1,2"; 424 | }; 425 | name = Debug; 426 | }; 427 | 99234F981F5F6B520006ABAD /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | buildSettings = { 430 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 431 | CODE_SIGN_IDENTITY = "iPhone Developer"; 432 | CODE_SIGN_STYLE = Automatic; 433 | DEVELOPMENT_TEAM = GP3ES2Y53G; 434 | INFOPLIST_FILE = "SceneKit-MeshLine_Demo_iOS/Info.plist"; 435 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = "com.mnmly.SceneKit-MeshLine-Demo-iOS"; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SDKROOT = iphoneos; 440 | SWIFT_VERSION = 4.0; 441 | TARGETED_DEVICE_FAMILY = "1,2"; 442 | VALIDATE_PRODUCT = YES; 443 | }; 444 | name = Release; 445 | }; 446 | 9928142F1F5F701F00B8CA9D /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 450 | CODE_SIGN_ENTITLEMENTS = "SceneKit-MeshLine_Demo-macOS/SceneKit_MeshLine_Demo_macOS.entitlements"; 451 | CODE_SIGN_STYLE = Automatic; 452 | COMBINE_HIDPI_IMAGES = YES; 453 | DEVELOPMENT_TEAM = GP3ES2Y53G; 454 | INFOPLIST_FILE = "SceneKit-MeshLine_Demo-macOS/Info.plist"; 455 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 456 | MACOSX_DEPLOYMENT_TARGET = 10.12; 457 | PRODUCT_BUNDLE_IDENTIFIER = "com.mnmly.SceneKit-MeshLine-Demo-macOS"; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | SWIFT_VERSION = 4.0; 460 | }; 461 | name = Debug; 462 | }; 463 | 992814301F5F701F00B8CA9D /* Release */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 467 | CODE_SIGN_ENTITLEMENTS = "SceneKit-MeshLine_Demo-macOS/SceneKit_MeshLine_Demo_macOS.entitlements"; 468 | CODE_SIGN_STYLE = Automatic; 469 | COMBINE_HIDPI_IMAGES = YES; 470 | DEVELOPMENT_TEAM = GP3ES2Y53G; 471 | INFOPLIST_FILE = "SceneKit-MeshLine_Demo-macOS/Info.plist"; 472 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 473 | MACOSX_DEPLOYMENT_TARGET = 10.12; 474 | PRODUCT_BUNDLE_IDENTIFIER = "com.mnmly.SceneKit-MeshLine-Demo-macOS"; 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | SWIFT_VERSION = 4.0; 477 | }; 478 | name = Release; 479 | }; 480 | /* End XCBuildConfiguration section */ 481 | 482 | /* Begin XCConfigurationList section */ 483 | 99234F601F5F64DF0006ABAD /* Build configuration list for PBXProject "SceneKit-MeshLine" */ = { 484 | isa = XCConfigurationList; 485 | buildConfigurations = ( 486 | 99234F751F5F64DF0006ABAD /* Debug */, 487 | 99234F761F5F64DF0006ABAD /* Release */, 488 | ); 489 | defaultConfigurationIsVisible = 0; 490 | defaultConfigurationName = Release; 491 | }; 492 | 99234F961F5F6B520006ABAD /* Build configuration list for PBXNativeTarget "SceneKit-MeshLine_iOS" */ = { 493 | isa = XCConfigurationList; 494 | buildConfigurations = ( 495 | 99234F971F5F6B520006ABAD /* Debug */, 496 | 99234F981F5F6B520006ABAD /* Release */, 497 | ); 498 | defaultConfigurationIsVisible = 0; 499 | defaultConfigurationName = Release; 500 | }; 501 | 9928142E1F5F701F00B8CA9D /* Build configuration list for PBXNativeTarget "SceneKit-MeshLine_Demo-macOS" */ = { 502 | isa = XCConfigurationList; 503 | buildConfigurations = ( 504 | 9928142F1F5F701F00B8CA9D /* Debug */, 505 | 992814301F5F701F00B8CA9D /* Release */, 506 | ); 507 | defaultConfigurationIsVisible = 0; 508 | defaultConfigurationName = Release; 509 | }; 510 | /* End XCConfigurationList section */ 511 | }; 512 | rootObject = 99234F5D1F5F64DF0006ABAD /* Project object */; 513 | } 514 | -------------------------------------------------------------------------------- /SceneKit-MeshLine.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SceneKit-MeshLine_Demo-macOS 4 | // 5 | // Created by Hiroaki Yamane on 9/5/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | func applicationDidFinishLaunching(_ aNotification: Notification) { 15 | // Insert code here to initialize your application 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/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 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | Default 531 | 532 | 533 | 534 | 535 | 536 | 537 | Left to Right 538 | 539 | 540 | 541 | 542 | 543 | 544 | Right to Left 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | Default 556 | 557 | 558 | 559 | 560 | 561 | 562 | Left to Right 563 | 564 | 565 | 566 | 567 | 568 | 569 | Right to Left 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // SceneKit-MeshLine_Demo 4 | // 5 | // Created by Hiroaki Yamane on 9/5/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | 9 | import SceneKit 10 | import QuartzCore 11 | 12 | class GameViewController: NSViewController { 13 | 14 | var lineNodes: [MeshLineNode]! = [] 15 | var lineMaterials: [MeshLineMaterial]! = [] 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | // create a new scene 21 | let scene = SCNScene() 22 | 23 | for i in 0..<5 { 24 | let node = MeshLineNode() 25 | let material = MeshLineMaterial() 26 | material.uniform.lineWidth = 2.0 //Float(i * 2 + 3) 27 | material.update() 28 | var _vertices: [SCNVector3] = [] 29 | for i in 0..<360 { 30 | let phase = Float(i) / Float(360) 31 | let x = (CGFloat(i) / 300.0 - 0.5) * 100.0; 32 | let y = CGFloat(sin( phase * 20.0 ) * 5.1); 33 | let z = CGFloat(cos( phase * 30.0) * 1.0 ); 34 | _vertices.append(SCNVector3(x: x, y: y, z: z)) 35 | } 36 | node.setVertices(vertices: _vertices) 37 | node.geometry?.materials = [material] 38 | node.position.y += (CGFloat(i) * 1.0 - 2.5) * 10.0 39 | lineNodes.append(node) 40 | lineMaterials.append(material) 41 | scene.rootNode.addChildNode(node) 42 | } 43 | 44 | 45 | // create and add a camera to the scene 46 | let cameraNode = SCNNode() 47 | cameraNode.camera = SCNCamera() 48 | scene.rootNode.addChildNode(cameraNode) 49 | 50 | // place the camera 51 | cameraNode.position = SCNVector3(x: 0, y: 0, z: 15) 52 | 53 | // create and add a light to the scene 54 | let lightNode = SCNNode() 55 | lightNode.light = SCNLight() 56 | lightNode.light!.type = .omni 57 | lightNode.position = SCNVector3(x: 0, y: 10, z: 10) 58 | scene.rootNode.addChildNode(lightNode) 59 | 60 | // create and add an ambient light to the scene 61 | let ambientLightNode = SCNNode() 62 | ambientLightNode.light = SCNLight() 63 | ambientLightNode.light!.type = .ambient 64 | ambientLightNode.light!.color = NSColor.darkGray 65 | scene.rootNode.addChildNode(ambientLightNode) 66 | ambientLightNode.runAction(SCNAction.repeat(SCNAction.moveBy(x: 10.0, y: 0, z: 0, duration: 0.1), count: 1000)) 67 | 68 | 69 | // retrieve the SCNView 70 | let scnView = self.view as! SCNView 71 | 72 | // set the scene to the view 73 | scnView.scene = scene 74 | 75 | // allows the user to manipulate the camera 76 | scnView.allowsCameraControl = true 77 | 78 | // show statistics such as fps and timing information 79 | scnView.showsStatistics = true 80 | 81 | // configure the view 82 | scnView.backgroundColor = NSColor.black 83 | 84 | // Add a click gesture recognizer 85 | let clickGesture = NSClickGestureRecognizer(target: self, action: #selector(handleClick(_:))) 86 | var gestureRecognizers = scnView.gestureRecognizers 87 | gestureRecognizers.insert(clickGesture, at: 0) 88 | scnView.gestureRecognizers = gestureRecognizers 89 | scnView.delegate = self 90 | scnView.loops = true 91 | NotificationCenter.default.addObserver(self, selector: #selector(onResize), name: NSWindow.didResizeNotification, object: nil) 92 | } 93 | 94 | 95 | @objc 96 | func handleClick(_ gestureRecognizer: NSGestureRecognizer) { 97 | // retrieve the SCNView 98 | let scnView = self.view as! SCNView 99 | 100 | // check what nodes are clicked 101 | let p = gestureRecognizer.location(in: scnView) 102 | let hitResults = scnView.hitTest(p, options: [:]) 103 | // check that we clicked on at least one object 104 | if hitResults.count > 0 { 105 | // retrieved the first clicked object 106 | let result = hitResults[0] 107 | 108 | // get its material 109 | let material = result.node.geometry!.firstMaterial! 110 | 111 | // highlight it 112 | SCNTransaction.begin() 113 | SCNTransaction.animationDuration = 0.5 114 | 115 | // on completion - unhighlight 116 | SCNTransaction.completionBlock = { 117 | SCNTransaction.begin() 118 | SCNTransaction.animationDuration = 0.5 119 | 120 | material.emission.contents = NSColor.black 121 | 122 | SCNTransaction.commit() 123 | } 124 | 125 | material.emission.contents = NSColor.red 126 | 127 | SCNTransaction.commit() 128 | } 129 | } 130 | 131 | @objc func onResize() { 132 | lineMaterials.forEach { (material) in 133 | material.uniform.resolution = float2(Float(self.view.bounds.size.width), Float(self.view.bounds.size.height)) 134 | material.update() 135 | } 136 | } 137 | } 138 | 139 | 140 | extension GameViewController: SCNSceneRendererDelegate { 141 | func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { 142 | 143 | lineNodes.enumerated().forEach { (arg) in 144 | let (index, node) = arg 145 | lineMaterials[index].uniform.lineWidth = (sin( Float(time) * 1.0 ) + 1.0) / 2.0 * Float(index + 1) / 5.0 * 2.0; 146 | lineMaterials[index].update() 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2017 Hiroaki Yamane. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/SceneKit_MeshLine_Demo_macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/art.scnassets/ship.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmly/SceneKit-MeshLine/7e708a10b08fe4f7e1f867bf9dbefbd60a962d7c/SceneKit-MeshLine_Demo-macOS/art.scnassets/ship.scn -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo-macOS/art.scnassets/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mnmly/SceneKit-MeshLine/7e708a10b08fe4f7e1f867bf9dbefbd60a962d7c/SceneKit-MeshLine_Demo-macOS/art.scnassets/texture.png -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo_iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SceneKit-MeshLine_Demo_iOS 4 | // 5 | // Created by Hiroaki Yamane on 9/5/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo_iOS/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 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo_iOS/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 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo_iOS/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 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo_iOS/GameViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GameViewController.swift 3 | // SceneKit-MeshLine_Demo_iOS 4 | // 5 | // Created by Hiroaki Yamane on 9/5/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import QuartzCore 11 | import SceneKit 12 | 13 | 14 | class GameViewController: UIViewController { 15 | 16 | var lineNodes: [MeshLineNode]! = [] 17 | var lineMaterials: [MeshLineMaterial]! = [] 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | 22 | // create a new scene 23 | let scene = SCNScene() 24 | for i in 0..<5 { 25 | let node = MeshLineNode() 26 | let material = MeshLineMaterial() 27 | material.uniform.lineWidth = Float(i * 2 + 3) 28 | material.uniform.resolution = float2(Float(view.bounds.width), Float(view.bounds.height)) 29 | material.update() 30 | var _vertices: [SCNVector3] = [] 31 | for i in 0..<360 { 32 | let phase = Float(i) / Float(360) 33 | let x: Float = (Float(i) / 300.0 - 0.5) * 4.0; 34 | let y: Float = Float(sin( phase * 20.0 ) * 0.1); 35 | let z: Float = Float(cos( phase * 30.0) * 1.0 ); 36 | _vertices.append(SCNVector3(x: x, y: y, z: z)) 37 | } 38 | node.setVertices(vertices: _vertices) 39 | node.geometry?.materials = [material] 40 | node.position.y += Float(i) * 1.0 - 2.5 41 | lineNodes.append(node) 42 | lineMaterials.append(material) 43 | scene.rootNode.addChildNode(node) 44 | } 45 | 46 | // create and add a camera to the scene 47 | let cameraNode = SCNNode() 48 | cameraNode.camera = SCNCamera() 49 | scene.rootNode.addChildNode(cameraNode) 50 | 51 | // place the camera 52 | cameraNode.position = SCNVector3(x: 0, y: 0, z: 15) 53 | 54 | // create and add a light to the scene 55 | let lightNode = SCNNode() 56 | lightNode.light = SCNLight() 57 | lightNode.light!.type = .omni 58 | lightNode.position = SCNVector3(x: 0, y: 10, z: 10) 59 | scene.rootNode.addChildNode(lightNode) 60 | 61 | // create and add an ambient light to the scene 62 | let ambientLightNode = SCNNode() 63 | ambientLightNode.light = SCNLight() 64 | ambientLightNode.light!.type = .ambient 65 | ambientLightNode.light!.color = UIColor.darkGray 66 | scene.rootNode.addChildNode(ambientLightNode) 67 | 68 | // retrieve the SCNView 69 | let scnView = self.view as! SCNView 70 | 71 | // set the scene to the view 72 | scnView.scene = scene 73 | 74 | // allows the user to manipulate the camera 75 | scnView.allowsCameraControl = true 76 | 77 | // show statistics such as fps and timing information 78 | scnView.showsStatistics = true 79 | 80 | // configure the view 81 | scnView.backgroundColor = UIColor.black 82 | 83 | // add a tap gesture recognizer 84 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:))) 85 | scnView.addGestureRecognizer(tapGesture) 86 | 87 | scnView.delegate = self 88 | scnView.loops = true 89 | } 90 | 91 | @objc 92 | func handleTap(_ gestureRecognize: UIGestureRecognizer) { 93 | // retrieve the SCNView 94 | let scnView = self.view as! SCNView 95 | 96 | // check what nodes are tapped 97 | let p = gestureRecognize.location(in: scnView) 98 | let hitResults = scnView.hitTest(p, options: [:]) 99 | // check that we clicked on at least one object 100 | if hitResults.count > 0 { 101 | // retrieved the first clicked object 102 | let result = hitResults[0] 103 | 104 | // get its material 105 | let material = result.node.geometry!.firstMaterial! 106 | 107 | // highlight it 108 | SCNTransaction.begin() 109 | SCNTransaction.animationDuration = 0.5 110 | 111 | // on completion - unhighlight 112 | SCNTransaction.completionBlock = { 113 | SCNTransaction.begin() 114 | SCNTransaction.animationDuration = 0.5 115 | 116 | material.emission.contents = UIColor.black 117 | 118 | SCNTransaction.commit() 119 | } 120 | 121 | material.emission.contents = UIColor.red 122 | 123 | SCNTransaction.commit() 124 | } 125 | } 126 | 127 | override var shouldAutorotate: Bool { 128 | return true 129 | } 130 | 131 | override var prefersStatusBarHidden: Bool { 132 | return true 133 | } 134 | 135 | override var supportedInterfaceOrientations: UIInterfaceOrientationMask { 136 | if UIDevice.current.userInterfaceIdiom == .phone { 137 | return .allButUpsideDown 138 | } else { 139 | return .all 140 | } 141 | } 142 | 143 | override func didReceiveMemoryWarning() { 144 | super.didReceiveMemoryWarning() 145 | // Release any cached data, images, etc that aren't in use. 146 | } 147 | } 148 | 149 | // MARK: SCNSceneRenderDelegate 150 | 151 | extension GameViewController: SCNSceneRendererDelegate { 152 | func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { 153 | lineNodes.enumerated().forEach { (index, node) in 154 | var _vertices: [SCNVector3] = [] 155 | for i in 0..<360 { 156 | let phase = Float(i) / Float(360) 157 | let x = (Float(i) / 300.0 - 0.5) * 4.0; 158 | let y = Float(sin( phase * 50.0 + Float(time) * 5.2) * 0.1); 159 | let z = Float(cos( phase * 5.0 + Float(time) * 5.0 ) * 0.5 ); 160 | _vertices.append(SCNVector3(x: x, y: y, z: z)) 161 | } 162 | lineNodes[index].setVertices(vertices: _vertices) 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /SceneKit-MeshLine_Demo_iOS/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 | APPL 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 | -------------------------------------------------------------------------------- /SceneKit_MeshLine/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /SceneKit_MeshLine/SceneKit_MeshLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // SceneKit_MeshLine.h 3 | // SceneKit_MeshLine 4 | // 5 | // Created by Hiroaki Yamane on 9/5/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SceneKit_MeshLine. 12 | FOUNDATION_EXPORT double SceneKit_MeshLineVersionNumber; 13 | 14 | //! Project version string for SceneKit_MeshLine. 15 | FOUNDATION_EXPORT const unsigned char SceneKit_MeshLineVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sources/Functions.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Functions.metal 3 | // MeshLine 4 | // 5 | // Created by Hiroaki Yamane on 9/3/17. 6 | // 7 | // Ported to .metal from https://github.com/spite/THREE.MeshLine/blob/master/src/THREE.MeshLine.js 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer{ 14 | float4x4 modelTransform; 15 | float4x4 inverseModelTransform; 16 | float4x4 modelViewTransform; 17 | float4x4 inverseModelViewTransform; 18 | float4x4 normalTransform; // This is the inverseTransposeModelViewTransform, need for normal transformation 19 | float4x4 modelViewProjectionTransform; 20 | float4x4 inverseModelViewProjectionTransform; 21 | float2x3 boundingBox; 22 | float2x3 worldBoundingBox; 23 | }; 24 | 25 | 26 | struct CustomBuffer { 27 | float4 position [[ attribute(SCNVertexSemanticPosition) ]]; 28 | float3 normal [[ attribute(SCNVertexSemanticNormal) ]]; 29 | float4 tangent [[ attribute(SCNVertexSemanticTangent) ]]; 30 | // Misc misc [[ attribute(SCNVertexSemanticBoneWeights) ]]; 31 | float3 misc [[ attribute(SCNVertexSemanticBoneWeights) ]]; 32 | float2 texcoords [[attribute(SCNVertexSemanticTexcoord0)]]; 33 | }; 34 | 35 | struct VertexOut { 36 | float4 position [[ position ]]; 37 | float pointSize [[ point_size ]]; 38 | float4 color; 39 | float2 texcoords; 40 | float counters; 41 | 42 | }; 43 | 44 | /* Uniforms */ 45 | struct Uniform { 46 | float lineWidth; 47 | float useMap; 48 | float useAlphaMap; 49 | float4 color; 50 | float opacity; 51 | float2 resolution; 52 | float sizeAttenuation; 53 | float near; 54 | float far; 55 | float2 dashArray; 56 | float useDash; 57 | float visibility; 58 | float alphaTest; 59 | float2 repeating; 60 | }; 61 | 62 | float2 fixPos( float4 i, float _aspect ) { 63 | float2 res = i.xy / i.w; 64 | res.x *= _aspect; 65 | return res; 66 | } 67 | 68 | 69 | struct Misc { 70 | float counter; 71 | float side; 72 | float width; 73 | }; 74 | 75 | 76 | vertex VertexOut vertexFunction(CustomBuffer _geometry [[ stage_in ]], 77 | constant SCNSceneBuffer& scn_frame [[ buffer(0) ]], 78 | constant NodeBuffer& scn_node [[ buffer(1) ]], 79 | constant Uniform &uniforms [[ buffer(2) ]] ) { 80 | 81 | // expanding misc info 82 | float width = _geometry.misc.z; 83 | float side = _geometry.misc.y; 84 | float counters = _geometry.misc.x; 85 | 86 | float sizeAttenuation = uniforms.sizeAttenuation; 87 | float2 resolution = uniforms.resolution; 88 | 89 | float aspect = resolution.x / resolution.y; 90 | float pixelWidthRatio = 1.0 / (resolution.x * scn_frame.projectionTransform[0][0]); 91 | float4x4 m = scn_frame.projectionTransform * scn_node.modelViewTransform; 92 | float4 finalPosition = m * _geometry.position; 93 | float4 prevPos = m * float4( _geometry.normal, 1.0 ); 94 | float4 nextPos = m * float4( _geometry.tangent.xyz, 1.0 ); 95 | 96 | float2 currentP = fixPos(finalPosition, aspect); 97 | float2 prevP = fixPos(prevPos, aspect); 98 | float2 nextP = fixPos(nextPos, aspect); 99 | 100 | float pixelWidth = finalPosition.w * pixelWidthRatio; 101 | float w = 1.8 * pixelWidth * uniforms.lineWidth * width; 102 | 103 | if ( sizeAttenuation == 1.0 ) { 104 | w = 1.8 * uniforms.lineWidth * width; 105 | } 106 | 107 | float2 dir; 108 | if ( nextP.x == currentP.x && nextP.y == currentP.y ) { dir = normalize( currentP - prevP ); } 109 | else if ( prevP.x == currentP.x && prevP.y == currentP.y ) { dir = normalize( nextP - currentP ); } 110 | else { 111 | float2 dir1 = normalize( currentP - prevP ); 112 | float2 dir2 = normalize( nextP - currentP ); 113 | dir = normalize( dir1 + dir2 ); 114 | // float2 perp = float2( -dir1.y, dir1.x ); 115 | // float2 miter = float2( -dir.y, dir.x ); 116 | //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width ); 117 | } 118 | 119 | // float2 normal = ( cross( float3( dir, 0 ), float3( 0, 0, 1 ) ) ).xy; 120 | float2 normal = float2(-dir.y, dir.x); 121 | normal.x /= aspect; 122 | normal *= .5 * w; 123 | 124 | float4 offset = float4( normal * side, 0.0, 1.0 ); 125 | finalPosition.xy += offset.xy; 126 | VertexOut out; 127 | out.position = finalPosition; 128 | out.color = float4( uniforms.color.xyz, uniforms.opacity ); 129 | out.texcoords = _geometry.texcoords; 130 | out.counters = counters; 131 | out.pointSize = 3.0; 132 | return out; 133 | }; 134 | 135 | 136 | 137 | fragment half4 fragmentFunction(VertexOut in [[ stage_in ]], 138 | constant Uniform &uniforms [[buffer(0)]]) { 139 | constexpr sampler defaultSampler; 140 | float4 color = in.color; 141 | // // if ( useMap == 1.0 ) { c *= uniforms.map.sample( defaultSampler, in.texcoords * uniforms.repeating ); } 142 | // // if ( useAlphaMap == 1.0 ) { c.a *= uniforms.alphaMap.sample( defaultSampler, in.texcoords * uniforms.repeating ).a; } 143 | // if ( color.a < uniforms.alphaTest ) { 144 | // discard_fragment(); 145 | // } 146 | // if ( uniforms.useDash == 1.0 ) {} 147 | // color.a *= step( in.counters, uniforms.visibility ); 148 | return half4(color); 149 | } 150 | -------------------------------------------------------------------------------- /Sources/MeshLine.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeshLine.swift 3 | // AnimationDemo 4 | // 5 | // Created by Hiroaki Yamane on 9/2/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | // Usage: 9 | // 10 | // ``` 11 | // let node = MeshLineNode() 12 | // let material = MeshLineMaterial() 13 | // var _vertices: [SCNVector3] = [] 14 | // for i in 0..<360 { 15 | // let phase = Float(i) / Float(360) 16 | // let x = CGFloat(i) / 300.0; 17 | // let y = CGFloat(sin( phase * 20.0 ) * 0.1); 18 | // let z = CGFloat(cos( phase * 30.0) * 1.0 ); 19 | // _vertices.append(SCNVector3(x: x, y: y, z: z)) 20 | // } 21 | // node.setVertices(vertices: _vertices) 22 | // node.geometry?.materials = [material] 23 | // ``` 24 | 25 | 26 | 27 | import SceneKit 28 | 29 | public class MeshLineNode: SCNNode { 30 | 31 | public struct Attribute { 32 | var position: float3! // => Semantic.vertex 33 | var previous: float3! // => Semantic.normal 34 | var next: float3! // => Semantic.tangent 35 | var uv: float2! // => Semantic.vertex 36 | var misc: float3! // => Semantic.boneWeights 37 | } 38 | 39 | public override init() { 40 | super.init() 41 | } 42 | 43 | public func setVertices(vertices: [SCNVector3]) { 44 | let mat = geometry?.firstMaterial 45 | process(vertices) 46 | if mat != nil { 47 | geometry?.firstMaterial = mat 48 | } 49 | } 50 | 51 | private func process(_ vertices: [SCNVector3]) { 52 | 53 | let l = vertices.count 54 | var indices: [UInt16] = [] 55 | var attributes: [Attribute] = [] 56 | 57 | vertices.enumerated().forEach { (arg) in 58 | 59 | let (index, v) = arg 60 | 61 | let c = Float(index) / Float(l) 62 | if l - 1 > index { 63 | let n = index * 2 64 | let t1: [UInt16] = [UInt16(n), UInt16(n + 1), UInt16(n + 2)] 65 | let t2: [UInt16] = [UInt16(n + 2), UInt16(n + 1), UInt16(n + 3)] 66 | 67 | indices.append(contentsOf: t1) 68 | indices.append(contentsOf: t2) 69 | } 70 | for k in 0..<2 { 71 | let position = v 72 | let counter = c 73 | let side = Float(k == 0 ? 1 : -1) 74 | let width: Float = 1 75 | let uv = float2(Float(Float(index) / Float(l - 1)), k == 0 ? 0 : 1) 76 | let previous = vertices[index == 0 ? (vertices[0] == vertices[l - 1] ? l - 2 : 0) : index] 77 | let next = vertices[index < l - 1 ? index + 1 : vertices[l - 1] == vertices[0] ? 1 : l - 1] 78 | 79 | attributes.append(Attribute(position: float3(Float(position.x), Float(position.y), Float(position.z)), 80 | previous: float3(Float(previous.x), Float(previous.y), Float(previous.z)), 81 | next: float3(Float(next.x), Float(next.y), Float(next.z)), 82 | uv: uv, 83 | misc: float3(counter, side, width))) 84 | } 85 | } 86 | 87 | let baseData = NSData.init(bytes: &attributes, length: attributes.count * MemoryLayout.stride) 88 | let data = Data(referencing: baseData) 89 | let count = l * 2 90 | let floatSize = MemoryLayout.size 91 | let stride = MemoryLayout.stride 92 | let indicesData_ = NSData.init(bytes: &indices, length: MemoryLayout.stride * indices.count) 93 | let indicesData = Data.init(referencing: indicesData_) 94 | let vertexSource = SCNGeometrySource(data: data, semantic: .vertex, vectorCount: count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: floatSize, dataOffset: 0, dataStride: stride) 95 | let previousSource = SCNGeometrySource(data: data, semantic: .normal, vectorCount: count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: floatSize, dataOffset: offsets[1], dataStride: stride) 96 | let nextSource = SCNGeometrySource(data: data, semantic: .tangent, vectorCount: count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: floatSize, dataOffset: offsets[2], dataStride: stride) 97 | let tcoordSource = SCNGeometrySource(data: data, semantic: .texcoord, vectorCount: count, usesFloatComponents: true, componentsPerVector: 2, bytesPerComponent: floatSize, dataOffset: offsets[3], dataStride: stride) 98 | let miscSource = SCNGeometrySource(data: data, semantic: .boneWeights, vectorCount: count, usesFloatComponents: true, componentsPerVector: 3, bytesPerComponent: floatSize, dataOffset: offsets[4], dataStride: stride) 99 | let indicesSource = SCNGeometryElement.init(data: indicesData, primitiveType: .triangles, primitiveCount: indices.count / 3, bytesPerIndex: MemoryLayout.size) 100 | let sources = [vertexSource, tcoordSource, previousSource, nextSource, miscSource] 101 | geometry = SCNGeometry.init(sources: sources, elements: [indicesSource]) 102 | } 103 | 104 | 105 | required public init?(coder aDecoder: NSCoder) { 106 | fatalError("init(coder:) has not been implemented") 107 | } 108 | 109 | // There's no `offsetOf` in swift. 110 | // Here, basically calculating the offsets by its position in address 111 | lazy var offsets: [Int] = { 112 | 113 | var a = Attribute() 114 | var offsets: [Int] = [] 115 | var start: Int = 0 116 | 117 | withUnsafePointer(to: &a) { 118 | start = Int(bitPattern: $0) 119 | } 120 | 121 | withUnsafePointer(to: &a.position) { 122 | offsets.append(Int(bitPattern: $0) - start) 123 | } 124 | withUnsafePointer(to: &a.previous) { 125 | offsets.append(Int(bitPattern: $0) - start) 126 | } 127 | withUnsafePointer(to: &a.next) { 128 | offsets.append(Int(bitPattern: $0) - start) 129 | } 130 | withUnsafePointer(to: &a.uv) { 131 | offsets.append(Int(bitPattern: $0) - start) 132 | } 133 | withUnsafePointer(to: &a.misc) { 134 | offsets.append(Int(bitPattern: $0) - start) 135 | } 136 | 137 | return offsets 138 | }() 139 | } 140 | 141 | extension SCNVector3 { 142 | static func ==(lhs: SCNVector3, rhs: SCNVector3) -> Bool { 143 | return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Sources/MeshLineMaterial.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MeshLineMaterial.swift 3 | // AnimationDemo 4 | // 5 | // Created by Hiroaki Yamane on 9/5/17. 6 | // Copyright © 2017 Hiroaki Yamane. All rights reserved. 7 | // 8 | 9 | import SceneKit 10 | 11 | public class MeshLineMaterial: SCNMaterial { 12 | 13 | // TODO: texture props. 14 | 15 | public var uniform: Uniform! { 16 | didSet { 17 | needsUpdate = true 18 | } 19 | } 20 | 21 | public var needsUpdate = true 22 | 23 | public struct Uniform { 24 | public var lineWidth: Float = 1.0 25 | // map 26 | public var useMap: Float = 0 27 | public var useAlphaMap: Float = 0 28 | // alphaMap 29 | public var color: float4 = float4(1, 1, 1, 1) 30 | public var opacity: Float = 1.0 31 | public var resolution: float2 = float2(1, 1) 32 | public var sizeAttenuation: Float = 1 33 | public var near: Float = 1 34 | public var far: Float = 1 35 | public var dashArray: float2 = float2(0, 0) 36 | public var useDash: Float = 0 37 | public var visibility: Float = 1 38 | public var alphaTest: Float = 0 39 | public var repeating: float2 = float2(1, 1) 40 | } 41 | 42 | 43 | public override init() { 44 | super.init() 45 | uniform = Uniform() 46 | program = setupProgram() 47 | isDoubleSided = true 48 | update() 49 | } 50 | 51 | private func setupProgram() -> SCNProgram { 52 | let program = SCNProgram() 53 | program.vertexFunctionName = "vertexFunction" 54 | program.fragmentFunctionName = "fragmentFunction" 55 | return program 56 | } 57 | 58 | public func update() { 59 | if needsUpdate { 60 | let uniformData = Data.init(bytes: &uniform, count: MemoryLayout.stride) 61 | setValue(uniformData, forKey: "uniforms") 62 | } 63 | needsUpdate = false 64 | } 65 | 66 | 67 | required public init?(coder aDecoder: NSCoder) { 68 | fatalError("init(coder:) has not been implemented") 69 | } 70 | } 71 | --------------------------------------------------------------------------------