使用演示

实现解析

着色器脚本(矩形)

shader_type spatial;
render_mode unshaded, depth_draw_never, skip_vertex_transform;

uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; // 深度贴图
uniform sampler2D gradient_texture  : repeat_disable;

instance uniform vec3 range = vec3(1.0); // 范围
uniform float camera_near = 0.05; //(设为相机近平面距离)

void vertex() {
	// 顶点变换到视图空间
	vec4 VIEW_VERTEX = MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
	// 确保在放大时网格不被近平面剪裁
	VIEW_VERTEX.z = min(VIEW_VERTEX.z, -camera_near);
	VERTEX = VIEW_VERTEX.xyz;
}

void fragment() {
	// https://docs.godotengine.org/zh-cn/4.x/tutorials/shaders/advanced_postprocessing.html#depth-texture
	float depth = texture(depth_texture, SCREEN_UV).x; // 获取深度纹理
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth); // xy 原点轴屏幕居中
	vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	vec3 world_position = world.xyz / world.w; // 获取世界坐标

	// 将世界坐标转换为物体的局部坐标
	vec3 local_position = (inverse(MODEL_MATRIX) * vec4(world_position, 1.0)).xyz;
//
	//// 计算物体局部坐标系中的距离
	vec3 center_distance = abs(local_position); // 使用局部坐标
	if (center_distance.x >= range.x || center_distance.y >= range.y || center_distance.z >= range.z) discard; // 剪切范围外像素
	center_distance = 1.0 - center_distance / range; // 计算映射
	vec4 gradient = texture(gradient_texture, vec2(center_distance.x * center_distance.y * center_distance.z)); // 映射过度
//
	ALBEDO = gradient.rgb;
	ALPHA = gradient.a;
	
	//ALBEDO = vec3(center_distance.x * center_distance.y * center_distance.z);
	//ALBEDO = vec3(center_distance.x);
}

着色器脚本(圆形)

shader_type spatial;
render_mode unshaded, depth_draw_never, skip_vertex_transform;

uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; // 深度贴图
uniform sampler2D gradient_texture  : repeat_disable;

instance uniform float range = 1.0; // 范围
uniform float camera_near = 0.05; //(设为相机近平面距离)

void vertex() {
	// 顶点变换到视图空间
	vec4 VIEW_VERTEX = MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
	// 确保在放大时网格不被近平面剪裁
	VIEW_VERTEX.z = min(VIEW_VERTEX.z, -camera_near);
	VERTEX = VIEW_VERTEX.xyz;
}

void fragment() {
	// https://docs.godotengine.org/zh-cn/4.x/tutorials/shaders/advanced_postprocessing.html#depth-texture
	float depth = texture(depth_texture, SCREEN_UV).x; // 获取深度纹理
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth); // xy 原点轴屏幕居中
	vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	vec3 world_position = world.xyz / world.w; // 获取世界坐标

	float center_distance = distance(NODE_POSITION_WORLD, world_position); // 相对于物体的距离
	if (center_distance >= range) discard; // 剪切范围外像素
	vec4 gradient = texture(gradient_texture, vec2(center_distance / range)); // 映射过度

	ALBEDO = gradient.rgb;
	ALPHA = gradient.a;
	//ALBEDO = vec3(world_position.z);
}

着色器脚本(锥形)

shader_type spatial;
render_mode unshaded, depth_draw_never, skip_vertex_transform;

uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; // 深度贴图
uniform sampler2D gradient_texture  : repeat_disable;

instance uniform float range = 1.0; // 范围
instance uniform float cone_angle = 30; // 锥形的角度
uniform float camera_near = 0.05; //(设为相机近平面距离)

void vertex() {
	// 顶点变换到视图空间
	vec4 VIEW_VERTEX = MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
	// 确保在放大时网格不被近平面剪裁
	VIEW_VERTEX.z = min(VIEW_VERTEX.z, -camera_near);
	VERTEX = VIEW_VERTEX.xyz;
}

void fragment() {
	float radian = radians(cone_angle);
	
	// https://docs.godotengine.org/zh-cn/4.x/tutorials/shaders/advanced_postprocessing.html#depth-texture
	float depth = texture(depth_texture, SCREEN_UV).x; // 获取深度纹理
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth); // xy 原点轴屏幕居中
	vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	vec3 world_position = world.xyz / world.w; // 获取世界坐标

	// 将世界坐标转换为物体的局部坐标
	vec3 local_position = (inverse(MODEL_MATRIX) * vec4(world_position, 1.0)).xyz;
	vec3 direction_to_fragment = normalize(world_position - NODE_POSITION_WORLD);

	// 计算圆
	float center_distance = distance(NODE_POSITION_WORLD, world_position); // 相对于物体的距离
	if (center_distance >= range) discard; // 剪切范围外像素

	// 计算从物体中心到片段的方向
	vec3 object_up_direction = normalize(mat3(MODEL_MATRIX) * vec3(0.0, 1.0, 0.0));

	// 计算方向向量之间的点积,并通过反余弦函数获取角度
	float angle = acos(dot(direction_to_fragment, object_up_direction));

	// 如果角度大于锥角,则丢弃片段
	if (angle > radian)discard;

	vec4 gradient = texture(gradient_texture, vec2((1.0 - (angle / PI) / (radian / PI)) * (1.0 - center_distance / range))); // 映射过度

	if ((1.0 - (angle / PI) / (radian / PI)) * (1.0 - center_distance / range) <= 0.0)discard;

	ALBEDO = gradient.rgb;
	ALPHA = gradient.a;
	
	//ALBEDO = vec3( (1.0 - (angle / PI) / (radian / PI)) * (1.0 - center_distance / range) );
	//ALBEDO = vec3(world_position.z);
}

