├── .gitignore ├── ModelPicker.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── swiftpm │ └── Package.resolved ├── ModelPicker ├── Model │ └── Model.swift ├── Support │ ├── 3DModels │ │ ├── biplane.usdz │ │ ├── drummer.usdz │ │ ├── fender.usdz │ │ ├── gramophone.usdz │ │ ├── retrotv.usdz │ │ ├── robot.usdz │ │ ├── teapot.usdz │ │ ├── wateringcan.usdz │ │ └── wheelbarrow.usdz │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── biplane.imageset │ │ │ ├── Contents.json │ │ │ └── biplane.jpg │ │ ├── drummer.imageset │ │ │ ├── Contents.json │ │ │ └── drummer.jpg │ │ ├── fender.imageset │ │ │ ├── Contents.json │ │ │ └── fender.jpg │ │ ├── gramophone.imageset │ │ │ ├── Contents.json │ │ │ └── gramophone.jpg │ │ ├── retrotv.imageset │ │ │ ├── Contents.json │ │ │ └── retrotv.jpg │ │ ├── robot.imageset │ │ │ ├── Contents.json │ │ │ └── robot.jpg │ │ ├── teapot.imageset │ │ │ ├── Contents.json │ │ │ └── teapot.jpg │ │ ├── wateringcan.imageset │ │ │ ├── Contents.json │ │ │ └── wateringcan.jpg │ │ └── wheelbarrow.imageset │ │ │ ├── Contents.json │ │ │ └── wheelbarrow.jpg │ ├── Info.plist │ ├── ModelPickerApp.swift │ └── Preview Content │ │ └── Preview Assets.xcassets │ │ └── Contents.json └── View │ ├── ARViewRepresentable.swift │ ├── ContentView.swift │ ├── CustomARView.swift │ ├── ModelPickerView.swift │ └── PlacementButtonView.swift ├── README.md └── modelPickerDemo.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /ModelPicker.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 53; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 07D53AEA24CB177B00195440 /* ModelPickerApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07D53AE924CB177B00195440 /* ModelPickerApp.swift */; }; 11 | 07D53AEC24CB177B00195440 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07D53AEB24CB177B00195440 /* ContentView.swift */; }; 12 | 07D53AEE24CB177B00195440 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 07D53AED24CB177B00195440 /* Assets.xcassets */; }; 13 | 07D53AF124CB177B00195440 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 07D53AF024CB177B00195440 /* Preview Assets.xcassets */; }; 14 | 07D53AFD24CB180B00195440 /* ARViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07D53AFC24CB180B00195440 /* ARViewRepresentable.swift */; }; 15 | 07D53B0A24CB1F0200195440 /* wheelbarrow.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0124CB1F0200195440 /* wheelbarrow.usdz */; }; 16 | 07D53B0B24CB1F0200195440 /* drummer.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0224CB1F0200195440 /* drummer.usdz */; }; 17 | 07D53B0C24CB1F0200195440 /* teapot.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0324CB1F0200195440 /* teapot.usdz */; }; 18 | 07D53B0D24CB1F0200195440 /* robot.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0424CB1F0200195440 /* robot.usdz */; }; 19 | 07D53B0E24CB1F0200195440 /* wateringcan.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0524CB1F0200195440 /* wateringcan.usdz */; }; 20 | 07D53B0F24CB1F0200195440 /* fender.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0624CB1F0200195440 /* fender.usdz */; }; 21 | 07D53B1024CB1F0200195440 /* retrotv.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0724CB1F0200195440 /* retrotv.usdz */; }; 22 | 07D53B1124CB1F0200195440 /* gramophone.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0824CB1F0200195440 /* gramophone.usdz */; }; 23 | 07D53B1224CB1F0200195440 /* biplane.usdz in Resources */ = {isa = PBXBuildFile; fileRef = 07D53B0924CB1F0200195440 /* biplane.usdz */; }; 24 | 07EF081024CB229D00556F10 /* ModelPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EF080F24CB229D00556F10 /* ModelPickerView.swift */; }; 25 | 07EF081224CB33CA00556F10 /* PlacementButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EF081124CB33CA00556F10 /* PlacementButtonView.swift */; }; 26 | 07EF081424CB675200556F10 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EF081324CB675200556F10 /* Model.swift */; }; 27 | 07EF081724CB6F0D00556F10 /* FocusEntity in Frameworks */ = {isa = PBXBuildFile; productRef = 07EF081624CB6F0D00556F10 /* FocusEntity */; }; 28 | 07EF081924CB6F4400556F10 /* CustomARView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07EF081824CB6F4400556F10 /* CustomARView.swift */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 07D53AE624CB177B00195440 /* ModelPicker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ModelPicker.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 07D53AE924CB177B00195440 /* ModelPickerApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelPickerApp.swift; sourceTree = ""; }; 34 | 07D53AEB24CB177B00195440 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 35 | 07D53AED24CB177B00195440 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 36 | 07D53AF024CB177B00195440 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 37 | 07D53AF224CB177B00195440 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 07D53AFC24CB180B00195440 /* ARViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ARViewRepresentable.swift; sourceTree = ""; }; 39 | 07D53B0124CB1F0200195440 /* wheelbarrow.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = wheelbarrow.usdz; sourceTree = ""; }; 40 | 07D53B0224CB1F0200195440 /* drummer.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = drummer.usdz; sourceTree = ""; }; 41 | 07D53B0324CB1F0200195440 /* teapot.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = teapot.usdz; sourceTree = ""; }; 42 | 07D53B0424CB1F0200195440 /* robot.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = robot.usdz; sourceTree = ""; }; 43 | 07D53B0524CB1F0200195440 /* wateringcan.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = wateringcan.usdz; sourceTree = ""; }; 44 | 07D53B0624CB1F0200195440 /* fender.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = fender.usdz; sourceTree = ""; }; 45 | 07D53B0724CB1F0200195440 /* retrotv.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = retrotv.usdz; sourceTree = ""; }; 46 | 07D53B0824CB1F0200195440 /* gramophone.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = gramophone.usdz; sourceTree = ""; }; 47 | 07D53B0924CB1F0200195440 /* biplane.usdz */ = {isa = PBXFileReference; lastKnownFileType = file.usdz; path = biplane.usdz; sourceTree = ""; }; 48 | 07EF080F24CB229D00556F10 /* ModelPickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelPickerView.swift; sourceTree = ""; }; 49 | 07EF081124CB33CA00556F10 /* PlacementButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlacementButtonView.swift; sourceTree = ""; }; 50 | 07EF081324CB675200556F10 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; 51 | 07EF081824CB6F4400556F10 /* CustomARView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomARView.swift; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 07D53AE324CB177B00195440 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 07EF081724CB6F0D00556F10 /* FocusEntity in Frameworks */, 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXFrameworksBuildPhase section */ 64 | 65 | /* Begin PBXGroup section */ 66 | 07D53ADD24CB177B00195440 = { 67 | isa = PBXGroup; 68 | children = ( 69 | 07D53AE824CB177B00195440 /* ModelPicker */, 70 | 07D53AE724CB177B00195440 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | 07D53AE724CB177B00195440 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 07D53AE624CB177B00195440 /* ModelPicker.app */, 78 | ); 79 | name = Products; 80 | sourceTree = ""; 81 | }; 82 | 07D53AE824CB177B00195440 /* ModelPicker */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 07D53AF824CB178000195440 /* Model */, 86 | 07D53AF924CB178700195440 /* View */, 87 | 07D53AFB24CB179900195440 /* Support */, 88 | ); 89 | path = ModelPicker; 90 | sourceTree = ""; 91 | }; 92 | 07D53AEF24CB177B00195440 /* Preview Content */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 07D53AF024CB177B00195440 /* Preview Assets.xcassets */, 96 | ); 97 | path = "Preview Content"; 98 | sourceTree = ""; 99 | }; 100 | 07D53AF824CB178000195440 /* Model */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | 07EF081324CB675200556F10 /* Model.swift */, 104 | ); 105 | path = Model; 106 | sourceTree = ""; 107 | }; 108 | 07D53AF924CB178700195440 /* View */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 07D53AFC24CB180B00195440 /* ARViewRepresentable.swift */, 112 | 07EF081824CB6F4400556F10 /* CustomARView.swift */, 113 | 07D53AEB24CB177B00195440 /* ContentView.swift */, 114 | 07EF080F24CB229D00556F10 /* ModelPickerView.swift */, 115 | 07EF081124CB33CA00556F10 /* PlacementButtonView.swift */, 116 | ); 117 | path = View; 118 | sourceTree = ""; 119 | }; 120 | 07D53AFB24CB179900195440 /* Support */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 07D53B0024CB1BA300195440 /* 3DModels */, 124 | 07D53AEF24CB177B00195440 /* Preview Content */, 125 | 07D53AED24CB177B00195440 /* Assets.xcassets */, 126 | 07D53AF224CB177B00195440 /* Info.plist */, 127 | 07D53AE924CB177B00195440 /* ModelPickerApp.swift */, 128 | ); 129 | path = Support; 130 | sourceTree = ""; 131 | }; 132 | 07D53B0024CB1BA300195440 /* 3DModels */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 07D53B0924CB1F0200195440 /* biplane.usdz */, 136 | 07D53B0224CB1F0200195440 /* drummer.usdz */, 137 | 07D53B0624CB1F0200195440 /* fender.usdz */, 138 | 07D53B0824CB1F0200195440 /* gramophone.usdz */, 139 | 07D53B0724CB1F0200195440 /* retrotv.usdz */, 140 | 07D53B0424CB1F0200195440 /* robot.usdz */, 141 | 07D53B0324CB1F0200195440 /* teapot.usdz */, 142 | 07D53B0524CB1F0200195440 /* wateringcan.usdz */, 143 | 07D53B0124CB1F0200195440 /* wheelbarrow.usdz */, 144 | ); 145 | path = 3DModels; 146 | sourceTree = ""; 147 | }; 148 | /* End PBXGroup section */ 149 | 150 | /* Begin PBXNativeTarget section */ 151 | 07D53AE524CB177B00195440 /* ModelPicker */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 07D53AF524CB177B00195440 /* Build configuration list for PBXNativeTarget "ModelPicker" */; 154 | buildPhases = ( 155 | 07D53AE224CB177B00195440 /* Sources */, 156 | 07D53AE324CB177B00195440 /* Frameworks */, 157 | 07D53AE424CB177B00195440 /* Resources */, 158 | ); 159 | buildRules = ( 160 | ); 161 | dependencies = ( 162 | ); 163 | name = ModelPicker; 164 | packageProductDependencies = ( 165 | 07EF081624CB6F0D00556F10 /* FocusEntity */, 166 | ); 167 | productName = ModelPicker; 168 | productReference = 07D53AE624CB177B00195440 /* ModelPicker.app */; 169 | productType = "com.apple.product-type.application"; 170 | }; 171 | /* End PBXNativeTarget section */ 172 | 173 | /* Begin PBXProject section */ 174 | 07D53ADE24CB177B00195440 /* Project object */ = { 175 | isa = PBXProject; 176 | attributes = { 177 | BuildIndependentTargetsInParallel = YES; 178 | LastSwiftUpdateCheck = 1200; 179 | LastUpgradeCheck = 1430; 180 | TargetAttributes = { 181 | 07D53AE524CB177B00195440 = { 182 | CreatedOnToolsVersion = 12.0; 183 | }; 184 | }; 185 | }; 186 | buildConfigurationList = 07D53AE124CB177B00195440 /* Build configuration list for PBXProject "ModelPicker" */; 187 | compatibilityVersion = "Xcode 9.3"; 188 | developmentRegion = en; 189 | hasScannedForEncodings = 0; 190 | knownRegions = ( 191 | en, 192 | Base, 193 | ); 194 | mainGroup = 07D53ADD24CB177B00195440; 195 | packageReferences = ( 196 | 07EF081524CB6F0D00556F10 /* XCRemoteSwiftPackageReference "FocusEntity" */, 197 | ); 198 | productRefGroup = 07D53AE724CB177B00195440 /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | 07D53AE524CB177B00195440 /* ModelPicker */, 203 | ); 204 | }; 205 | /* End PBXProject section */ 206 | 207 | /* Begin PBXResourcesBuildPhase section */ 208 | 07D53AE424CB177B00195440 /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 07D53B0B24CB1F0200195440 /* drummer.usdz in Resources */, 213 | 07D53AF124CB177B00195440 /* Preview Assets.xcassets in Resources */, 214 | 07D53AEE24CB177B00195440 /* Assets.xcassets in Resources */, 215 | 07D53B0F24CB1F0200195440 /* fender.usdz in Resources */, 216 | 07D53B0A24CB1F0200195440 /* wheelbarrow.usdz in Resources */, 217 | 07D53B0E24CB1F0200195440 /* wateringcan.usdz in Resources */, 218 | 07D53B0D24CB1F0200195440 /* robot.usdz in Resources */, 219 | 07D53B0C24CB1F0200195440 /* teapot.usdz in Resources */, 220 | 07D53B1024CB1F0200195440 /* retrotv.usdz in Resources */, 221 | 07D53B1124CB1F0200195440 /* gramophone.usdz in Resources */, 222 | 07D53B1224CB1F0200195440 /* biplane.usdz in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXResourcesBuildPhase section */ 227 | 228 | /* Begin PBXSourcesBuildPhase section */ 229 | 07D53AE224CB177B00195440 /* Sources */ = { 230 | isa = PBXSourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | 07D53AEC24CB177B00195440 /* ContentView.swift in Sources */, 234 | 07D53AEA24CB177B00195440 /* ModelPickerApp.swift in Sources */, 235 | 07EF081024CB229D00556F10 /* ModelPickerView.swift in Sources */, 236 | 07EF081424CB675200556F10 /* Model.swift in Sources */, 237 | 07D53AFD24CB180B00195440 /* ARViewRepresentable.swift in Sources */, 238 | 07EF081924CB6F4400556F10 /* CustomARView.swift in Sources */, 239 | 07EF081224CB33CA00556F10 /* PlacementButtonView.swift in Sources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | /* End PBXSourcesBuildPhase section */ 244 | 245 | /* Begin XCBuildConfiguration section */ 246 | 07D53AF324CB177B00195440 /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_NONNULL = YES; 251 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_ENABLE_OBJC_WEAK = YES; 257 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 258 | CLANG_WARN_BOOL_CONVERSION = YES; 259 | CLANG_WARN_COMMA = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 262 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 263 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INFINITE_RECURSION = YES; 267 | CLANG_WARN_INT_CONVERSION = YES; 268 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 269 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 270 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 271 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 272 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 273 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 274 | CLANG_WARN_STRICT_PROTOTYPES = YES; 275 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 276 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 277 | CLANG_WARN_UNREACHABLE_CODE = YES; 278 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 279 | COPY_PHASE_STRIP = NO; 280 | DEBUG_INFORMATION_FORMAT = dwarf; 281 | ENABLE_STRICT_OBJC_MSGSEND = YES; 282 | ENABLE_TESTABILITY = YES; 283 | GCC_C_LANGUAGE_STANDARD = gnu11; 284 | GCC_DYNAMIC_NO_PIC = NO; 285 | GCC_NO_COMMON_BLOCKS = YES; 286 | GCC_OPTIMIZATION_LEVEL = 0; 287 | GCC_PREPROCESSOR_DEFINITIONS = ( 288 | "DEBUG=1", 289 | "$(inherited)", 290 | ); 291 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 292 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 293 | GCC_WARN_UNDECLARED_SELECTOR = YES; 294 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 295 | GCC_WARN_UNUSED_FUNCTION = YES; 296 | GCC_WARN_UNUSED_VARIABLE = YES; 297 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 298 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 299 | MTL_FAST_MATH = YES; 300 | ONLY_ACTIVE_ARCH = YES; 301 | SDKROOT = iphoneos; 302 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 303 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 304 | }; 305 | name = Debug; 306 | }; 307 | 07D53AF424CB177B00195440 /* Release */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ALWAYS_SEARCH_USER_PATHS = NO; 311 | CLANG_ANALYZER_NONNULL = YES; 312 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 313 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 314 | CLANG_CXX_LIBRARY = "libc++"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_ENABLE_OBJC_WEAK = YES; 318 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 319 | CLANG_WARN_BOOL_CONVERSION = YES; 320 | CLANG_WARN_COMMA = YES; 321 | CLANG_WARN_CONSTANT_CONVERSION = YES; 322 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 323 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 324 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN_ENUM_CONVERSION = YES; 327 | CLANG_WARN_INFINITE_RECURSION = YES; 328 | CLANG_WARN_INT_CONVERSION = YES; 329 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 334 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 335 | CLANG_WARN_STRICT_PROTOTYPES = YES; 336 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 337 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 338 | CLANG_WARN_UNREACHABLE_CODE = YES; 339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 340 | COPY_PHASE_STRIP = NO; 341 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 342 | ENABLE_NS_ASSERTIONS = NO; 343 | ENABLE_STRICT_OBJC_MSGSEND = YES; 344 | GCC_C_LANGUAGE_STANDARD = gnu11; 345 | GCC_NO_COMMON_BLOCKS = YES; 346 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 347 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 348 | GCC_WARN_UNDECLARED_SELECTOR = YES; 349 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 350 | GCC_WARN_UNUSED_FUNCTION = YES; 351 | GCC_WARN_UNUSED_VARIABLE = YES; 352 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 353 | MTL_ENABLE_DEBUG_INFO = NO; 354 | MTL_FAST_MATH = YES; 355 | SDKROOT = iphoneos; 356 | SWIFT_COMPILATION_MODE = wholemodule; 357 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 358 | VALIDATE_PRODUCT = YES; 359 | }; 360 | name = Release; 361 | }; 362 | 07D53AF624CB177B00195440 /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 366 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 367 | CODE_SIGN_STYLE = Automatic; 368 | DEVELOPMENT_ASSET_PATHS = "\"ModelPicker/Support/Preview Content\""; 369 | DEVELOPMENT_TEAM = UKS358BH88; 370 | ENABLE_PREVIEWS = YES; 371 | INFOPLIST_FILE = ModelPicker/Support/Info.plist; 372 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 373 | LD_RUNPATH_SEARCH_PATHS = ( 374 | "$(inherited)", 375 | "@executable_path/Frameworks", 376 | ); 377 | PRODUCT_BUNDLE_IDENTIFIER = "com.backslash-f.ModelPicker"; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | SWIFT_VERSION = 5.0; 380 | TARGETED_DEVICE_FAMILY = "1,2"; 381 | }; 382 | name = Debug; 383 | }; 384 | 07D53AF724CB177B00195440 /* Release */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 388 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 389 | CODE_SIGN_STYLE = Automatic; 390 | DEVELOPMENT_ASSET_PATHS = "\"ModelPicker/Support/Preview Content\""; 391 | DEVELOPMENT_TEAM = UKS358BH88; 392 | ENABLE_PREVIEWS = YES; 393 | INFOPLIST_FILE = ModelPicker/Support/Info.plist; 394 | IPHONEOS_DEPLOYMENT_TARGET = 15.0; 395 | LD_RUNPATH_SEARCH_PATHS = ( 396 | "$(inherited)", 397 | "@executable_path/Frameworks", 398 | ); 399 | PRODUCT_BUNDLE_IDENTIFIER = "com.backslash-f.ModelPicker"; 400 | PRODUCT_NAME = "$(TARGET_NAME)"; 401 | SWIFT_VERSION = 5.0; 402 | TARGETED_DEVICE_FAMILY = "1,2"; 403 | }; 404 | name = Release; 405 | }; 406 | /* End XCBuildConfiguration section */ 407 | 408 | /* Begin XCConfigurationList section */ 409 | 07D53AE124CB177B00195440 /* Build configuration list for PBXProject "ModelPicker" */ = { 410 | isa = XCConfigurationList; 411 | buildConfigurations = ( 412 | 07D53AF324CB177B00195440 /* Debug */, 413 | 07D53AF424CB177B00195440 /* Release */, 414 | ); 415 | defaultConfigurationIsVisible = 0; 416 | defaultConfigurationName = Release; 417 | }; 418 | 07D53AF524CB177B00195440 /* Build configuration list for PBXNativeTarget "ModelPicker" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | 07D53AF624CB177B00195440 /* Debug */, 422 | 07D53AF724CB177B00195440 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | /* End XCConfigurationList section */ 428 | 429 | /* Begin XCRemoteSwiftPackageReference section */ 430 | 07EF081524CB6F0D00556F10 /* XCRemoteSwiftPackageReference "FocusEntity" */ = { 431 | isa = XCRemoteSwiftPackageReference; 432 | repositoryURL = "https://github.com/maxxfrazer/FocusEntity.git"; 433 | requirement = { 434 | kind = upToNextMajorVersion; 435 | minimumVersion = 2.0.1; 436 | }; 437 | }; 438 | /* End XCRemoteSwiftPackageReference section */ 439 | 440 | /* Begin XCSwiftPackageProductDependency section */ 441 | 07EF081624CB6F0D00556F10 /* FocusEntity */ = { 442 | isa = XCSwiftPackageProductDependency; 443 | package = 07EF081524CB6F0D00556F10 /* XCRemoteSwiftPackageReference "FocusEntity" */; 444 | productName = FocusEntity; 445 | }; 446 | /* End XCSwiftPackageProductDependency section */ 447 | }; 448 | rootObject = 07D53ADE24CB177B00195440 /* Project object */; 449 | } 450 | -------------------------------------------------------------------------------- /ModelPicker.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ModelPicker.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ModelPicker.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "FocusEntity", 6 | "repositoryURL": "https://github.com/maxxfrazer/FocusEntity.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "cf36b43d9a6ced6f572d6c60a3e3b825a20a210b", 10 | "version": "2.0.1" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /ModelPicker/Model/Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Model.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import SwiftUI 9 | import RealityKit 10 | import Combine 11 | 12 | class Model { 13 | 14 | // MARK: - Properties 15 | 16 | static let modelNames = [ 17 | "biplane", 18 | "drummer", 19 | "fender", 20 | "gramophone", 21 | "retrotv", 22 | "robot", 23 | "teapot", 24 | "wateringcan", 25 | "wheelbarrow" 26 | ] 27 | 28 | var modelName: String 29 | var image: UIImage 30 | var modelEntity: ModelEntity? 31 | 32 | private var cancellable: AnyCancellable? = nil 33 | 34 | // MARK: - Lifecycle 35 | 36 | init(modelName: String) { 37 | self.modelName = modelName 38 | self.image = UIImage(named: modelName)! 39 | 40 | let filename = modelName + ".usdz" 41 | self.cancellable = ModelEntity.loadModelAsync(named: filename) 42 | .sink { loadCompletion in 43 | if case .failure(let error) = loadCompletion { 44 | print("Unable to load modelEntity for: \(modelName)") 45 | print("Error: \(error)") 46 | } 47 | } receiveValue: { modelEntity in 48 | self.modelEntity = modelEntity 49 | self.modelEntity?.name = modelName 50 | print("Successfully loaded modelEntity for: \(modelName)") 51 | } 52 | } 53 | } 54 | 55 | // MARK: - Hashable 56 | 57 | extension Model: Hashable { 58 | func hash(into hasher: inout Hasher) { 59 | hasher.combine(modelName) 60 | } 61 | } 62 | 63 | // MARK: - Equatable 64 | 65 | extension Model: Equatable { 66 | static func == (lhs: Model, rhs: Model) -> Bool { 67 | lhs.modelName == rhs.modelName 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/biplane.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/biplane.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/drummer.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/drummer.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/fender.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/fender.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/gramophone.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/gramophone.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/retrotv.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/retrotv.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/robot.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/robot.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/teapot.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/teapot.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/wateringcan.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/wateringcan.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/3DModels/wheelbarrow.usdz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/3DModels/wheelbarrow.usdz -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/biplane.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "biplane.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/biplane.imageset/biplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/biplane.imageset/biplane.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/drummer.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "drummer.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/drummer.imageset/drummer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/drummer.imageset/drummer.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/fender.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "fender.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/fender.imageset/fender.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/fender.imageset/fender.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/gramophone.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "gramophone.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/gramophone.imageset/gramophone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/gramophone.imageset/gramophone.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/retrotv.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "retrotv.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/retrotv.imageset/retrotv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/retrotv.imageset/retrotv.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/robot.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "robot.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/robot.imageset/robot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/robot.imageset/robot.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/teapot.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "teapot.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/teapot.imageset/teapot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/teapot.imageset/teapot.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/wateringcan.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "wateringcan.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/wateringcan.imageset/wateringcan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/wateringcan.imageset/wateringcan.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/wheelbarrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "wheelbarrow.jpg", 5 | "idiom" : "universal" 6 | } 7 | ], 8 | "info" : { 9 | "author" : "xcode", 10 | "version" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ModelPicker/Support/Assets.xcassets/wheelbarrow.imageset/wheelbarrow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/ModelPicker/Support/Assets.xcassets/wheelbarrow.imageset/wheelbarrow.jpg -------------------------------------------------------------------------------- /ModelPicker/Support/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | RealityKit 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | 30 | UIApplicationSupportsIndirectInputEvents 31 | 32 | UILaunchScreen 33 | 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UISupportedInterfaceOrientations~ipad 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationPortraitUpsideDown 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ModelPicker/Support/ModelPickerApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelPickerApp.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct ModelPickerApp: App { 12 | 13 | // MARK: - Properties 14 | 15 | var body: some Scene { 16 | WindowGroup { 17 | ContentView() 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ModelPicker/Support/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ModelPicker/View/ARViewRepresentable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ARViewRepresentable.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import SwiftUI 9 | import RealityKit 10 | import ARKit 11 | 12 | struct ARViewRepresentable: UIViewRepresentable { 13 | 14 | // MARK: - Properties 15 | 16 | @Binding var modelConfirmedForPlacement: Model? 17 | @Binding var shouldRemoveAllModels: Bool 18 | 19 | // MARK: - UIViewRepresentable 20 | 21 | func makeUIView(context: Context) -> ARView { 22 | CustomARView(frame: .zero) 23 | } 24 | 25 | func updateUIView(_ uiView: ARView, context: Context) { 26 | if shouldRemoveAllModels { 27 | uiView.scene.anchors.forEach { anchor in 28 | anchor.children.forEach { entity in 29 | if Model.modelNames.contains(entity.name) { 30 | entity.removeFromParent() 31 | } 32 | } 33 | } 34 | DispatchQueue.main.async { 35 | shouldRemoveAllModels = false 36 | } 37 | } else if let model = modelConfirmedForPlacement, 38 | let modelEntity = model.modelEntity { 39 | print("Adding model to scene: \(model.modelName)") 40 | let anchorEntity = AnchorEntity(plane: .any) 41 | anchorEntity.addChild(modelEntity .clone(recursive: true)) 42 | uiView.scene.addAnchor(anchorEntity) 43 | DispatchQueue.main.async { 44 | modelConfirmedForPlacement = nil 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ModelPicker/View/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | 12 | // MARK: - Properties 13 | 14 | @State private var isPlacementEnabled = false 15 | @State private var selectedModel: Model? 16 | @State private var modelConfirmedForPlacement: Model? 17 | @State private var shouldRemoveAllModels = false 18 | 19 | private var models: [Model] = { 20 | let fileManager = FileManager.default 21 | guard let path = Bundle.main.resourcePath, 22 | let files = try? fileManager.contentsOfDirectory(atPath: path) else { 23 | return [] 24 | } 25 | return files 26 | .filter { $0.hasSuffix(".usdz") } 27 | .compactMap { $0.replacingOccurrences(of: ".usdz", with: "") } 28 | .compactMap { Model(modelName: $0 ) } 29 | }() 30 | 31 | // MARK: Body 32 | 33 | var body: some View { 34 | ZStack(alignment: .top) { 35 | Button(role: .destructive) { 36 | shouldRemoveAllModels = true 37 | } label: { 38 | HStack { 39 | Image(systemName: "trash") 40 | Text("Remove All") 41 | } 42 | } 43 | } 44 | 45 | ZStack(alignment: .bottom) { 46 | ARViewRepresentable( 47 | modelConfirmedForPlacement: $modelConfirmedForPlacement, 48 | shouldRemoveAllModels: $shouldRemoveAllModels 49 | ) 50 | 51 | if isPlacementEnabled { 52 | PlacementButtonView( 53 | isPlacementEnabled: $isPlacementEnabled, 54 | selectedModel: $selectedModel, 55 | modelConfirmedForPlacement: $modelConfirmedForPlacement 56 | ) 57 | } else { 58 | ModelPickerView( 59 | isPlacementEnabled: $isPlacementEnabled, 60 | selectedModel: $selectedModel, 61 | models: models 62 | ) 63 | } 64 | } 65 | } 66 | } 67 | 68 | // MARK: - Preview 69 | 70 | #if DEBUG 71 | struct ContentView_Previews: PreviewProvider { 72 | static var previews: some View { 73 | ContentView() 74 | } 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /ModelPicker/View/CustomARView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomARView.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import RealityKit 9 | import ARKit 10 | import FocusEntity 11 | 12 | class CustomARView: ARView { 13 | 14 | // MARK: - Properties 15 | 16 | var focusEntity: FocusEntity? 17 | 18 | // MARK: - Lifecycle 19 | 20 | required init(frame frameRect: CGRect) { 21 | super.init(frame: frameRect) 22 | setupFocusEntity() 23 | setupARView() 24 | } 25 | 26 | required init?(coder decoder: NSCoder) { 27 | super.init(coder: decoder) 28 | setupFocusEntity() 29 | setupARView() 30 | } 31 | } 32 | 33 | // MARK: - Private 34 | 35 | private extension CustomARView { 36 | 37 | func setupFocusEntity() { 38 | focusEntity = FocusEntity(on: self, style: .classic(color: UIColor.red)) 39 | focusEntity?.setAutoUpdate(to: true) 40 | } 41 | 42 | func setupARView() { 43 | 44 | // Uncomment to use ".nonAR" camera. 45 | //useNonARCameraSample() 46 | 47 | let config = ARWorldTrackingConfiguration() 48 | config.planeDetection = [.horizontal, .vertical] 49 | config.environmentTexturing = .automatic 50 | if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) { 51 | config.sceneReconstruction = .mesh 52 | } 53 | session.run(config) 54 | } 55 | 56 | /// From: https://developer.apple.com/forums/thread/122229 57 | func useNonARCameraSample() { 58 | 59 | // RealityKit now adds and uses a default PerspectiveCamera. 60 | cameraMode = .nonAR 61 | 62 | // Provide your own PerspectiveCamera. 63 | // See: https://developer.apple.com/documentation/realitykit/perspectivecamera 64 | let cameraEntity = PerspectiveCamera() 65 | cameraEntity.camera.fieldOfViewInDegrees = 140 66 | let cameraAnchor = AnchorEntity(world: .one) 67 | cameraAnchor.addChild(cameraEntity) 68 | 69 | scene.addAnchor(cameraAnchor) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ModelPicker/View/ModelPickerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ModelPickerView.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ModelPickerView: View { 11 | 12 | // MARK: - Properties 13 | 14 | @Binding var isPlacementEnabled: Bool 15 | @Binding var selectedModel: Model? 16 | 17 | var models: [Model] 18 | 19 | // MARK: Body 20 | 21 | var body: some View { 22 | ScrollView(.horizontal, showsIndicators: false) { 23 | HStack(spacing: 30) { 24 | ForEach(models, id: \.self) { model in 25 | Button { 26 | print("Picked model: \(model.modelName)") 27 | selectedModel = model 28 | isPlacementEnabled = true 29 | } label: { 30 | Image(uiImage: model.image) 31 | .resizable() 32 | .frame(height: 80) 33 | .aspectRatio(1/1, contentMode: .fit) 34 | .background( Color.white) 35 | .cornerRadius(12) 36 | } 37 | .buttonStyle(PlainButtonStyle()) 38 | } 39 | } 40 | } 41 | .padding(20) 42 | .background(Color.black.opacity(0.5)) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ModelPicker/View/PlacementButtonView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlacementButtonView.swift 3 | // ModelPicker 4 | // 5 | // Created by Fernando Fernandes on 24.07.20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct PlacementButtonView: View { 11 | 12 | // MARK: - Properties 13 | 14 | @Binding var isPlacementEnabled: Bool 15 | @Binding var selectedModel: Model? 16 | @Binding var modelConfirmedForPlacement: Model? 17 | 18 | // MARK: Body 19 | 20 | var body: some View { 21 | HStack { 22 | Button { 23 | print("Cancel button tapped") 24 | resetPlacementParameters() 25 | } label: { 26 | Image(systemName: "xmark") 27 | .frame(width: 60, height: 60) 28 | .font(.title) 29 | .background(Color.white.opacity(0.75)) 30 | .cornerRadius(30) 31 | .padding(20) 32 | } 33 | 34 | Button { 35 | print("Confirm button tapped") 36 | modelConfirmedForPlacement = selectedModel 37 | resetPlacementParameters() 38 | } label: { 39 | Image(systemName: "checkmark") 40 | .frame(width: 60, height: 60) 41 | .font(.title) 42 | .background(Color.white.opacity(0.75)) 43 | .cornerRadius(30) 44 | .padding(20) 45 | } 46 | } 47 | } 48 | } 49 | 50 | // MARK: - Private 51 | 52 | private extension PlacementButtonView { 53 | 54 | func resetPlacementParameters() { 55 | isPlacementEnabled = false 56 | selectedModel = nil 57 | } 58 | } 59 | 60 | // MARK: - Preview 61 | 62 | #if DEBUG 63 | struct PlacementButtonView_Previews: PreviewProvider { 64 | static var previews: some View { 65 | PlacementButtonView( 66 | isPlacementEnabled: .constant(false), 67 | selectedModel: .constant(nil), 68 | modelConfirmedForPlacement: .constant(nil) 69 | ) 70 | } 71 | } 72 | #endif 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # realitykit-swiftui 2 | RealityKit + SwiftUI demo 3 | 4 | An implementation of [Ryan Kopinsky's tutorial](https://www.youtube.com/watch?v=9R_G0EI-UoI) with some tweaks here and there. 5 | 6 | ## Demo 7 | 8 | ![ModelPickerApp](https://github.com/backslash-f/realitykit-swiftui/blob/master/modelPickerDemo.gif) 9 | -------------------------------------------------------------------------------- /modelPickerDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/backslash-f/realitykit-swiftui/f2c75ca8e7d6b9c7719b3140ea6e6b5a31664206/modelPickerDemo.gif --------------------------------------------------------------------------------