Shader resource file

Godot Version

4.6

Question

Hi everyone!

I worked on a shader that should replace colors (based on this color-swap shader) and saved it to a file (the material too). So, when I load the material with the shader into a sprite, all the sprites applies the same color. My shader has a parameter (an int that should be 0 or 1) and based on that parameter, the shader will apply a set of colors.

My question is: I know shaders and materials are Resource, so they will apply their effects to all objects that load them. Do I have a way to make my shader apply its effects separately for each object, even with the shader being a file loaded? To contextualize, this is for chess pieces, so the parameter would define whether the piece is white or black, and set the colors in the sprite.

I thought that I could just save the file, define a shader parameter to set the color, but when I change the parameter for one piece, it changes to all pieces. Pieces and shaders should be instantiated and loaded at run time.

Shader parameters are kept in material resources. In order to have unique parameters you need to duplicate the material resource (while shader resource can still be shared). You can do this either by manual duplication or, if the material is inside a scene, enable material’s resource_local_to_scene_flag, which will instruct the engine to automatically duplicate upon scene instantiation.

What normalized said is correct for normal uniforms, but you also have the option of using instance uniforms that can be set on a per-object basis. See the guide below:

I use this to overcome that limitation. Applies the shader to each sprite only when I need it.

class_name ShaderController

class ShaderShared: 
	var sprite: Sprite2D
	var shader_material := ShaderMaterial.new()
	var shader: Shader 
	
	func _init(new_sprite: Sprite2D) -> void:
		sprite = new_sprite
		sprite.material = shader_material
		
	
	func setup() -> void: 
		sprite.material.shader = shader
		

class Dissolve extends ShaderShared:
	func _init(new_sprite: Sprite2D) -> void:
		super(new_sprite)
		shader = ShaderAtlas.DISSOLVE
		

var sprite: Sprite2D
var shader_instance = ShaderController.Dissolve.new(sprite)
shader_instance.setup()

omg since when do we have this beautiful option in shader language???

Looks like they were originally implemented for 3D objects in 4.0[1] and later implemented for 2D objects and Compatibility in 4.4.[2][3]


  1. GH-37949 ↩︎

  2. GH-99230 ↩︎

  3. GH-96819 ↩︎