How do I correctly load a shader / modify its variables?

Godot Version

4.3

Question

I’m trying out shaders for the first time, and I need to apply an outline to my character sometimes.
The method I wanted to use was to completely remove the shader when it’s not needed, and then load it again.
This is my shader for context:
image
I’ve tried a lot of things, but none seem to work correctly. This is the code I use to load shaders (doesn’t work):

const passengerShader:Resource = preload("res://other/shaders/passenger.gdshader")
var isPassenger:bool = false

func _ready() -> void: #Gives a random skin to the passenger
	rng = RandomNumberGenerator.new()
	var weights = PackedFloat32Array([0.7, 1, 0.3, 1, 1])
	var randomNumber:int = rng.rand_weighted(weights)
	print(randomNumber)
	match randomNumber:
		0: sprite.texture = load("res://sprites/npcs/baldMan.png")
		1: sprite.texture = load("res://sprites/npcs/hoodieMan.png")
		2: sprite.texture = load("res://sprites/npcs/jonkler.png")
		3: sprite.texture = load("res://sprites/npcs/man.png")
		4: 
			isPassenger = true
			sprite.texture = load("res://sprites/npcs/woman.png")
			
	print(sprite.material.shader)
	rng = null

func _physics_process(delta: float) -> void:
	if isPassenger:
		if sprite.material.shader != passengerShader: sprite.material.shader = passengerShader
		sprite.material.shader.set_shader_parameter("progress", 1)
		sprite.material.shader.set_shader_parameter("width", 0.003)


#All this is connected to a VisibleOnScreenNotifier2D
func _visible_entered() -> void:
	if isPassenger: sprite.material.shader = passengerShader
	sprite.visible = true
	
func _visible_exited() -> void:
	sprite.material.shader = null
	sprite.visible = false

Lastly, it also tells me that set_shader_parameter doesn’t exist in base shader.
I understand that it means that the function doesn’t exist, but I cannot find any other substitute online or in the docs.

Any help is appreciated, thanks in advance.

I have some code here that does the following (there’s no material.shader, just material):

func set_position(node: Node, position: Vector2) -> void:
	var _shader := node.material as ShaderMaterial

	if _shader:
		_shader.set_shader_parameter("slide", position)

You may also use an instance uniform in your shader:

instance uniform float alpha: hint_range(0.0, 1.0, 0.01) = 1.0;

And then set the uniform value in the mesh instance using the material instead of the material itself (good to not propagate the change to all instances using the same material):

mesh_instance.set("instance_shader_parameters/alpha", value)
1 Like