How can I make a transparency shader apply only when the player is behind a tree or wall, and not when in front of it?

Godot Version

4.4.1

Question

I’m trying to create a transparency effect on trees (or walls) so the player becomes visible when they go behind them.
I’ve managed to make the tree become transparent using a shader and a mask, and it works when the player is behind the tree.

However, I ran into a new issue:

The transparency shader still applies even when the player is in front of the tree, which is not what I want.

The tree is a StaticObject2D.

I applied the transparency shader to the tree scene itself.

What I want:
I want the shader to make the tree transparent only when the player is behind it (occluded).
If the player is in front of the tree, the shader effect should not apply — the tree should remain fully opaque.

it would be convenient to look at the shader code. But I think this can be solved by passing the position of the tree and the character to the shader to determine the rendering order (if you have y_sort_enabled = true, otherwise pass global z_index)

//shader:
instance uniform vec2 object_position;
uniform vec2 player_position;

void fragment() {
	// check is object infront of the player
	if (object_position.y < player_position.y){
		// your transparency code
		COLOR.a= 0.;
	}
}
#tree.gd
func _ready() -> void:
	item_rect_changed.connect(on_position_changed)

func on_position_changed():
	set_instance_shader_parameter("object_position", position);
1 Like

I already did that, and nothing happened, this isi my shader code :

shader.gd:

shader_type canvas_item;

uniform vec2 player_pos = vec2(576,324);
uniform float max_distance = 75.0;
uniform float num = 0;
uniform vec2 tree_pos = vec2(0, 0);

void fragment() {
	if (player_pos.y > tree_pos.y) {
		if (COLOR.a!=0.0){
			vec2 place = FRAGCOORD.xy;
			float distance_to_player = distance(FRAGCOORD.xy, vec2(576,324));
			COLOR.a = clamp(((distance_to_player-max_distance)/max_distance*7.0),0.1,1);
		};
	};
}

this my tree.gd :

extends StaticBody2D
@onready var animated_sprite_2d: AnimatedSprite2D = $AnimatedSprite2D
@onready var tree: StaticBody2D = $"."
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D

#func _ready() -> void:
	#animated_sprite_2d.item_rect_changed.connect(_on_position_change)
	#
#func _on_position_change():
	#set_instance_shader_parameter("tree_pos", animated_sprite_2d.position)

func player_pos(pos: Vector2) :
	print("function called ...")
	animated_sprite_2d.set_instance_shader_parameter("player_pos", pos)
	print("\npositions of player : ", pos)
	print("value of shader : ", animated_sprite_2d.get_instance_shader_parameter("player_pos"))
	print("\nvalue of tree_pos : ", animated_sprite_2d.position, "\n")

this is my world.gd(where player and tree put together in one scene) :

func _process(delta: float):
	if player_1.global_position.y < _tree.animated_sprite_2d.global_position.y :
		print("player postion in world : ", Vector2(player_1.global_position))
		var treeShader = _tree.player_pos(Vector2(player_1.global_position))
	if player_1.global_position.y > _tree.animated_sprite_2d.global_position.y :
		print("\n\nrispek, this should be i\n\n")
		print("player postion in world : ", Vector2(player_1.global_position))

this is log result :

player postion in world : (-17.0, -78.0)
function called ...

positions of player : (-17.0, -78.0)
value of shader : (-17.0, -78.0)

value of tree_pos : (0.0, -52.0)

player postion in world : (-20.53554, -74.46446)
function called ...

positions of player : (-20.53554, -74.46446)
value of shader : (-20.53554, -74.46446)

value of tree_pos : (0.0, -52.0)

player postion in world : (-24.07107, -70.92892)
function called ...

positions of player : (-24.07107, -70.92892)
value of shader : (-24.07107, -70.92892)

value of tree_pos : (0.0, -52.0)

player postion in world : (-27.6066, -67.39339)
function called ...

positions of player : (-27.6066, -67.39339)
value of shader : (-27.6066, -67.39339)

value of tree_pos : (0.0, -52.0)

player postion in world : (-31.14214, -63.85785)
function called ...

positions of player : (-31.14214, -63.85785)
value of shader : (-31.14214, -63.85785)

value of tree_pos : (0.0, -52.0)

player postion in world : (-34.67767, -60.32232)
function called ...

positions of player : (-34.67767, -60.32232)
value of shader : (-34.67767, -60.32232)

value of tree_pos : (0.0, -52.0)

player postion in world : (-38.21321, -56.78679)
function called ...

positions of player : (-38.21321, -56.78679)
value of shader : (-38.21321, -56.78679)

value of tree_pos : (0.0, -52.0)

player postion in world : (-41.74874, -53.25125)
function called ...

positions of player : (-41.74874, -53.25125)
value of shader : (-41.74874, -53.25125)

value of tree_pos : (0.0, -52.0)



rispek, this should be i


player postion in world : (-45.28428, -49.71572)


rispek, this should be i


player postion in world : (-45.28428, -44.71572)


rispek, this should be i


player postion in world : (-45.28428, -39.71572)


rispek, this should be i

you need make tree_pos a instance uniform in the shader code. Otherwise tree_pos will be similar for all trees

also, im not sure if regular uniform can be changed using .set_instance_shader_parameter() so i recommend to set player_pos by animated_sprite_2d.material.set_shader_parameter()

1 Like

thanks for the reply, I’ll try this tomorrow.

the solution for :

animated_sprite_2d.material.set_shader_parameter("player_pos", pos)

is not working, it didn’t set any value, the log result as below :
Enemy : (-2051.0, 2146.0)
Player : (3.0, -78.0)
direction : (2054.0, -2224.0)
Direction Length:3027.39038085938
player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :

value of tree_pos : (0.0, -52.0)

player postion in world : (3.0, -78.0)
function called …

positions of player : (3.0, -78.0)
value of shader :