# shader
对于vertex shader,没有任何特殊点:
#version 330 core
layout(location = 0) in vec2 position;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
对于fragment shader:
#version 330 core
uniform vec2 size;
uniform float radius;
uniform vec4 color;
uniform vec2 position;
float roundedBoxSDF(vec2 p, vec2 b, float r) {
return length(max(abs(p) - b + r, 0.0)) - r;
}
void main() {
vec2 center = vec2(position.x + size.x / 2.0, position.y - size.y / 2.0);
float distance = roundedBoxSDF(gl_FragCoord.xy - center, size / 2.0, radius * 100.0);
if (distance > 0.0f) {
discard;
}
gl_FragColor = color;
}
# SDF
上面shader中最重要的自然是roundedBoxSDF函数
:
float roundedBoxSDF(vec2 p, vec2 b, float r) {
return length(max(abs(p) - b + r, 0.0)) - r;
}
SDF即符号距离函数,表示一个点到图形的最近距离,且带符号:正数表示点在图形外,负数反之。因此我们可以利用SDF函数简单获取到圆角矩形边界,并且只渲染边界内的图形,即:
if (distance > 0.0f) {
discard;
}
对于圆角矩形的SDF,有三个参数p
,b
和r
,分别表示:
- 点到矩形中心的矢量,即
gl_FragCoord.xy - center
- 矩形的一个顶点到矩形中心的矢量(即
[width / 2, height / 2]
) - 圆角半径
# 消除锯齿
其中p是当前片元相对矩形中心的坐标,b为二分之一矩形尺寸,radius为圆角尺寸。
这样实现的圆角矩形在放大后会有锯齿,因此需要使用mix来减少锯齿。
void main() {
vec2 center = vec2(position.x + size.x / 2.0, position.y - size.y / 2.0);
float distance = roundedBoxSDF(gl_FragCoord.xy - center, size / 2.0, radius * 100.0);
float alpha = (1.0 - smoothstep(0.0f, 2.0f, distance)) * color.w;
vec4 mixed_color = vec4(color.xyz, alpha);
gl_FragColor = mix(mixed_color, color, alpha / color.w);
}