RealityKit – Get ModelEntity Size as SIMD3<Float>
Asked Answered
T

3

5

Is there anyway to know the size of the ModelEntity as SIMD3? Once, I get the size, I want to pass it to the CollisionComponent.

 let box = ModelEntity(mesh: MeshResource.generateBox(size: 0.2), 
                  materials: [SimpleMaterial(color: .green, isMetallic: true)])
 box.position.y = 0.3 
 box.generateCollisionShapes(recursive: true)
 box.physicsBody = PhysicsBodyComponent(massProperties: .default, 
                                              material: .default, 
                                                  mode: .dynamic)
            
 // I know I can use the following
 box.collision = CollisionComponent(shapes: [.generateBox(size: [0.2,0.2,0.2])], 
                                                          mode: .trigger, 
                                                        filter: .sensor)
            
 // but why not just pass the size of the box I created earlier. 
 box.collision = CollisionComponent(shapes: [PASS BOX SIZE HERE], 
                                      mode: .trigger, 
                                    filter: .sensor)
Twomey answered 5/5, 2022 at 17:41 Comment(0)
M
8

"Reverse Engineering"

To calculate the size of a primitive, use the max and min values of its bounding box.

let box = ModelEntity(mesh: MeshResource.generateBox(width: 0.11, 
                                                    height: 0.23, 
                                                     depth: 0.45))

let width = (box.model?.mesh.bounds.max.x)! - (box.model?.mesh.bounds.min.x)!
let height = (box.model?.mesh.bounds.max.y)! - (box.model?.mesh.bounds.min.y)!
let depth = (box.model?.mesh.bounds.max.z)! - (box.model?.mesh.bounds.min.z)!
    
let boxSize: SIMD3<Float> = [width, height, depth]
    
print(boxSize)

// Result:

// SIMD3<Float>(0.11, 0.23, 0.45)

To calculate the size of bounding box of any part of .usdz model use the following approach:

let car = try! ModelEntity.load(named: "car.usdz")

let carBody = car.children[0]..........children[0] as! ModelEntity

print((carBody.model?.mesh.bounds)!)
Macegan answered 5/5, 2022 at 20:26 Comment(6)
Hi @Andy Jazz: What is reason we need to dig into multi level children to get a model entity? And how this affects if entity is modified by scale while saving in usdz file?Corrody
Hi @NKD2007, .usdz, .usda and .reality files can store ModelEntities deep inside the hierarchical scene structure. You can retrieve any model from scene using the following approaches. ModelEntities can be modified in Xcode non-destructively.Macegan
But if I use visualBounds( recursive: Bool = true, relativeTo referenceEntity: Entity?, excludeInactive: Bool = false ) -> BoundingBox then I get a different value. Is scale is affecting?Corrody
Post it as another question, please (including code).Macegan
Added here #78327538Corrody
Post a new question, please (not a comment).Macegan
S
1

To simplify the code you can add the extension

extension BoundingBox {
    var size: SIMD3<Float> {
        let width = max.x - min.x
        let height = max.y - min.y
        let depth = max.z - min.z
        return [width, height, depth]
    }
}

Also, in place of searching the ModelEntity child of our object manually you should use the method:

visualBounds(
    recursive: Bool = true, 
    relativeTo referenceEntity: Entity?, 
    excludeInactive: Bool = false
) -> BoundingBox

This method computes a bounding box for the entity in the specified space, including child entities (recursive is true by default) keeping in mind all the applied transforms so it is precise.

So for example imagine that we have an box entity of a 1 meter side, and a scale of 0.5:

  • modelEntity.model.mesh.bounds.size.x --> 1 meter
  • entity.visualBounds(relativeTo: nil).size.x --> 0.5 meter
Separation answered 6/8, 2023 at 9:56 Comment(2)
isn't this more expensive performance wise?Agricola
I don't think so, it's quite optimise. I guess that the method uses the box of the mesh under the hood, and if the entity does not have children the performance will be the same. Anyway we should try to keep the things simple and to optimise when you observe a problem not at the beginning.Separation
W
1

My extension is based on the code of @Andy Jazz:

extension ModelEntity {
    func size() -> SIMD3<Float> {
        guard let mesh = self.model?.mesh else {
            return .zero
        }

        let width = mesh.bounds.max.x - mesh.bounds.min.x
        let height = mesh.bounds.max.y - mesh.bounds.min.y
        let depth = mesh.bounds.max.z - mesh.bounds.min.z
        return [width, height, depth]
    }
}
...

let size = modelEntity.size()
Weighty answered 4/10, 2023 at 11:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.