Dragging shader into material slot or making changes to a shader makes object turn black

Godot Version

Replicated in 4.1 and 4.3

Question

So far this is happening with custom toon/cel shaders I’m using for trees and characters (two separate shaders with different parameters). I have the shader working perfectly on multiple trees and characters.

When I make changes to the shader code, whichever scene I’m working in, updates as I make changes and looks fine, however when I go to another scene with objects using that same shader they have all turned black and no changes I make to the exposed parameters have any effect.

If I clear the material slot and drag the shader back in they are still black. The only way to fix them is to copy the shader from an object in which it’s working and past it into the material slot for one where the shader is not working. Then it works fine, I just have to reset all the parameters and re-drag in all the textures for each object, which is not sustainable for large projects).

Likewise if I bring in a brand new object that never had the shader in the material slot to begin with, and I try dragging the shader from the outliner into the material slot, the object just turns black and none of the parameters work. I have to also copy the shader from an instance in which it is working and past it into the material slot for the new object.

Also, if I just create a new shader in the material slot of one of the broken objects, and past in all the exact same shader code, the shader works properly.

I just can’t drag shaders from a directory into a material slot or make changes to them without them breaking.

While I have not run into this specific issue, I did run into a very similar one.

I recommend not defining a material for any shader you are using in a class. Instead, create the material when you create the object from the class. This means you also need to define the shader on creation - but it is fairly simple to do.

@onready var sprite: Sprite2D = %Sprite
@onready var fire_shader: Shader = preload(ShadersMap.BUILDING_FIRE)


# Called from _ready()
sprite.material = ShaderMaterial.new()
sprite.material.shader = fire_shader