Search code examples
swiftaugmented-realityarkitrealitykitreality-composer

Is there a way to programmatically change the material of an Entity that was created in Reality Composer?


I want to change the color of an entity programmatically after it was created in Reality Composer.

As Reality Composer does not create a ModelEntity (it creates a generic Entity), it does not appear that I have access to change its color. When I typecast to a ModelEntity, I now have access to the ModelComponent materials. However, when I try to add that to the scene I get a Thread 1: signal SIGABART error. Could not cast value of type 'RealityKit.Entity' (0x1fcebe6e8) to 'RealityKit.ModelEntity' (0x1fceba970). Sample code below.

import UIKit
import RealityKit

class ViewController: UIViewController {

    @IBOutlet var arView: ARView!

    override func viewDidLoad() {
        super.viewDidLoad()
    
        // Load the "Box" scene from the "Experience" Reality File
        let boxAnchor = try! Experience.loadBox()
    
        // Typecast Steelbox as ModelEntity to change its color
        let boxModelEntity = boxAnchor.steelBox as! ModelEntity
    
        // Remove materials and create new material
        boxModelEntity.model?.materials.removeAll()
    
        let blueMaterial = SimpleMaterial(color: .blue, isMetallic: false)
        boxModelEntity.model?.materials.append(blueMaterial)
    
        // Add the box anchor to the scene
        arView.scene.anchors.append(boxAnchor)
    }
}

Solution

  • Model entity is stored deeper in RealityKit's hierarchy, and as you said, it's Entity, not ModelEntity. So use downcasting to access mesh and materials:

    import UIKit
    import RealityKit
    
    class ViewController: UIViewController {
        
        @IBOutlet var arView: ARView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let boxScene = try! Experience.loadBox()
            print(boxScene)
            
            let modelEntity = boxScene.steelBox?.children[0] as! ModelEntity
            let material = SimpleMaterial(color: .green, isMetallic: false)
            modelEntity.model?.materials = [material]
            
            let anchor = AnchorEntity()
            anchor.scale = [5,5,5]
            modelEntity.setParent(anchor)
            arView.scene.anchors.append(anchor)
        }
    }
    

    Also, this post and this one can be helpful.