Nikolay Podolnyy
Nikolay Podolnyy

Reputation: 1091

Change texture image for 3d model

I'm investigating iOS and trying to understand is it possible to change the texture of the model using any other picture?

Let's say I have model.obj with related texture green.png which is applied to this model so the appearance of the product is green. Is it possible to choose any other image, for example, blue.png, and apply it programmatically in runtime to 3d model and make the appearance of the product blue?

I have one working example

    override func viewDidLoad() {
        super.viewDidLoad()
        let node = SCNNode()
        let geometry = SCNSphere(radius: 0.2)
        
        node.position = SCNVector3(0, 0, -1)
        
        sceneView.backgroundColor = .black
        sceneView.scene = SCNScene()
        
        node.geometry = self.geometry
        let image = UIImage(named: "art.scnassets/green.jpeg")
        print(image)
        node.geometry?.firstMaterial?.diffuse.contents = image
        
        sceneView.scene.rootNode.addChildNode(node)
    }

But when I try apply image to uploaded 3d model it's appearance doesn't change, here is a code.

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tempScene = SCNScene(named: "art.scnassets/California_chair_1.obj")!
        let node = tempScene.rootNode
        
        node.position = SCNVector3(0, 0, -1)
        sceneView.scene = SCNScene()
        let image = UIImage(named: "art.scnassets/green.jpeg")
        print(image)
        
        /**/
        let material = SCNMaterial()
        material.isDoubleSided = false
        material.diffuse.contents = image
        node.geometry?.materials = [material]
        /**/
        
        node.geometry?.firstMaterial?.diffuse.contents = image
        
        sceneView.scene.rootNode.addChildNode(node)
    }

How to apply image to any 3d model created by designer?

Many thanks for any help!

Upvotes: 3

Views: 1405

Answers (1)

Andy Jazz
Andy Jazz

Reputation: 58043

For retrieving a model from SCNScene, you may use subscript .childNodes[0] several times to get to geometry and its corresponding materials in hierarchy.

import ARKit

class ViewController: UIViewController {

    @IBOutlet var sceneView: ARSCNView!
    let node = SCNNode()

    override func viewDidLoad() {
        super.viewDidLoad()
        sceneView.scene = SCNScene(named: "art.scnassets/California_chair.scn")!
        sceneView.autoenablesDefaultLighting = true
    
        node = sceneView.scene.rootNode.childNode(withName: "firstChair", 
                                               recursively: true)
        let green = UIColor.green
        node?.childNodes[0].geometry?.firstMaterial?.diffuse.contents = green
    }

    @IBAction func changeTexture(_ sender: UIButton) {
        let blue = UIImage(named: "art.scnassets/blueTexture.png")
        node.geometry?.firstMaterial?.diffuse.contents = blue
    }
}

Consider that SCNGeometry may be nested inside deep hierarchy:

node?.childNodes[0].childNodes[0].childNodes[0].geometry.firstMaterial?.diffuse

In Xcode's Scene graph such a nested hierarchy looks like this:

enter image description here

Also always check your node's size (scale), to find out if your camera is inside 3D model or not.

P.S.

In case you use obj models – use their corresponding mtl textures:

sceneView.scene = SCNScene(named: "art.scnassets/file.obj")!
    
let obj = sceneView.scene.rootNode.childNode(withName: "default", 
                                          recursively: true)

obj?.geometry?.firstMaterial?.diffuse.contents = UIImage(named: 
                                                       "art.scnassets/file.mtl")

Upvotes: 2

Related Questions