片段着色器 - 绘制曲线

时间:2018-03-27 16:19:58

标签: opengl glsl shader

如何使用片段着色器绘制直线或曲线?

我有一个程序,在给定用户指定的一组顶点的情况下计算贝塞尔曲线。在早期,我很简单地处理应用程序端的每个顶点,根据这个三次Bezier曲线方程生成一组插值点:

Cubic Bezier curve

...然后将所有处理过的顶点存储到GL_VERTEX_ARRAY中,以便使用glDrawArrays(GL_LINE_STRIP,0,myArraySize)进行绘制。虽然解决方案很简单,但此实现的时间复杂度为 O(n ^ 2)。问题出现在我开始增加步数的地方,例如在我的循环的每次迭代中将t递增0.01,由用户生成他们想要的顶点数量复杂化。

所以当我开始研究着色器时,尤其是片段着色器。据我所知,我们的片段着色器程序为GPU处理的当前片段分配颜色。我没有认真对待着色器编程,但我当前的行着色器实现如下:

#version 120

uniform vec2 resolution;
uniform vec2 ptA;
uniform vec2 ptB;
uniform vec2 ptC;
uniform vec2 ptD;
uniform float stepTotal;

void main()
{
    vec2 uv = gl_FragCoord.xy / resolution.xy;
    vec2 curvePts[int(stepTotal)];

    float t = stepTotal;

    for(float i = 0.; i < 1.0; i += 1./t)
    {
        # Courtesy to: https://yalantis.com/blog/how-we-created-visualization-for-horizon-our-open-source-library-for-sound-visualization/
        vec2 q0 = mix(ptA, ptB, i);
        vec2 q1 = mix(ptB, ptC, i);
        vec2 q2 = mix(ptC, ptD, i);

        vec2 r0 = mix(q0, q1, i);
        vec2 r1 = mix(q1, q2, i);

        vec2 p_int = mix(r0, r1, i);
        curvePts[int(i) * int(stepTotal)] = p_int;
    }

    // TO DO:
    // Check if current fragment is within the curve. Not sure how
    // to proceed from here...
}

正如您所看到的,我目前仍然坚持如何检查当前片段是否在曲线内,以及如何为显示时最终变为曲线的特定片段指定颜色。

1 个答案:

答案 0 :(得分:0)

您可以使用距离函数绘制线段:

float DistanceToLineSegment(vec3 p, vec3 a, vec3 b)
{
    vec3 pa = p - a, ba = b - a;
    float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
    return length( pa - ba*h );
}

如果距离函数的结果小于某个阈值,则片段将位于片段的“内部”。

您也可以使用平滑步长函数替换阈值测试以绘制抗锯齿线。