Files
HelloVulkan/shaders/debug/outline.frag
T
atdunbg f73e52926f Reorganize directory layout: editor panels/, grouped shaders, drop stale header
- App/editor: move 7 panels into panels/ (Editor core stays at root)
- shaders/: group into pbr/ post/ debug/ env/ (runtime load paths updated)
- Delete outdated duplicate Engine/src/Renderer/VulkanAssetUploader.h
2026-10-07 09:52:17 +08:00

62 lines
2.6 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#version 450
// UE 编辑器选中描边:对 SelectionMask 做 16 方向圆周边缘检测,
// alpha 叠加在 Tonemap 之后的 PresentTarget 上(LDR 恒定 UI 色,
// 不进 bloom/曝光/TAA——与 UE 编辑器选中轮廓一致)。
//
// 规则:
// 外描边 自身 mask=0 且邻域有 1 → 描边(物体外圈一圈)
// 贴边线 自身 mask=1 且邻域采样越出视口(视为 0)→ 描边——物体
// 延伸出视口时 mask 在边缘截断,描边自动贴着渲染视口边缘
// 完全出视野 mask 全 0 → 无描边
// 描边不做深度遮挡判定(透墙可见)——UE 编辑器同行为,便于找到
// 被挡住的选中物体。
layout(location = 0) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
layout(set = 0, binding = 0) uniform sampler2D maskImage;
// 全屏 pass 通用 push(16B,程序级统一声明,VUID-08878)。
// 注意:必须用 4×float 平铺——"float + vec3" 会被 GLSL 对齐成 28B
// (vec3 落 16 偏移),超出 FullscreenPush 的 [0,16] 声明范围
// (VUID-10065)。语义与 FullscreenPush 对齐:exposure 槽位=描边宽度,
// param0-2=描边色。
layout(push_constant) uniform PushConstants {
float widthPx; // 描边宽度(物理像素)
float colorR; // 描边色 R
float colorG; // 描边色 G
float colorB; // 描边色 B
} pc;
void main() {
const float m = texture(maskImage, fragUV).r;
const vec2 texel = vec2(pc.widthPx) / vec2(textureSize(maskImage, 0));
float ringMax = 0.0;
bool anyOutside = false;
const int N = 16;
for (int i = 0; i < N; ++i) {
const float a = float(i) * (6.2831853 / float(N));
const vec2 suv = fragUV + vec2(cos(a), sin(a)) * texel;
// 越界 = 视口截断(视为无 mask)→ 贴边像素产生描边
const bool outside = suv.x < 0.0 || suv.x > 1.0 ||
suv.y < 0.0 || suv.y > 1.0;
anyOutside = anyOutside || outside;
if (!outside) {
ringMax = max(ringMax, texture(maskImage, suv).r);
}
}
// 外描边:自身 mask=0 且邻域有 1(真轮廓;mask 无洞,不会描出
// 前方遮挡物的轮廓)
// 贴边内描边:自身 mask=1 且邻域越出视口(仅视口截断,物体延伸
// 出视野时描边贴着渲染视口边缘)
const bool outer = m < 0.5 && ringMax > 0.5;
const bool edgeCut = m > 0.5 && anyOutside;
const float edge = (outer || edgeCut) ? 1.0 : 0.0;
// LDR 恒定色直出,alpha 混合叠加在 Tonemap 输出上
outColor = vec4(pc.colorR, pc.colorG, pc.colorB, edge);
}