I think RealityView should be able to do more fancy stuffs, but I still want to figure out the exact differences between them. For now, they are just too similar to each other, e.g. they both need an Entity name to get initialized. I want to know when a Model3D is just enough, and when we must use a RealityView?
@available(visionOS 1.0, macOS 15.0, iOS 18.0, *)
@MainActor
@preconcurrency
public struct RealityView<Content> : View where Content : View
Standard practice for Apple engineers is to give views several initializers. RealityView
isn't an exception here. Let's take a look at RealityView's init(make:update:attachments:)
initializer with three closures, where you can:
make
closure)update
closure)attachments
closure)There's also init(make:update:placeholder:)
initializer with a placeholder.
Use RealityView to asynchronously load (it's an optional action) and display a rich 3D content in RealityKit app. RealityView passes a struct conforming to RealityViewContentProtocol to the make
and update
closures, which you can use to add and remove RealityKit's entities to a scene. Entities must be 3D primitives, .usdz
models, or scenes from Reality Composer Pro.
RealityView { content, attachments in
// code
} update: { content, attachments in
// code
} attachments: {
// code
}
Just like in ARSCNView (it's a SceneKit's symbiosis of AR and VR), you are not obliged to use an anchor, however, using anchors gives you the opportunity to implement robust AR scenarios – such as image tracking
, plane tracking
, hand tracking
, etc.
Let's see how RealityView looks in code and what base object will be printed in console:
import SwiftUI
import RealityKit
struct ContentView: View {
var body: some View {
RealityView { content in
if let model = try? await Entity.load(named: "car") {
model.scale /= 10
let anchor = AnchorEntity()
anchor.addChild(model)
content.add(anchor)
print(content)
}
}
}
}
In other words, RealityView
is rather a RealityKit's view for visionOS
/iOS
/macOS
SwiftUI apps where you get an access to a scene's assembly point. And don't forget that anchors are an important part of the RealityView
hierarchical structure, which isn't the case in Model3D.
SwiftUI's Model3D view is simpler than RealityView, and is used to asynchronously load and display a model from the specified URL (.usdz
or .reality
models) or from app's bundle. Until the model loads, SwiftUI displays a placeholder. The resulted model is contained in ResolvedModel3D
view. Working with Model3D view you are unable to decompose a 3D scene like in RealityView.
You can work with if-else
statement inside a closure...
Model3D(url: url) { phase in
if let model = phase.model {
// model's modifiers
} else if phase.error != nil {
// error description
} else {
// placeholder
}
}
...or you can switch the cases of Model3DPhase
enum.
Model3D(named: named) { phase in
switch phase {
case .empty:
ProgressView()
case let .failure(error):
Text(error.localizedDescription)
case let .success(model):
model
.resizable()
.scaledToFit()
}
}
Just like RealityView, Model3D view has several initializers.
Let's see how init(named:bundle:content:placeholder:)
initializer with a placeholder @ViewBuilder looks in code and what base object will be printed in console:
import SwiftUI
import RealityKit
struct ContentView: View {
var body: some View {
Model3D(named: "car") { model in
model.resizable()
let _ = print(model)
} placeholder: {
ProgressView()
}
}
}
In other words, Model3D
is the SwiftUI's 3D view holding RealityKit's scene.