点画图案的片段着色器
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;
}
我正在尝试使用着色器绘制点画图案,就像在 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;
}