在片段着色器中绘制别名像素完美线?

Posted

技术标签:

【中文标题】在片段着色器中绘制别名像素完美线?【英文标题】:Drawing aliased pixel-perfect lines in fragment shader? 【发布时间】:2019-10-23 09:39:22 【问题描述】:

我正在尝试使用片段着色器在 OpenGL 中绘制像素完美的线条。我有以下从this question 获得的片段着色器。然而,结果是 2 像素而不是 1 像素。

#version 330

layout(location=0) out vec4 frag_colour;

in vec4 color;

uniform vec2 positionA;
uniform vec2 positionB;
uniform int thickness;

float lineSegment(vec2 p, vec2 a, vec2 b, float thickness)

    vec2 pa = p - a;
    vec2 ba = b - a;

    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );

    float k = length(pa - ba*h);

    return smoothstep(0.0, thickness, k);


void main()

    vec2 uv = gl_FragCoord.xy;

    frag_colour = mix(color,vec4(0),lineSegment(uv,positionA,positionB,thickness));

据我了解,这是因为无论“线”在哪里,从技术上讲,两侧的像素距离相同,所以如果我尝试移除任何类型的抗锯齿,它们都“在线” " 所以我的 1 像素宽的线最终变成了 2 像素。

您可以看到黄色水平线是 2 像素宽(将其与文本中的各个像素进行比较)。

我在网上到处尝试了一些其他的片段代码,它们都存在同样的问题。

如何在 GLSL 中绘制像素完美的锯齿线(非抗锯齿线)?

编辑 1 通过0.5f调整位置和粗细后,移动到像素的中心,对角线在每一种“台阶”上都有抗锯齿。

对角线:

【问题讨论】:

thickness 就像是一条线周围的半径。如果您指定 1 个像素,您将获得上方 1 个像素和下方 1 个像素,即总共 2 个像素。如果您使用 0.5px 半径,请确保在像素中心指定端点,以避免数值不稳定。 谢谢@Nico,为水平/垂直线做了这件事。但是以一定角度延伸的线添加了抗锯齿功能。 然后将smoothstep 替换为return k <= thickness ? 0 : 1 就是这样@NicoSchertler。在有人解释之后总是很明显。如果您将其放入答案中,我会接受。 【参考方案1】:

也许这会有所帮助(在 shadertoy 中测试):

bool lineSegment(vec2 p, vec2 a, vec2 b, float thickness)

    vec2 pa = p - a;
    vec2 ba = b - a;
    float len = length(ba);
    vec2 dir = ba / len;
    float t = dot(pa, dir);
    vec2 n = vec2(-dir.y, dir.x);
    float factor = max(abs(n.x), abs(n.y));
    float distThreshold = (thickness - 1.0 + factor)*0.5;
    float proj = dot(n, pa);
    
    return (t > 0.0) && (t < len) && (proj <= distThreshold) && (proj > -distThreshold);


void mainImage(out vec4 fragColor, in vec2 fragCoord)

    vec2 positionA = iResolution.xy * 0.5;
    vec2 positionB = iMouse.xy;
    float thickness = 1.0;
    
    fragColor = mix(vec4(0), vec4(1), float(lineSegment(fragCoord,positionA,positionB,thickness)));

以防万一,here's math.stackexchange 上的相关问题。

【讨论】:

以上是关于在片段着色器中绘制别名像素完美线?的主要内容,如果未能解决你的问题,请参考以下文章

使用片段着色器在特定位置绘制完美的水平线

GLSL片段着色器-绘制简单的粗曲线

GLSL:使用片段着色器进行对象翻译

在片段着色器中丢失纹理定义

如何在片段着色器中进行自定义模板测试

GLSL片段着色器 - 绘制简单的粗曲线