1
This commit is contained in:
2025-06-23 16:09:04 +08:00
parent 94f09b8dd9
commit 12fbe9debf
757 changed files with 11656 additions and 13580 deletions

View File

@@ -0,0 +1,108 @@
shader_type canvas_item;
uniform bool allow_out_of_bounds = true;
uniform float outline_thickness: hint_range(0.0, 16.0, 1.0) = 1.0;
uniform vec4 outline_color: source_color = vec4(1.0);
uniform int quality: hint_range(1, 3, 1) = 2; // 1=低质量但快速, 2=平衡, 3=高质量但慢
uniform bool use_fast_mode = true; // 快速模式,牺牲一点质量换取性能
bool is_inside_usquare(vec2 x) {
return x == clamp(x, vec2(0.0), vec2(1.0));
}
vec4 blend(vec4 bottom, vec4 top) {
float alpha = top.a + bottom.a * (1.0 - top.a);
if (alpha < 0.0001) return vec4(0.0);
vec3 color = mix(bottom.rgb * bottom.a, top.rgb, top.a) / alpha;
return vec4(color, alpha);
}
void vertex() {
if (allow_out_of_bounds) VERTEX += (UV * 2.0 - 1.0) * outline_thickness;
}
void fragment() {
if (outline_thickness <= 0.0 || outline_color.a <= 0.0) {
COLOR = texture(TEXTURE, UV);
} else {
vec2 uv = UV;
vec4 texture_color = texture(TEXTURE, UV);
if (allow_out_of_bounds) {
vec2 texture_pixel_size = vec2(1.0) / (vec2(1.0) / TEXTURE_PIXEL_SIZE + vec2(outline_thickness * 2.0));
uv = (uv - texture_pixel_size * outline_thickness) * TEXTURE_PIXEL_SIZE / texture_pixel_size;
if (is_inside_usquare(uv)) {
texture_color = texture(TEXTURE, uv);
} else {
texture_color = vec4(0.0);
}
}
// 如果当前像素已经有alpha且不是在边缘可以跳过复杂计算
if (texture_color.a > 0.9) {
COLOR = texture_color;
} else {
float alpha = 0.0;
if (use_fast_mode) {
// 快速模式:使用较少的采样点
float step_size = max(1.0, outline_thickness / 4.0);
int max_samples = 32; // 限制最大采样数
int sample_count = 0;
for (float radius = step_size; radius <= outline_thickness && sample_count < max_samples; radius += step_size) {
// 使用8个方向的采样点
vec2 directions[8] = {
vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(0.0, 1.0), vec2(0.0, -1.0),
vec2(0.707, 0.707), vec2(-0.707, 0.707), vec2(0.707, -0.707), vec2(-0.707, -0.707)
};
for (int i = 0; i < 8; i++) {
vec2 sample_uv = uv + directions[i] * radius * TEXTURE_PIXEL_SIZE;
if (is_inside_usquare(sample_uv)) {
float sample_alpha = texture(TEXTURE, sample_uv).a;
alpha = max(alpha, sample_alpha);
sample_count++;
if (alpha > 0.99) break; // 早期退出
}
}
if (alpha > 0.99) break; // 早期退出
}
} else {
// 原始高质量模式,但有优化
int max_thickness = int(min(outline_thickness, float(8 + quality * 4))); // 限制最大厚度
for (int y = 1; y <= max_thickness; y++) {
for (int x = 0; x <= y; x++) {
float dist = length(vec2(float(x), float(y) - 0.5));
if (dist > outline_thickness) break;
vec2 offsets[8] = {
vec2(float(x), float(y)), vec2(float(-x), float(y)),
vec2(float(x), float(-y)), vec2(float(-x), float(-y)),
vec2(float(y), float(x)), vec2(float(-y), float(x)),
vec2(float(y), float(-x)), vec2(float(-y), float(-x))
};
for (int i = 0; i < 8; i++) {
vec2 sample_uv = uv + offsets[i] * TEXTURE_PIXEL_SIZE;
if (is_inside_usquare(sample_uv)) {
float sample_alpha = texture(TEXTURE, sample_uv).a;
alpha = max(alpha, sample_alpha);
if (alpha > 0.99) break; // 早期退出
}
}
if (alpha > 0.99) break; // 早期退出
}
if (alpha > 0.99) break; // 早期退出
}
}
COLOR = blend(vec4(outline_color.rgb, alpha * outline_color.a), texture_color);
}
}
}