Is it possible to map an exported var to an Instance Shader Parameter of a Child Scene in the Editor?

Godot Version

4.3

Question

My Scene has:

  • Node3D_DebugRoom
    • Tank
    • Tank

The Child Tank Scene has:

  • Tank
    • MeshInstance3D_for_Tank_Model
    • MeshInstance3D_for_Team_Color

The MeshInstance3D_for_Tank_Model is the Tank Vehicle model, while MeshInstance3D_for_Team_Color is the MeshInstance3D on certain parts of the MeshInstance3D_for_Tank_Model for color coding. Think RTS game. Some parts of the RTS units will be color coded for each team. The MeshInstance3D_for_Team_Color has a Shader Material with 1 Instance Shader Parameter which is just albedo. The whole MeshInstance3D will only have 1 simple color.

Now, the tank also an @export var team_number: int , and I could assign the team number 0 and 1 to each tank, and I can get different color with the following code in the tank’s gd script:

func _ready() -> void:
	var mi3d:MeshInstance3D = get_node("MeshInstance3D_for_Team_Color")
	mi3d.set_instance_shader_parameter("albedo", globalSingleton.TEAM_RGB[team_number])

The globalSingleton.TEAM_RGB is just a static var for BLUE and RED:

static var TEAM_RGB = [
	Vector3( 0.0, 0.0, 1.0 ), 
	Vector3( 1.0, 0.0, 0.0 )
]

With 2 tanks from above, one tank is assigned team_number 0 and the other team_number 1. When I run the game, I could already have a BLUE tank and a RED tank correctly.

HOWEVER, the _ready() constructor above only runs when the game runs. This means in the editor, my tanks will not be colored accordingly. So here is the question: in this circumstance, is it possible to make it so that the Godot Editor could change the Instance Shader Parameter with respect to the @export var team_number?

As the Tank’s Scene has MeshInstance3D_for_Team_Color as its child, I am making all Tanks in the Node3D_DebugRoom to have Editable Children, and from there, I am manually changing each Tank to have the correct color via Instance Shader Parameter right now.

Is there a better way to do what I am doing? I want the shader albedo of MeshInstance3D_for_Team_Color to changed with respect to team_number in the editor.

It may be worth looking into the @tool keyword along with get/set for @export variables.

@tool keyword will allow the script to also run in the editor.

And using the get/set keywords on an exported variable should allow you to access the shader params for that mesh.

1 Like

@GameDevOne interesting. I’ve tried this, and I learned the following:

  1. If I chose to do this, this means all the scenes that need team color will need to have @tool at the top.
  2. All functions will now need to handle whether the code will run in the editor, in the game or both.
  3. As I set my team color in the constructor, I see that the code will only run when I close the scene and open it again. There is a way to address this as seen in https://www.reddit.com/r/godot/comments/13jc41q/comment/jkejz5o/ but after playing around with this, somehow my @export var team_color just refuse to change its value. When I set it in the editor, it just changed itself back to the previous value for some reasons… it feels buggy… or I am doing something wrong.

From here, I found @tool an interesting feature, but at the same time, number 2 and 3 above make me worry… as things could get very complicated.