惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
aimingoo的专栏
aimingoo的专栏
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
The Cloudflare Blog
量子位
T
Tailwind CSS Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
G
Google Developers Blog
D
DataBreaches.Net
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
U
Unit 42
博客园 - 聂微东
有赞技术团队
有赞技术团队
A
About on SuperTechFans

博客园 - porter_代码工作者

给 codex 的长期任务,长沙一个定时任务,做保活功能 .net nupkgs 配置 Vibe Coding ---- 2026年3月 很火的词 bigemap 软件 godot 透明 与 混合模式 叠加使用效果 AI 回复 C# ScottPlot 高性能图表 高性能绘图库 godot + Avalonia 渲染第三方UI 判断左手坐标系和右手坐标系的方法 国产操作系统: 项目配置 .net 添加Nuget源 godot 位置 和 角度 的平滑插值 godot 通过代码程序化地生成一个三维数据场,然后使用光线步进(Ray Marching)着色器将其渲染出来。 godot shader 等高线的绘制 和 模型描边的绘制 和 shader 常用算法 godot shader 控制 颜色绘制的 金典公式 godot 四元数 旋转 godot 二维报表库 godot 5.4.4 线程安全的调用方法 godot FPS 第三人称教程 UE4脸部捕捉 LiveLink 数据 常用四元数的值 unity Avatar (化身) 使用electron-builder打包 vue3 项目 exe
godot 描边插件
porter_代码工作者 · 2025-11-03 · via 博客园 - porter_代码工作者
shader_type spatial;
render_mode unshaded;

/*
    Normal/Depth outline shader. Apply to nodes as a next pass shader texture.
    Inspired by Yui Kinomoto @arlez80, lukky_nl (YT), Robin Seibold (YT)
    Uses Sobel Edge detection on a normal and depth texture
    Written by William Li (LoudFlameLava)

    MIT License
*/

// Might create an outline at the edge of the viewport

uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear_mipmap;
uniform sampler2D NORMAL_TEXTURE : hint_normal_roughness_texture, filter_linear_mipmap;

uniform float normal_threshold = 0.1;
uniform float depth_threshold = 0.05;
uniform float depth_artifact_correction_coef = 2;
uniform vec3 outline_color: source_color;

const mat3 sobel_y = mat3(
    vec3(1.0, 0.0, -1.0),
    vec3(2.0, 0.0, -2.0),
    vec3(1.0, 0.0, -1.0)
);

const mat3 sobel_x = mat3(
    vec3(1.0, 2.0, 1.0),
    vec3(0.0, 0.0, 0.0),
    vec3(-1.0, -2.0, -1.0)
);

float edge_value_normal(sampler2D normal_tex, vec2 uv, vec2 pixel_size, mat3 sobel) {
    float output = 0.0;
    vec3 normal = texture(normal_tex, uv).rgb;
    vec3 n = texture(NORMAL_TEXTURE, uv + vec2(0.0, -pixel_size.y)).rgb;
    vec3 s = texture(NORMAL_TEXTURE, uv + vec2(0.0, pixel_size.y)).rgb;
    vec3 e = texture(NORMAL_TEXTURE, uv + vec2(pixel_size.x, 0.0)).rgb;
    vec3 w = texture(NORMAL_TEXTURE, uv + vec2(-pixel_size.x, 0.0)).rgb;
    vec3 nw = texture(NORMAL_TEXTURE, uv + vec2(-pixel_size.x, -pixel_size.y)).rgb;
    vec3 ne = texture(NORMAL_TEXTURE, uv + vec2(pixel_size.x, -pixel_size.y)).rgb;
    vec3 sw = texture(NORMAL_TEXTURE, uv + vec2(-pixel_size.x, pixel_size.y)).rgb;
    vec3 se = texture(NORMAL_TEXTURE, uv + vec2(pixel_size.x, pixel_size.y)).rgb;

    mat3 error_mat = mat3(
        vec3(length(normal - nw), length(normal - n), length(normal - ne)),
        vec3(length(normal - w), 0.0, length(normal - e)),
        vec3(length(normal - sw), length(normal - s), length(normal - se))
    );

    output += dot(sobel[0], error_mat[0]);
    output += dot(sobel[1], error_mat[1]);
    output += dot(sobel[2], error_mat[2]);
    return abs(output);
}

