swiftuirealitykitvisionos

I've tried to give a physicsBodyComponent to modelEntity, and it is just not sitting on the floor currectly


there was simple 6 sided dice before this 12 sided dice as ModelEntity but back then it was working properly for 6 sided dice.enter image description here

            let floor = ModelEntity(mesh: .generatePlane(width: 50, depth: 50), materials: [OcclusionMaterial()])
            floor.generateCollisionShapes(recursive: false)
            floor.components[PhysicsBodyComponent.self] = .init(
                massProperties: .default,
                mode: .static
            )
            
            content.add(floor)
            
            if let diceModel = try? await Entity(named: "d20"),
               let dice = diceModel.children.first?.children.first {
                dice.scale = [0.1, 0.1, 0.1]
                dice.position.y = 0.5
                dice.position.z = -1
                
                dice.generateCollisionShapes(recursive: true)
                dice.components.set(InputTargetComponent())
                
                dice.components.set(ImageBasedLightReceiverComponent(imageBasedLight: dice))
                dice.components.set(GroundingShadowComponent(castsShadow: true))
                
                dice.components[PhysicsBodyComponent.self] = .init(PhysicsBodyComponent(
                    massProperties: .default,
                    material: .generate(staticFriction: 0.8, dynamicFriction: 0.5, restitution: 0.1),
                    mode: .dynamic
                ))
                
                dice.components[PhysicsBodyComponent]
                
                
                dice.components[PhysicsMotionComponent.self] = .init()
                
                content.add(dice)
            }
        }
        .gesture(dragGesture)
    }

Solution

  • Creating a custom Collision Shape for Icosahedron

    First of all, your image shows an icosahedron that is a three-dimensional shape with 20 (not 12, as you said) flat triangular faces. In order to generate a custom Collision Shape for any 3D polyhedron (but not for 6-sided cube, which the .generateCollisionShapes(recursive:) default method is generally used for) you need to use .generateConvex(from:) type method.

    Here's my code:

    import SwiftUI
    import RealityKit
    
    struct ContentView : View {
        let entity = try! Entity.load(named: "Icosahedron")
        let plane = ModelEntity(mesh: .generatePlane(width: 5, depth: 5))
    
        init() {
            plane.model?.materials = [OcclusionMaterial()]
            plane.generateCollisionShapes(recursive: false)
            plane.physicsBody = .init()
            plane.physicsBody?.mode = .static
        }
        
        var body: some View {
            RealityView { rvc in
                rvc.add(plane)
                
                print(entity)
                let icosahedron = entity.findEntity(named: "Object_0") as! ModelEntity
                icosahedron.scale /= 2.5
                icosahedron.position = [0.0, 1.0,-4.0]
                icosahedron.orientation = .init(angle: -.pi/16, axis: [1, 0.4, 0])
                icosahedron.model?.materials = [SimpleMaterial(color: .white, isMetallic: false)]
                
                Task { @MainActor in
                    let resource = try await ShapeResource.generateConvex(from: icosahedron.model!.mesh)
                    icosahedron.components[CollisionComponent.self] = .init(shapes: [resource])
                }
                icosahedron.physicsBody = .init()
                icosahedron.physicsBody?.mode = .dynamic
                rvc.add(icosahedron)
                
                plane.position.z = icosahedron.position.z
            }
        }
    }
    

    enter image description here

    A visualized Collision Shape in Xcode's visionOS Debugging:

    enter image description here