I'm having some trouble understanding how to apply or change a texture of a 3D model. I have of course Google'd to no avail, and searched the forum here, but I can't find a clear-cut example or explanation that works.

I'm basically trying to:

var image = Image.new()
var texture = ImageTexture.new()
image.load("res://Textures/tex.png")
texture.create_from_image(image)
model_instance = model.instance()
model_instance.get_node("MeshInstance").set_texture(texture)

Welcome to the forums @cas77!

I believe you can do something like this:

# load your image.
var image = load("res://Textures/tex.png")
# Get the 3D model
var mesh = get_node("MeshInstance")
# Get the material in slot 0
var material_one = mesh.get_surface_material(0)
# Change the texture
material_one.albedo_texture = image
# Reassign the material
mesh.set_surface_material(0, material_one)

Yup, exactly as I thought it would be; elegant and simple. I just couldn't figure out how to properly access and changes the textures, but your example is perfectly clear-cut. Many thanks, and thanks for the welcome. :)

Is it necessary to get_surface_material() and store it on the side, in order to change anything in the material?

@cas77 said: Yup, exactly as I thought it would be; elegant and simple. I just couldn't figure out how to properly access and changes the textures, but your example is perfectly clear-cut. Many thanks, and thanks for the welcome. :)

Happy to help :smile:

Is it necessary to get_surface_material() and store it on the side, in order to change anything in the material?

I'm not sure. You may be able to skip storing it off to the side and reassigning, I just didn't want to assume in the code snippet. I would recommend giving it a try and seeing what happens.

Another follow-up question; it seems that changing the texture on the latest instance of my model changes all the models' textures so they all have the same texture as the latest model. This is definitely not what I want. It simply won't only change the instance at hand.

Edit: I have uploaded an example file to better show what's going on.

Yup, that is expected to happen. Its because Godot batches materials together for performance reasons, but when you modify one material all instances of that material get modified. The solution is just to make a duplicate and use it instead:

# load your image.
var image = load("res://Textures/tex.png")
# Get the 3D model
var mesh = get_node("MeshInstance")
# Get a duplicate material of the material in slot 0
# (New code below!)
var material_one = mesh.get_surface_material(0).duplicate()
# Change the texture
material_one.albedo_texture = image
# Reassign the material
mesh.set_surface_material(0, material_one)

Thank you very much again. It's funny how one single piece of code can make all the difference.

2 years later