I bought 2 USDZ models from Sketchfab. But I don't understand why the behavior is different.
The first model, I can use ModelEntity
adding the object.model!.mesh.bounds.extents
and storing the object.availableAnimations[0]
struct ImmrsiveView: View {
@State var object: ModelEntity? = nil
@State var animation: AnimationResource? = nil
var body: some View {
RealityView { content in
do {
object = try await ModelEntity(named: "speaker")
if let object {
let objectBound = object.model!.mesh.bounds.extents
object.components.set(CollisionComponent(shapes: [.generateBox(size: objectBound)]))
object.components.set(InputTargetComponent())
animation = object.availableAnimations[0]
content.add(object)
}
}
catch {
print("Error loading the model")
}
}
}
}
However, when I use the second USDZ file (by simply changing the entity name),
object
type to Entity
even though the loader is ModelEntity.load(named: "object") with a warning: No 'async' operations occur within 'await' expression..mesh.bounds.extents
for Entity. The collision doesn't workEntity
, now the availableAnimations[0] works!So now the code becomes
struct ImmrsiveView: View {
@State var object: Entity? = nil
@State var animation: AnimationResource? = nil
var body: some View {
RealityView { content in
do {
object = try await ModelEntity.load(named: "object2")
if let object {
// This doesn't work
// let objectBound = object.model!.mesh.bounds.extents
// object.components.set(CollisionComponent(shapes: [.generateBox(size: objectBound)]))
// object.components.set(InputTargetComponent())
animation = object.availableAnimations[0]
content.add(object)
}
}
catch {
print("Error loading the model")
}
}
}
}
The questions are ... suppose there are different ways of loading USDZ files:
You can use the ModelEntity(named:)
initializer to load your character as model entity to assign a collision shape to it...
import SwiftUI
import RealityKit
struct ContentView : View {
@State var object = ModelEntity()
@State var animation: AnimationResource? = nil
var body: some View {
RealityView { rvc in
do {
object = try await ModelEntity(named: "Man")
object.position.z = -3.0
object.name = "Character"
object.generateCollisionShapes(recursive: true)
object.components.set(InputTargetComponent())
animation = object.availableAnimations[0].repeat()
object.playAnimation(animation!)
rvc.add(object)
print(object.model?.mesh.bounds.extents as Any)
} catch {
print("Error loading the model")
}
}
.gesture(gesture)
}
var gesture: some Gesture {
TapGesture()
.targetedToEntity(object)
.onEnded {
print($0.entity.name)
}
}
}
...however, the only "righteous" RealityKit's way is to find the ModelEntity within the hierarchical structure in your USDZ.
struct ContentView : View {
@State var object = Entity()
@State var animation: AnimationResource? = nil
var body: some View {
RealityView { rvc in
do {
object = try await Entity(named: "Man")
object.position.z = -3.0
// find the model entity's name in the hierarchy
// in my case it's "skin0"
print(object)
let me = object.findEntity(named: "skin0") as! ModelEntity
me.generateCollisionShapes(recursive: true)
me.components.set(InputTargetComponent())
animation = me.availableAnimations[0].repeat()
me.playAnimation(animation!)
rvc.add(object)
print(me.model?.mesh.bounds.extents as Any)
} catch {
print("Error loading the model")
}
}
.gesture(gesture)
}
var gesture: some Gesture {
TapGesture()
.targetedToEntity(object)
.onEnded {
print($0.entity.name)
}
}
}