{"id":3265,"date":"2025-02-25T14:46:46","date_gmt":"2025-02-25T19:46:46","guid":{"rendered":"https:\/\/stepinto.vision\/?p=3265"},"modified":"2025-02-25T14:46:46","modified_gmt":"2025-02-25T19:46:46","slug":"spatial-swiftui-model3d","status":"publish","type":"post","link":"https:\/\/stepinto.vision\/example-code\/spatial-swiftui-model3d\/","title":{"rendered":"Spatial SwiftUI: Model3D"},"content":{"rendered":"\n<p>Model3D is a simple view that can load a USD or `.reality` file and display it in your SwiftUI view.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" data-attachment-id=\"3275\" data-permalink=\"https:\/\/stepinto.vision\/example-code\/spatial-swiftui-model3d\/attachment\/step-example-051-01\/\" data-orig-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?fit=2732%2C2048&amp;ssl=1\" data-orig-size=\"2732,2048\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"step-example-051-01\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?fit=1024%2C768&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=1024%2C768&#038;ssl=1\" alt=\"\" class=\"wp-image-3275\" srcset=\"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=1024%2C768&amp;ssl=1 1024w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=300%2C225&amp;ssl=1 300w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=768%2C576&amp;ssl=1 768w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=1536%2C1151&amp;ssl=1 1536w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=2048%2C1535&amp;ssl=1 2048w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=1200%2C900&amp;ssl=1 1200w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=800%2C600&amp;ssl=1 800w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=600%2C450&amp;ssl=1 600w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=400%2C300&amp;ssl=1 400w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?resize=200%2C150&amp;ssl=1 200w, https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?w=2580&amp;ssl=1 2580w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Overview<\/h2>\n\n\n\n<p>Most of the work on this site is done in RealityKit, but there are times when all we need to do is display the contents of a 3D file. In those cases, Model3D may be a good fit.<\/p>\n\n\n\n<p>We can load a model that has been included in the app bundle. Apple suggests that we place 3D assets inside a <code>.rkassets<\/code> bundle. This bundle can be found in the RealityKitContent bundle if you used a visionOS template project. <\/p>\n\n\n\n<p>This will load a USDZ from the bundle.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"Model3D(named: &quot;Earth&quot;, bundle: realityKitContentBundle)\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #795E26\">Model3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">named<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;Earth&quot;<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">bundle<\/span><span style=\"color: #000000\">: realityKitContentBundle)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>We can unpack the ResolvedModel3D and call SwiftUI modifiers on it. For example, let&#8217;s mark the earth model and resizable, then wrap it in a frame. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"Model3D(named: &quot;Earth&quot;, bundle: realityKitContentBundle)  { model in\n    model\n        .resizable()\n        .aspectRatio(contentMode: .fit)\n} placeholder: {\n    ProgressView()\n}\n.frame(width: 100, height: 100)\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #795E26\">Model3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">named<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;Earth&quot;<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">bundle<\/span><span style=\"color: #000000\">: realityKitContentBundle)  { model <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">resizable<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        .<\/span><span style=\"color: #795E26\">aspectRatio<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">contentMode<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">fit<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">} placeholder: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #795E26\">ProgressView<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">.<\/span><span style=\"color: #795E26\">frame<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">100<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">100<\/span><span style=\"color: #000000\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>If we need to load a file from a server, we can use an asynchronous version of Model3D. We can show a placeholder and a view to display on error.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"Model3D(url: url)\n{ phase in\n    if let model = phase.model {\n        model\n            .resizable()\n            .aspectRatio(contentMode: .fit)\n    } else if phase.error != nil {\n        Text(&quot;Could not load model \\(name).&quot;)\n    } else {\n        ProgressView()\n    }\n}\n\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #795E26\">Model3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">url<\/span><span style=\"color: #000000\">: url)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">{ phase <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #AF00DB\">if<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> model = phase.<\/span><span style=\"color: #001080\">model<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            .<\/span><span style=\"color: #795E26\">resizable<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            .<\/span><span style=\"color: #795E26\">aspectRatio<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">contentMode<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">fit<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    } <\/span><span style=\"color: #AF00DB\">else<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #AF00DB\">if<\/span><span style=\"color: #000000\"> phase.<\/span><span style=\"color: #001080\">error<\/span><span style=\"color: #000000\"> != <\/span><span style=\"color: #0000FF\">nil<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Could not load model <\/span><span style=\"color: #0000FF\">\\(<\/span><span style=\"color: #000000FF\">name<\/span><span style=\"color: #0000FF\">)<\/span><span style=\"color: #A31515\">.&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    } <\/span><span style=\"color: #AF00DB\">else<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">ProgressView<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Model3D is just a SwiftUI view, so we can use modifiers on it just like any other view. We can use some of the spatial modifiers from <a href=\"https:\/\/stepinto.vision\/learn-visionos\/#spatial\">this series<\/a>.<\/p>\n\n\n\n<p>Example: the moon model with frame, offset, and hover.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"ModelView(name: &quot;Moon&quot;)\n  .frame(width: 40, height: 40)\n  .offset(x: 50, y: -50)\n  .offset(z: 100)\n  .hoverEffect()\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #795E26\">ModelView<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">name<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;Moon&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">  .<\/span><span style=\"color: #795E26\">frame<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">40<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">40<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">  .<\/span><span style=\"color: #795E26\">offset<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">x<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">50<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">y<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">-50<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">  .<\/span><span style=\"color: #795E26\">offset<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">z<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">100<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">  .<\/span><span style=\"color: #795E26\">hoverEffect<\/span><span style=\"color: #000000\">()<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Apple has a lot more details about <a href=\"https:\/\/developer.apple.com\/documentation\/realitykit\/model3d\/\">Model3D<\/a> in the documentation, so we won&#8217;t cover much more here. <\/p>\n\n\n\n<p>Bonus: We can load more than just USDZ files. For example, when we create scenes in Reality Composer Pro, those are saved as <code>.usda<\/code> files. We can load them from the bundle just like we did with the earth model above. We could make special preview versions of our scenes that we can use in SwiftUI views. I may use this to provide a menu of scenes for the Dark Spaces project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Full Example Code<\/h2>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#000000;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"struct Example051: View {\n\n    @State private var isActive = false\n\n    var body: some View {\n        VStack {\n            Text(&quot;Model3D Examples&quot;)\n                .font(.title)\n\n            HStack(alignment: .center) {\n                ModelView(name: &quot;Earth&quot;)\n                    .frame(width: 160, height: 160)\n                    .rotation3DEffect(\n                        Angle(degrees: isActive ? 180 : 0),\n                        axis: (x: 0, y: 1, z: 0)\n                    )\n                    .hoverEffect()\n                    .onTapGesture {\n                        withAnimation {\n                            isActive.toggle()\n                        }\n                    }\n                ModelView(name: &quot;Moon&quot;)\n                    .frame(width: 40, height: 40)\n                    .offset(x: 50, y: -50)\n                    .offset(z: 100)\n                    .hoverEffect()\n\n            }\n            .padding(24)\n\n            Text(&quot;Earth and Moon from the Reality Composer Pro asset library.&quot;)\n                .font(.caption)\n        }\n    }\n}\n\nfileprivate struct ModelView: View {\n\n    @State var name: String = &quot;&quot;\n\n    var body: some View {\n        Model3D(named: name, bundle: realityKitContentBundle)\n        { phase in\n            if let model = phase.model {\n                model\n                    .resizable()\n                    .aspectRatio(contentMode: .fit)\n            } else if phase.error != nil {\n                Text(&quot;Could not load model \\(name).&quot;)\n            } else {\n                ProgressView()\n            }\n        }\n    }\n}\" style=\"color:#000000;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki light-plus\" style=\"background-color: #FFFFFF\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">Example051<\/span><span style=\"color: #000000\">: View {<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@State<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">private<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> isActive = <\/span><span style=\"color: #0000FF\">false<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        VStack {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Model3D Examples&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">font<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">title<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">HStack<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">alignment<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">center<\/span><span style=\"color: #000000\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">ModelView<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">name<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;Earth&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">frame<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">160<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">160<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">rotation3DEffect<\/span><span style=\"color: #000000\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                        <\/span><span style=\"color: #795E26\">Angle<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">degrees<\/span><span style=\"color: #000000\">: isActive ? <\/span><span style=\"color: #098658\">180<\/span><span style=\"color: #000000\"> : <\/span><span style=\"color: #098658\">0<\/span><span style=\"color: #000000\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                        <\/span><span style=\"color: #795E26\">axis<\/span><span style=\"color: #000000\">: (<\/span><span style=\"color: #795E26\">x<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">0<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">y<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">1<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">z<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">0<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">hoverEffect<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #001080\">onTapGesture<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                        withAnimation {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                            isActive.<\/span><span style=\"color: #795E26\">toggle<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">ModelView<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">name<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #A31515\">&quot;Moon&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">frame<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">width<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">40<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">height<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">40<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">offset<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">x<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">50<\/span><span style=\"color: #000000\">, <\/span><span style=\"color: #795E26\">y<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">-50<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">offset<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">z<\/span><span style=\"color: #000000\">: <\/span><span style=\"color: #098658\">100<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">hoverEffect<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            .<\/span><span style=\"color: #795E26\">padding<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #098658\">24<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Earth and Moon from the Reality Composer Pro asset library.&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                .<\/span><span style=\"color: #795E26\">font<\/span><span style=\"color: #000000\">(.<\/span><span style=\"color: #001080\">caption<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #0000FF\">fileprivate<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">struct<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #267F99\">ModelView<\/span><span style=\"color: #000000\">: View {<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">@State<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> name: <\/span><span style=\"color: #267F99\">String<\/span><span style=\"color: #000000\"> = <\/span><span style=\"color: #A31515\">&quot;&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    <\/span><span style=\"color: #0000FF\">var<\/span><span style=\"color: #000000\"> body: some View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        <\/span><span style=\"color: #795E26\">Model3D<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">named<\/span><span style=\"color: #000000\">: name, <\/span><span style=\"color: #795E26\">bundle<\/span><span style=\"color: #000000\">: realityKitContentBundle)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        { phase <\/span><span style=\"color: #AF00DB\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            <\/span><span style=\"color: #AF00DB\">if<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #0000FF\">let<\/span><span style=\"color: #000000\"> model = phase.<\/span><span style=\"color: #001080\">model<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                model<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">resizable<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                    .<\/span><span style=\"color: #795E26\">aspectRatio<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #795E26\">contentMode<\/span><span style=\"color: #000000\">: .<\/span><span style=\"color: #001080\">fit<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            } <\/span><span style=\"color: #AF00DB\">else<\/span><span style=\"color: #000000\"> <\/span><span style=\"color: #AF00DB\">if<\/span><span style=\"color: #000000\"> phase.<\/span><span style=\"color: #001080\">error<\/span><span style=\"color: #000000\"> != <\/span><span style=\"color: #0000FF\">nil<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">Text<\/span><span style=\"color: #000000\">(<\/span><span style=\"color: #A31515\">&quot;Could not load model <\/span><span style=\"color: #0000FF\">\\(<\/span><span style=\"color: #000000FF\">name<\/span><span style=\"color: #0000FF\">)<\/span><span style=\"color: #A31515\">.&quot;<\/span><span style=\"color: #000000\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            } <\/span><span style=\"color: #AF00DB\">else<\/span><span style=\"color: #000000\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">                <\/span><span style=\"color: #795E26\">ProgressView<\/span><span style=\"color: #000000\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #000000\">}<\/span><\/span><\/code><\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Model3D is a simple view that can load a USD or .reality file and display it in your SwiftUI view.<\/p>\n","protected":false},"author":93705089,"featured_media":3275,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"_kadence_starter_templates_imported_post":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1365],"tags":[],"class_list":["post-3265","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-example-code"],"jetpack_publicize_connections":[],"taxonomy_info":{"category":[{"value":1365,"label":"Example Code"}]},"featured_image_src_large":["https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?fit=1024%2C768&ssl=1",1024,768,true],"author_info":{"display_name":"Joseph Simpson","author_link":"https:\/\/stepinto.vision\/author\/vrhermit\/"},"comment_info":0,"category_info":[{"term_id":1365,"name":"Example Code","slug":"example-code","term_group":0,"term_taxonomy_id":11,"taxonomy":"category","description":"Code snippets and examples of using common APIs throughout visionOS development","parent":0,"count":187,"filter":"raw","cat_ID":1365,"category_count":187,"category_description":"Code snippets and examples of using common APIs throughout visionOS development","cat_name":"Example Code","category_nicename":"example-code","category_parent":0}],"tag_info":false,"jetpack_featured_media_url":"https:\/\/i0.wp.com\/stepinto.vision\/wp-content\/uploads\/2025\/02\/step-example-051-01.jpeg?fit=2732%2C2048&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/3265","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/users\/93705089"}],"replies":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/comments?post=3265"}],"version-history":[{"count":10,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/3265\/revisions"}],"predecessor-version":[{"id":3276,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/posts\/3265\/revisions\/3276"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media\/3275"}],"wp:attachment":[{"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/media?parent=3265"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/categories?post=3265"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/stepinto.vision\/wp-json\/wp\/v2\/tags?post=3265"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}