着色器脚本(距离场)

shader_type spatial;
render_mode unshaded, depth_draw_never, skip_vertex_transform;

uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; // 深度贴图
uniform sampler2D gradient_texture  : repeat_disable;

instance uniform float angle = 30.0; // 锥形的顶角度
instance uniform vec3 range = vec3(1.0); // 范围
instance uniform float rounded = 1.0; // 圆角
uniform float camera_near = 0.05; //(设为相机近平面距离)

// https://iquilezles.org/articles/distfunctions/
// p:点的位置 b:盒子尺寸 r:圆角半径
float sdRoundBox( vec3 p, vec3 b, float r )
{
	// 距离场 max 取正值 min 取负值
	vec3 q = abs(p) - b;
	return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0) - r;
}

float sdCone( vec3 p,vec2 c)
{
	vec2 q = vec2( length(p.xz), -p.y );
	float d = length(q-c*max(dot(q,c), 0.0));
	return d * ((q.x*c.y-q.y*c.x<0.0)?-1.0:1.0);
}

void vertex() {
	// 顶点变换到视图空间
	vec4 VIEW_VERTEX = MODELVIEW_MATRIX * vec4(VERTEX, 1.0);
	// 确保在放大时网格不被近平面剪裁
	VIEW_VERTEX.z = min(VIEW_VERTEX.z, -camera_near);
	VERTEX = VIEW_VERTEX.xyz;
}

void fragment() {
	// https://docs.godotengine.org/zh-cn/4.x/tutorials/shaders/advanced_postprocessing.html#depth-texture
	float depth = texture(depth_texture, SCREEN_UV).x; // 获取深度纹理
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth); // xy 原点轴屏幕居中
	vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	vec3 world_position = world.xyz / world.w; // 获取世界坐标

	// 将世界坐标转换为物体的局部坐标
	vec3 local_position = (inverse(MODEL_MATRIX) * vec4(world_position, 1.0)).xyz;

	// 距离场
	float radian = radians(angle/2.0);
	float center_distance = max(sdRoundBox(local_position, range-rounded, rounded),sdCone(local_position, vec2(sin(radian),cos(radian))));
	if (angle <= 360.0){
		center_distance = max(sdRoundBox(local_position, range-rounded, rounded),sdCone(local_position, vec2(sin(radian),cos(radian))));
	}else{
		center_distance = sdRoundBox(local_position, range-rounded, rounded);
	}
	if (center_distance >= 0.0) discard; // 剪切范围外像素
	vec4 gradient = texture(gradient_texture, vec2(-center_distance)); // 映射过度

	ALBEDO = gradient.rgb;
	ALPHA = gradient.a;

	//ALBEDO = vec3(center_distance.x * center_distance.y * center_distance.z);
	//ALBEDO = vec3(world_position.z);
}

着色器脚本(后处理)

shader_type spatial;
render_mode unshaded, depth_draw_never;

uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest; // 深度贴图
uniform sampler2D gradient_texture  : repeat_disable;

instance uniform vec3 position; // 位置
instance uniform float range = 1.0; // 范围
uniform float camera_near = 0.05; //(设为相机近平面距离)


void fragment() {
	// https://docs.godotengine.org/zh-cn/4.x/tutorials/shaders/advanced_postprocessing.html#depth-texture
	float depth = texture(depth_texture, SCREEN_UV).x; // 获取深度纹理
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth); // xy 原点轴屏幕居中
	vec4 world = INV_VIEW_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	vec3 world_position = world.xyz / world.w - position; // 获取世界坐标

	float center_distance = distance(NODE_POSITION_WORLD, world_position); // 相对于物体的距离
	if (center_distance >= range) discard; // 剪切范围外像素
	vec4 gradient = texture(gradient_texture, vec2(center_distance / range)); // 映射过度

	ALBEDO = gradient.rgb;
	ALPHA = gradient.a;
	//ALBEDO = vec3(world_position.z);
}

网格脚本(后处理)

@tool
extends MeshInstance3D

@export var target: Node3D

func _process(delta: float) -> void:
	set_instance_shader_parameter("position", target.global_position - global_position)