P. Tsin
P. Tsin

Reputation: 581

What is the difference between Model3D and RealityView in visionOS?

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?

Upvotes: 9

Views: 3845

Answers (3)

hhamm
hhamm

Reputation: 1581

Model3D does not allow you to access / modify the data inside. E.g. if you want to change a material, mesh or even a color of a specific entity, this is not possible with Model3D. You basically are stuck with the Model3D that has been loaded.

RealityView gives you access to the whole ECS (Entity Component Systems) - which also allows you to change mesh, materials, colors, add custom components etc.

Also intersting: if you place Model3D in a SwiftUI View, its placed directly on the SwiftUI window, while RealityViews are put kinda far in front of a SwiftUI window. You can use positioning to put the RealityView -0.2 to put it just at the window:

RealityView { content in
  if var entity = try? await Entity(named: "Scene", in: realityKitContentBundle) {
    entity.position = SIMD3<Float>(0, 0, -0.2)
    entity.scale = SIMD3<Float>(1, 1, 1)
    content.add(entity)
    sphereEntity = entity
  }
}

Please correct me, if I'm wrong ;-)

Upvotes: 0

Andy Jazz
Andy Jazz

Reputation: 58143

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:

  • create, set up and configure the initial 3D scene's content (make closure)
  • update scene's content in response to changes in view's state (optional update closure)
  • implement ViewBuilder of attachment views to use in 3D scene (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.

enter image description here



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.

enter image description here

Upvotes: 9

elkraneo
elkraneo

Reputation: 119

It is also interesting to note that all instances of RealityView and Model3D share a unique hierarchy, regardless of where they are located in SwiftUI.

Using the .parent property of any entity, one can climb to a common root named Window Context Entity and there are also a number of intriguing new entity types in the tree like CALayerEntity

Upvotes: 1

Related Questions