I'm having a hard time figuring out how to change instancing colors, linking mesh model properties to change material albedo. Then do different actions on that object depending on it's instance color. WhitePawn is my kinetic object and Pawnmtl is my mesh it's attached to. I'm using GD-script. Any help would be much appreciated.

Something similar to what I'm trying to do... https://godotforums.org/discussion/21600/is-there-a-way-to-change-what-material-an-object-is-using-using-a-script

extends Spatial

onready var spawner_white_pawn = preload("res://scenes/WhitePawn.tscn")

func _ready() -> void:

	var b1 = spawner_white_pawn.instance()
	b1.set_translation(Vector3(0,5,0))
	b1.get_node("WhitePawn/Pawnmtl")
	mat = b1.get_surface_material(0)
	mat.set_albedo() = color()     #error  can't assign to expression
	add_child(b1)

#Pawnmtl

extends MeshInstance

func _ready():
	var to_mesh = get_node("WhitePawn/Pawnmtl")
	mat = to_mesh.get_surface_material(0)	#error The identifier "mat" isn't declared in current scope

There's a few issues with the scripts. Starting with the first script: One issue is that you are using a variable that has not be defined (mat), though the debugger hasn't caught that error because its stuck on line 11. The issue at line 11 is that you are assigning the albedo to a color function, rather than to a new color object.

So, to fix script 1, the following changes are needed to the _ready function:

func _ready() -> void:
	var b1 = spawner_white_pawn.instance()
	b1.set_translation(Vector3(0, 5, 0))
	b1.get_node("WhitePawn/Pawnmtl")

	# since material is a new variable, we need to add "var"
	var mat = b1.get_surface_material(0)
	# the color property for the albedo map is called
	# "albedo_color"
	mat.albedo_color = Color(0, 0, 0, 1)
	
	add_child(b1)

For script 2, the issue is the same as script 1 when it comes to the mat variable. You just need to define it using var:

func _ready():
	var to_mesh = get_node("WhitePawn/Pawnmtl")
	var material = to_mesh.get_surface_material(0)

Thanks but for some reason on script 2 the 3rd line is giving me an error.

"Attempt to call function 'get_surface_material' in base 'null instance' on a null instance".

It also says: The local variable 'material' is declared but never used in the block. if this is intended, prefix it with an underscore: '_material'

Also for some reason it doesn't appear that the node is even being found. In the error log it says:

"E 0:00:00.637 get_node: Node not found: WhitePawn/Pawnmtl. <C++ Error> Condition "!node" is true. Returned: __null <C++ Source> scene/main/node.cpp:1381 @ get_node() <Stack Trace> Pawnmtl.gd:11 @ _ready()"

I tried to change change the node on the script 2 to

func ready(): var to_mesh = get_node("") var material = to_mesh.get_surface_material(0)

but I still got the same error this time saying: get_node: Node not found.

I think both my vars are considered null. Maybe my surface needs to be defined in the mesh script?

@Godswarth said: Thanks but for some reason on script 2 the 3rd line is giving me an error.

"Attempt to call function 'get_surface_material' in base 'null instance' on a null instance".

Okay, so that means that the node in to_mesh was not found. Does the node that the second script is attached to have a child node called WhitePawn, with a sub child called Pawnmtl?

It also says: The local variable 'material' is declared but never used in the block. if this is intended, prefix it with an underscore: '_material'

Yup, that's because in the script above you are not using the variable anywhere. If you do not need to do anything with the material variable, then you can just delete it.

Also for some reason it doesn't appear that the node is even being found. In the error log it says:

"E 0:00:00.637 get_node: Node not found: WhitePawn/Pawnmtl. <C++ Error> Condition "!node" is true. Returned: __null <C++ Source> scene/main/node.cpp:1381 @ get_node() <Stack Trace> Pawnmtl.gd:11 @ _ready()"

I tried to change change the node on the script 2 to

func ready(): var to_mesh = get_node("") var material = to_mesh.get_surface_material(0)

but I still got the same error this time saying: get_node: Node not found.

Are you trying to get the current node? Is the second script attached to the node you are wanting to get the material from? If so, you don't need to use get_node but instead can call the functions directly:

func _ready():
	var _material = get_surface_material(0)

@TwistedTwigleg said:

Okay, so that means that the node in to_mesh was not found. Does the node that the second script is attached to have a child node called WhitePawn, with a sub child called Pawnmtl?

I have a 3d spatial instance called S_Main. The scene object is a kinetic body with the name WhitePawn, it has a child node meshinstance called Pawnmtl. On the spatial script I'm spawning the instance. The second script is on the meshinstance. I don't know if the scripts are in any way attached.

I have a 3rd script called WhitePawn that I'm using for movements which seems to be being called as the node instead of the meshinstance (Pawnmtl). Something wrong when I'm calling nodes I don't know what it is. debugger says: "Invalid call. Nonexistent function 'get_surface_material' in base 'KinematicBody (WhitePawn.gd)".

extends spatial

onready var spawner_white_pawn = preload("res://scenes/WhitePawn.tscn")

func _ready() -> void:

	var b1 = spawner_white_pawn.instance()
	b1.set_translation(Vector3(0,5,0))
	b1.get_node("WhitePawn/Pawnmtl")
	# since material is a new variable, we need to add "var"
	var mat = b1.get_surface_material(0)
	# the color property for the albedo map is called
	# "albedo_color"
	mat.albedo_color = Color(0, 0, 0, 1)
	add_child(b1)

@TwistedTwigleg said:

Are you trying to get the current node? Is the second script attached to the node you are wanting to get the material from? If so, you don't need to use get_node but instead can call the functions directly:

func _ready():
	var _material = get_surface_material(0)

I was trying to get the node on the node it was in...

Is the issue about the KinematicBody not having the method on the first script, or the second script?

If it is the first script, maybe try this and see if it works?

extends spatial

onready var spawner_white_pawn = preload("res://scenes/WhitePawn.tscn")

func _ready() -> void:

	var b1 = spawner_white_pawn.instance()
	b1.set_translation(Vector3(0,5,0))
	# assuming the root node in the WhitePawn scene is called
	# "WhitePawn", we can skip it and just try to get the MeshInstance node from
	# the scene
	b1.get_node("Pawnmtl")
	# since material is a new variable, we need to add "var"
	var mat = b1.get_surface_material(0)
	# the color property for the albedo map is called
	# "albedo_color"
	mat.albedo_color = Color(0, 0, 0, 1)
	add_child(b1)

Based on the error, the issue seems to be that the node that is having get_surface_material called on it is a KinematicBody node rather than a MeshInstance, so that means we're getting the wrong node.

If it is the second script, then the issue is probably that the script needs to get the MeshInstance node first. If it's a child node called Pawnmtl, then the second script's _ready function should be adjusted to the following:

func _ready():
	var material = get_node("Pawntml").get_surface_material(0)

That last line was what I needed. but how do I make it so not everyone I spawn is the same color. I want to spawn the same object with different colors but they are all linked together changing one changes them all.

Note: never mind I found out how to just "resource_local_to_scene" true. Thanks for all your help.

2 years later