It is possible to check occlusion between a node and the camera with the DEPTH_TEXTURE?

Godot Version

Godot 4.2.1.stable

Question

I am trying to make a lens flare shader in 3D, for occlusion/collision, how can I check if there is any geometry in between the camera and the node position? I think the better way is using the depth texture, but I don’t know if is even possible.

The right code should be like when the exact node position got behind some geometry, the alpha of every fragment got to zero, like the lens flare effect

Example: https://youtu.be/EGM3xDUu1BE?si=0Hl2bend50QQOSQs&t=90

For now, I have this, a shader that do a simple depth test, I am very new to depth texture related shaders…

image

shader_type spatial;
render_mode unshaded, cull_disabled, depth_test_disabled;

uniform sampler2D DEPTH_TEXTURE: hint_depth_texture, filter_nearest;

void vertex() {
	MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], INV_VIEW_MATRIX[1], INV_VIEW_MATRIX[2], MODEL_MATRIX[3]);
	MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);
}

void fragment() {
	float depth = texture(DEPTH_TEXTURE, SCREEN_UV).r;
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);

	vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	view.xyz /= view.w;

	float linear_depth = min(max(-view.z - (-NODE_POSITION_VIEW.z), 0.0), 0.001) / 0.001;

	ALBEDO = vec3(linear_depth, 0.0, 0.0); 
}

Coming back to it today, I founded one solution, pass the unprojected position of the node via code, then maps this position into the screen:

The GDScript code:

extends MeshInstance3D

func _process(delta: float) -> void:
	var unprojected_position: Vector2 = get_viewport().get_camera_3d().unproject_position(global_position);

	var shader_material: ShaderMaterial = material_override as ShaderMaterial
	shader_material.set_shader_parameter("unprojected_position", unprojected_position)

The shader:

shader_type spatial;
render_mode unshaded, cull_disabled, depth_test_disabled;

uniform vec2 unprojected_position = vec2(0.0);

uniform sampler2D DEPTH_TEXTURE: hint_depth_texture, filter_nearest;

void vertex() {
	MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], INV_VIEW_MATRIX[1], INV_VIEW_MATRIX[2], MODEL_MATRIX[3]);
	MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);
}


void fragment() {
	vec2 pixel_size = 1.0 / VIEWPORT_SIZE;
	vec2 uv = (unprojected_position * pixel_size);

	float depth = texture(DEPTH_TEXTURE, uv).r;
	vec3 ndc = vec3(uv * 2.0 - 1.0, depth);

	vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	view.xyz /= view.w;

	float linear_depth = min(max(-view.z - (-NODE_POSITION_VIEW.z), 0.0), 0.001) / 0.001;

	ALPHA = linear_depth;
}

The helpers
Advanced Screen Space Shaders: Godot Guide
How to set uv coordinates in shaders in godot to be by pixel, not from 0 to 1?

Works as intended :surfing_man:

1 Like