float get_depth(sampler2D depth_tex, vec2 uv, mat4 inv_projection_matrix) {
    float depth_raw = texture(depth_tex, uv).x;
    vec3 ndc = vec3(uv * 2.0 - 1.0, depth_raw);
    vec4 view = inv_projection_matrix * vec4(ndc, 1.0);
    view.xyz /= view.w;
    float depth_linear = -view.z;
    return depth_linear;
}

float edge_value_depth(sampler2D depth_tex, vec2 uv, vec2 pixel_size, mat3 sobel, mat4 inv_projection_matrix){
    float output = 0.0;
    float depth = get_depth(depth_tex, uv, inv_projection_matrix);
    float n = get_depth(depth_tex, uv + vec2(0.0, -pixel_size.y), inv_projection_matrix);
    float s = get_depth(depth_tex, uv + vec2(0.0, pixel_size.y), inv_projection_matrix);
    float e = get_depth(depth_tex, uv + vec2(pixel_size.x, 0.0), inv_projection_matrix);
    float w = get_depth(depth_tex, uv + vec2(-pixel_size.x, 0.0), inv_projection_matrix);
    float ne = get_depth(depth_tex, uv + vec2(pixel_size.x, -pixel_size.y), inv_projection_matrix);
    float nw = get_depth(depth_tex, uv + vec2(-pixel_size.x, -pixel_size.y), inv_projection_matrix);
    float se = get_depth(depth_tex, uv + vec2(pixel_size.x, pixel_size.y), inv_projection_matrix);
    float sw = get_depth(depth_tex, uv + vec2(-pixel_size.x, pixel_size.y), inv_projection_matrix);

    mat3 error_mat = mat3(
        vec3((depth - nw)/depth, (depth - n)/depth, (depth - ne)/depth),
        vec3((depth - w)/depth, 0.0, (depth - e)/depth),
        vec3((depth - sw)/depth, (depth - s)/depth, (depth - se)/depth)
    );

    output += dot(sobel[0], error_mat[0]);
    output += dot(sobel[1], error_mat[1]);
    output += dot(sobel[2], error_mat[2]);
    return abs(output);
}

vec3 get_world_position(vec2 screen_uv, float depth, mat4 _INV_PROJECTION_MATRIX, mat4 _INV_VIEW_MATRIX) {
    // Convert screen UV to NDC
    vec4 ndc = vec4(screen_uv * 2.0 - 1.0, depth, 1.0);

    // Convert NDC to view space
    vec4 view_space_pos = _INV_PROJECTION_MATRIX * ndc;
    view_space_pos /= view_space_pos.w;

    // Convert view space to world space
    vec4 world_space_pos = _INV_VIEW_MATRIX * view_space_pos;

    return world_space_pos.xyz;
}

void fragment() {
    float has_outline = 0.0;
    vec2 pixel_size = vec2(1.0) / VIEWPORT_SIZE * 0.2;
    ALBEDO = texture(SCREEN_TEXTURE, SCREEN_UV).xyz;
    //ALBEDO = vec3(get_depth(DEPTH_TEXTURE, SCREEN_UV, INV_PROJECTION_MATRIX));
    if (edge_value_normal(NORMAL_TEXTURE, SCREEN_UV, pixel_size, sobel_x) + edge_value_normal(NORMAL_TEXTURE, SCREEN_UV, pixel_size, sobel_y) > normal_threshold){
        ALBEDO = outline_color;
        has_outline += 1.0;
    }
    vec3 normal = texture(NORMAL_TEXTURE, SCREEN_UV).rgb;
    float angle = 1.0 - dot(normalize(normal-vec3(0.5)),  vec3(0.0,0.0,1.0));
    if (edge_value_depth(DEPTH_TEXTURE, SCREEN_UV, pixel_size, sobel_x, INV_PROJECTION_MATRIX) + edge_value_depth(DEPTH_TEXTURE, SCREEN_UV, pixel_size, sobel_y, INV_PROJECTION_MATRIX) > depth_threshold + angle * depth_artifact_correction_coef){
        ALBEDO = outline_color;
        has_outline += 1.0;
    }
    if (has_outline < 0.1){
        ALPHA = 0.0;
    }

    float worldY = get_world_position(SCREEN_UV, texture(DEPTH_TEXTURE, SCREEN_UV).x, INV_PROJECTION_MATRIX, INV_VIEW_MATRIX).y;

    ALPHA *= clamp((worldY + 70.0) / 70.0, 0.0, 1.0);
}