我创建了8x8像素位图字母来使用OpenGL渲染它们,但有时候,根据缩放我会得到奇怪的伪像,如下图所示。纹理过滤设置为最近的像素。它看起来像舍入问题,但如果线条完全水平,怎么会有一些。
左原始8x8,中间缩放到18x18,右缩放到54x54。
顶点数据是格式的无符号字节(x-offset,y-offset,letter)。这是完整的代码:
顶点着色器:
#version 330 core
layout(location = 0) in uvec3 Data;
uniform float ratio;
uniform float font_size;
out float letter;
void main()
{
letter = Data.z;
vec2 position = vec2(float(Data.x) / ratio, Data.y) * font_size - 1.0f;
position.y = -position.y;
gl_Position = vec4(position, 0.0f, 1.0f);
}
几何着色器:
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 4) out;
uniform float ratio;
uniform float font_size;
out vec3 texture_coord;
in float letter[];
void main()
{
// TODO: pre-calculate
float width = font_size / ratio;
float height = -font_size;
texture_coord = vec3(0.0f, 0.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(0.0f, height, 0.0f, 0.0f);
EmitVertex();
texture_coord = vec3(1.0f, 0.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(width, height, 0.0f, 0.0f);
EmitVertex();
texture_coord = vec3(0.0f, 1.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(0.0f, 0.0f, 0.0f, 0.0f);
EmitVertex();
texture_coord = vec3(1.0f, 1.0f, letter[0]);
gl_Position = gl_in[0].gl_Position + vec4(width, 0.0f, 0.0f, 0.0f);
EmitVertex();
EndPrimitive();
}
片段着色器:
#version 330 core
in vec3 texture_coord;
uniform sampler2DArray font_texture_array;
out vec4 output_color;
void main()
{
output_color = texture(font_texture_array, texture_coord);
}
答案 0 :(得分:0)
好吧,当使用最近的过滤时,如果您的样本位置非常接近两个纹素之间的边界,您将看到此类问题。并且由于要为每个要绘制的片段单独插入tex坐标,因此轻微的数值误差将导致在这两个纹素之间跳跃。
当您将8x8纹理绘制为18x18像素的大矩形,并且您的矩形与putput像素栅格完美对齐时,几乎可以保证触发该行为:
查看纹理符号坐标将显示对于最底部输出像素,纹理坐标将被内插到1 /(2 * 18)= 1/36。向上一个像素将增加1/18 = 2/36到t坐标。所以对于从底部开始的第五行,它将是9/36。
因此,对于您正在采样的8x8纹素大纹理,您实际上是在非标准化纹理坐标(9/36)* 8 == 2.0处采样。这正是纹理的第二行和第三行之间的边界。由于每个片段的纹理坐标通过分配给来自三角形的三个顶点的tex坐标之间的重心插值进行插值,因此可能存在轻微的不准确性。即使是以浮点格式表示的最微小的不准确性,也会导致在这种情况下在两个纹素之间翻转。
我认为你的做法并不好。缩放位图字体总是有问题的(可能除了积分比例因子)。如果你想要很好看的可缩放纹理字体,我建议你研究signed distance fields。这是一种非常简单而强大的技术,有tools available to generate the necessary distance field textures。
如果你正在寻找一个快速黑客,你也可以稍微偏移你的输出矩形。你基本上必须确保将偏移保持在[-0.5,0.5]像素(这样在光栅化期间永远不会产生不同的片段,并且你必须确保所有潜在的样本位置永远不会接近整数,所以偏移将取决于实际的比例因子。
答案 1 :(得分:0)
使用Freetype和OpenGL开发时,我遇到了同样的问题。经过数天的研究和摸索,我找到了解决方案。就我而言,我必须显式调用函数“ glBlendColor”。一次,我做到了,再也没有观察到任何伪像。
这是一个代码段:
//Set Viewport
glViewport(0, 0, FIXED_WIDTH, FIXED_HEIGHT);
//Enable Blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendColor(1.0f, 1.0f, 1.0f, 1.0f); //Without this I was having artifacts: IMPORTANT TO EXPLICITLY CALLED
//Set Alignment requirement to 1 byte
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
在github上查看此OpenGL-Freetype库的源代码后,我找到了解决方案:opengl-freetype library