Documentation
struct TriangleParams {
    p0: vec2<f32>,          //⬅️ 顶点位置1
    p1: vec2<f32>,          //⬅️ 顶点位置2
    p2: vec2<f32>,          //⬅️ 顶点位置3
    fill_color: vec4<f32>,  //⬅️ 填充颜色
    border_thickness: f32,  //⬅️ 边框宽度
    border_color: vec4<f32>,//⬅️ 边框颜色
};
@group(0) @binding(0)
var<uniform> params: TriangleParams;

struct VertexOutput {
    @builtin(position) position: vec4<f32>,
};

@vertex
fn vs_main(@builtin(vertex_index) index: u32) -> VertexOutput {
    var positions = array<vec2<f32>, 6>(
        vec2<f32>(-1.0, -1.0),
        vec2<f32>( 1.0, -1.0),
        vec2<f32>( 1.0,  1.0),
        vec2<f32>( 1.0,  1.0),
        vec2<f32>(-1.0,  1.0),
        vec2<f32>(-1.0, -1.0),
    );
    var out: VertexOutput;
    out.position = vec4<f32>(positions[index], 0.0, 1.0);
    return out;
}

fn edge(a: vec2<f32>, b: vec2<f32>, p: vec2<f32>) -> f32 {
    return (p.x - a.x) * (b.y - a.y) - (p.y - a.y) * (b.x - a.x);
}

fn sdEquilateralTriangle(p: vec2<f32>, a: vec2<f32>, b: vec2<f32>, c: vec2<f32>) -> f32 {
    // 三角形边向量
    let e0 = b - a;
    let e1 = c - b;
    let e2 = a - c;

    // 点到边的向量
    let v0 = p - a;
    let v1 = p - b;
    let v2 = p - c;

    // 投影到边上的距离
    let pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0);
    let pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0);
    let pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0);

    let d = min(length(pq0), min(length(pq1), length(pq2)));

    // 判断点是否在三角形内部
    let s = sign(e0.x * e2.y - e0.y * e2.x);
    let inside = sign(edge(a, b, p)) == s &&
                 sign(edge(b, c, p)) == s &&
                 sign(edge(c, a, p)) == s;
    var res=d;
    if inside { res=-d; } else { res=d; }


    return res;
}

@fragment
fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
    let p = pos.xy;

    let dist = sdEquilateralTriangle(p, params.p0, params.p1, params.p2);
    let aa = fwidth(dist);

    var fill_color = params.fill_color;
    var border_color = params.border_color;

    // 内部填充 alpha
    let inside_alpha = smoothstep(-aa, 0.0, -dist); // dist<0: inside

    var color = fill_color;

    // 边框抗锯齿
    if (params.border_thickness > 0.0) {
        let border_outer = params.border_thickness + aa;
        let border_inner = params.border_thickness - aa;

        // border_alpha 只在距离边界 dist ~ border_thickness 附近生效
        let border_alpha = smoothstep(border_outer, border_inner, abs(dist));

        // 将边框混合到填充色上
        color = mix(color, border_color, border_alpha);
    }

    return vec4(color.rgb, inside_alpha);
}