0 votes

Hello,

I have 2 questions:

1) I want to iterate over materials and change its color like this, how to do this?

first i get a mesh:

onready var mesh = get_tree().get_root().get_node("Spatial").get_node("tileroot").get_node("cube")   

then i want to change every color:

mesh.get_surface_material(0).albedo_color = Color(100,100,100)

How check how many materials i have on object (meshInstance) and iterate over this materials?

2) How to interpolate albedo color?

TweenNode.interpolate_property(
        self,
        'something like albedo color',
        self.albedo_color,
        Color(100,100,100),
        2, Tween.TRANS_ELASTIC, Tween.EASE_IN_OUT)

What will be at 'something like albedo color'?

Cheers,

Beet

asked Mar 3, 2019 in Engine by beetbeet (39 points)

Depending on what you want to do a shader might be the way to go.

MagnusS is probably right. A Shader might be a good idea.

Anyway:
You can apply and change materials at different places.

First, you got the mesh. This will often be of type "ArrayMesh":
https://docs.godotengine.org/en/latest/classes/class_arraymesh.html?highlight=arraymesh

If you've got a MeshInstance Node then you'll get the mesh via its mesh property.
Anyway, changing/setting the Mesh material will change the material of all occurances of this mesh at the same time.

In the editor you'll see these materials if you click on the Mesh inside the Meshinstance. There'll be Secions "Surface 1" and so on.

Then you got get_surface_material_count () to iterate the materials and get_surface_material ( int surface ). These materials are not always defined. In the editor you'll see these materials under "Material" (and then an index number starting at 0). If this material is defined (you can do that in the editor) then it will override the mesh material. You should be able to use `getsurfacematerial(index)' and then directly change the albedo.

Provided you've first assigned materials to the MeshInstance, the Tween could look somewhat like this: (I'm using your "mesh" for the MeshInstance node, a bit misleading.)
(Edited!)

for i in range(mesh.get_surface_material_count()):
  var mat = mesh.get_surface_material(i)
  if mat != null:
    tween.interpolate_property(mesh, "material/"+str(i)+"/albedo_color",
        mat.albedo_color, Color(100,100,100), 2,
        Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
    tween.start()
  else:
    print("Error: Material "+str(i)+" of mesh "+mesh.get_name()+" is null!")

(untested)

ok, but my object is Meshinstance, not ArrayMesh

How to "cast" type of meshinstance to arraymesh to get mesh.getsurfacematerial_count() working?

No, Arraymesh is the typical type of the mesh property inside the MeshInstance.

I just used the variable name mesh because you used it in your example. In my example the variable actually should contain the MeshInstance node.

Here's a code which I just successfully tried out: (had steal the correct name of the albedo property of an animation, which is also an alternative)

onready var meshinst = $MeshInstance2
onready var tween = $Tween

func _on_Button_pressed():
    for i in range(meshinst.get_surface_material_count()):
        print(str(i))
        var mat = meshinst.get_surface_material(i)
        if mat != null:
            print(str(mat.albedo_color))
            tween.interpolate_property(meshinst, "material/"+str(i)+":albedo_color", \
                mat.albedo_color, Color(0.5,0.5,0.5), 2.0, \
                Tween.TRANS_LINEAR, Tween.EASE_OUT)
            tween.start()
        else:
            print("Error: Material "+str(i)+" of mesh "+meshinst.get_name()+" is null!")

ok, so this is disadvantage that when i change materials albedo color it will affect all objects with these material on my scene

in unity when you change a material property from code - then angine creates a instance of this material itself

is there any way to change albedo on one instance of object without duplicating material in godot?

Yes, there is. You can make the material unique which creates a copy of the material. Click on the material drop down and select "Make Unique" (from memory, might spell a bit different).

If you want to do this in code then you can either create a completely new material with SpatialMaterial.new() or create a duplicate() of the current material.

var mat = meshinst.get_surface_material(0).duplicate()
mat.albedo_color=Color.blue
meshinst.set_surface_material(0,mat)

wombatstampede. thanks a lot guy! it works!

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.