Files
HelloVulkan/shaders/gizmo_billboard.frag
T
atdunbg cc837bc605 Add animation controller system, material assets and skeleton visualization
- .animctrl state machine asset (params/transitions/blend trees, 1D+2D
  directional blending) with Unity Animator-style editor panel: state
  list, transitions, params, directional pad preview driving live
  CrossFade on the selected entity
- Split animation evaluation out of SceneRenderer into
  AnimationSystem/AnimationEvaluator; skin palettes with rest-pose
  fallback and blend-weight epsilon filtering
- MaterialAsset (.material) with reload-safe preview tile pool
  (DropMaterial clears dirty refs before instance destruction)
- EditorGizmoPass skeleton wires + viewport joint overlay; camera
  projection rework (baked Vulkan Y-flip, ortho support)
- Editor/game build split via HELLOVULKAN_EDITOR option
2026-10-07 01:50:04 +08:00

85 lines
3.1 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
// Editor gizmo 图标片元:按 aux.x(形状 id,与 SceneRenderer 收集常量
// 一一对应)在 uv ∈ [-1,1] 上做程序化 SDF 造型,预乘 alpha 输出
//(pass 侧混合 ONE, ONE_MINUS_SRC_ALPHA)。
// 0 方向光(太阳盘 + 8 向光芒)
// 1 点光(亮核 + 柔和光晕)
// 2 相机(机身挖孔 + 镜头环 + 取景器凸块)
// 3 天空盒(等距立方线框)
// 4 天空光(环 + 内核点)
layout(location = 0) in vec4 inColor;
layout(location = 1) in vec4 inAux;
layout(location = 0) out vec4 outColor;
// 方框 SDF
float sdBox(vec2 p, vec2 b) {
vec2 d = abs(p) - b;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
// 线段 SDF
float sdSegment(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a, ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h);
}
// 等边六边形 SDF(circumradius r,iq 惯用式)
float sdHexagon(vec2 p, float r) {
const vec3 k = vec3(-0.866025404, 0.5, 0.577350269);
p = abs(p);
p -= 2.0 * min(dot(k.xy, p), 0.0) * k.xy;
p -= vec2(clamp(p.x, -k.z * r, k.z * r), r);
return length(p) * sign(p.y);
}
float ShapeSDF(vec2 p, int id) {
if (id == 0) { // 方向光:太阳盘 + 8 向光芒
float r = length(p);
float disc = r - 0.38;
float a = atan(p.y, p.x);
float s45 = 0.78539816; // 45° 扇区
float fa = abs(mod(a + s45 * 0.5, s45) - s45 * 0.5);
float ray = max(r * sin(fa), abs(r - 0.58) - 0.20);
return min(disc, ray);
}
if (id == 1) return length(p) - 0.22; // 点光亮核(光晕在 main)
if (id == 2) { // 相机
float body = sdBox(p - vec2(0.05, 0.0), vec2(0.50, 0.36));
float hole = max(body, -(length(p - vec2(0.05, 0.0)) - 0.20));
float ring = abs(length(p - vec2(0.05, 0.0)) - 0.28) - 0.035;
float vf = sdBox(p - vec2(0.30, 0.44), vec2(0.14, 0.10));
return min(min(hole, ring), vf);
}
if (id == 3) { // 天空盒:等距立方线框
float hex = abs(sdHexagon(p, 0.72)) - 0.045;
float e1 = sdSegment(p, vec2(0.0), vec2(0.0, -0.72)) - 0.045;
float e2 = sdSegment(p, vec2(0.0), vec2(-0.6235, 0.36)) - 0.045;
float e3 = sdSegment(p, vec2(0.0), vec2(0.6235, 0.36)) - 0.045;
return min(hex, min(e1, min(e2, e3)));
}
// 天空光(id == 4):环 + 内核点
return min(abs(length(p) - 0.52) - 0.09, length(p) - 0.14);
}
void main() {
vec2 uv = inAux.yz;
int id = int(inAux.x + 0.5);
// uv 空间的像素级边缘宽度(quad 上 uv 随屏幕像素线性变化)
float aa = fwidth(uv.x) * 1.5 + 1e-4;
float alpha = smoothstep(aa, -aa, ShapeSDF(uv, id));
if (id == 1) { // 点光:核心外叠加径向光晕
float r = length(uv);
float halo = (1.0 - smoothstep(0.25, 1.0, r)) * 0.35;
alpha = max(alpha, halo);
}
// 预乘 alpha:ONE / ONE_MINUS_SRC_ALPHA 混合下的正确形式
outColor = vec4(inColor.rgb * alpha, alpha);
}