Search code examples
swiftaugmented-realityarkitrealitykitreality-composer

Programmatically setting texture in Scene generated by Reality Composer


I am creating a cylinder object using Reality Composer. My requirement is to wrap the cylinder with custom image. Image is dynamically created by the app.

I have tried following approach and so far it's not working.

    1. After loading the anchor from Experience.
    1. Fetch model entity from anchor.
    1. Fetch model component from model entity.
    1. Add or edit material.

Code:

// Load the "anchor" scene from the "Experience" Reality File
let anchor = try! Experience.loadAnchor()

// Add the anchor to the scene
arView.scene.anchors.append(anchor)

let cylinderEntity : Entity = anchor.cylinder!

let cylinderModelEntity = cylinderEntity.children[0]

var cylinderModelComponent : ModelComponent = cylinderModelEntity.components[ModelComponent.self]!

let paths : NSArray = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) as NSArray
let path : NSString = paths.object(at: 0) as! NSString
let filePath : NSString = path.strings(byAppendingPaths: ["Image.png"])[0] as NSString
let url = URL.init(fileURLWithPath: filePath as String)

// Save image.
let image : UIImage = createImage()
try! image.pngData()?.write(to: url)
let data = NSData.init(contentsOf: url)
print(data!)

var material = SimpleMaterial()
material.tintColor = UIColor.yellow
material.baseColor = try! MaterialColorParameter.texture(TextureResource.load(contentsOf: url))
material.roughness = MaterialScalarParameter(floatLiteral: 0.1)
material.metallic = MaterialScalarParameter(floatLiteral: 1.0)

cylinderModelComponent.materials[0] = material

Any help is really appreciated.


Solution

  • You forgot to set a boxComponent which need to be stored on the entity.

    For this use set() instance method.

    In your code it should look like this:

    anchor.cylinder!.components.set(cylinderModelComponent)
    

    In my code it looks like this:

    anchor.steelBox!.components.set(boxComponent)
    

    Here are my full code version (I tested it in macOS app):

    import AppKit
    import RealityKit
    
    class GameViewController: NSViewController {
    
        @IBOutlet var arView: ARView!
    
        override func awakeFromNib() {
    
            let anchor = try! Experience.loadBox()
            anchor.steelBox?.scale = SIMD3(x: 9, y: 9, z: 9)
            anchor.steelBox?.orientation = simd_quatf(angle: -Float.pi/4,
                                                       axis: SIMD3(x: 1, y: 1, z: 0))      
    
            let boxEntity: Entity = anchor.steelBox!.children[0]
            var boxComponent: ModelComponent = boxEntity.components[ModelComponent].self!
    
            let paths: NSArray = NSSearchPathForDirectoriesInDomains(.documentDirectory, 
                                                                     .userDomainMask, 
                                                                      true) as NSArray
    
            // If you're testing it in macOS app – place your Image.png here:
            // /Users/<UserName>/Library/Containers/<ApplicationName>/Data/Documents/
    
            let path: NSString = paths.object(at: 0) as! NSString
            let filePath: NSString = path.strings(byAppendingPaths: ["Image.png"])[0] as NSString
            let url = URL(fileURLWithPath: filePath as String)
    
            var material = SimpleMaterial()
            material.tintColor = NSColor.yellow
            material.baseColor = try! MaterialColorParameter.texture(TextureResource.load(contentsOf: url))
            material.roughness = MaterialScalarParameter(floatLiteral: 0.1)
            material.metallic = MaterialScalarParameter(floatLiteral: 0.1)    
            boxComponent.materials = [material]
    
            anchor.steelBox!.components.set(boxComponent)
            arView.scene.anchors.append(anchor)
        }
    }
    

    enter image description here