点画图案的片段着色器

fragment shader for stipple pattern

我正在尝试使用着色器绘制点画图案,就像在 glStipple 中一样。但是它似乎没有按预期工作。

想法是将像素坐标与点画蒙版进行比较,如果像素坐标 mod 蒙版大小为 0,则丢弃片段。

但是,发生了两件奇怪的事情,这表明该方法存在一些我遗漏的缺陷。首先是生成的点画图案与掩码不匹配。 8x8 蒙版中的单条对角线在绘制的形状中看起来像是间隔 1 个像素的对角线。第二个是针对 1 而不是 0 的测试不会给出类似(但偏移)的模式。

顶点着色器如下所示:

static const char *vertexShaderSource =
"attribute highp vec4 posAttr;\n"
"attribute highp vec4 colAttr;\n"
"varying lowp vec4 col;\n"
"varying highp vec2 coord;\n"
"uniform highp mat4 matrix;\n"
"void main() {\n"
"   col = colAttr;\n"
"   gl_Position = matrix * posAttr;\n"
"   coord = gl_Position.xy;\n"
"}\n";

和片段着色器:

static const char *fragmentShaderSource =
"varying lowp vec4 col;\n"
"varying highp vec2 coord;\n"
"uniform int stipple[64];\n"
"uniform int width;\n"
"uniform int height;\n"
"void main() {\n"
"   if (stipple[abs(mod(coord.x * width,8)) + abs(mod(coord.y * height,8)) * 8] == 1)\n"
"   {\n"
"       discard;\n"
"   }\n"
"   gl_FragColor = col;\n"
"}\n";

其中宽度和高度是视口的 w/h,点画是例如

GLint stipple[64] = {
    0, 0, 0, 0, 0, 0, 0, 1,
    0, 0, 0, 0, 0, 0, 1, 0,
    0, 0, 0, 0, 0, 1, 0, 0,
    0, 0, 0, 0, 1, 0, 0, 0,
    0, 0, 0, 1, 0, 0, 0, 0,
    0, 0, 1, 0, 0, 0, 0, 0,
    0, 1, 0, 0, 0, 0, 0, 0,
    1, 0, 0, 0, 0, 0, 0, 0
};

任何想法表示赞赏,谢谢。

您可以使用 gl_FragCoord。它包含像素的中心坐标。因此,对于 800x600 的分辨率,gl_FragCoord 将在 vec2(0.5, 0.5)vec2(799.5, 599.5) 的范围内。因此不需要乘以分辨率,因为我们已经基本上有window坐标。

由于 gl_FragCoord 不会产生负数,您可以删除 abs().

总而言之,经过少量修改,片段着色器最终看起来像这样:

varying vec4 color;

uniform int stipple[64];

void main()
{
    ivec2 coord = ivec2(gl_FragCoord.xy - 0.5);

    if (stipple[int(mod(coord.x, 8) + mod(coord.y, 8) * 8)] == 0)
       discard;

    gl_FragColor = color;
}