我正在研发2d引擎。它已经运行良好,但我不断遇到像素错误。
例如,我的窗口是960x540像素,我从(0,0)到(959,0)画一条线。我希望扫描线0上的每个像素都会被设置为一种颜色,但是没有:最右边的像素没有被绘制。当我垂直绘制到像素539时,同样的问题。我真的需要绘制到(960,0)或(0,540)来绘制它。
当我出生在像素时代时,我确信这不是正确的结果。当我的屏幕大于320x200像素时,我可以从0到319从0到199画出,我的屏幕就会满了。现在我最终得到一个没有绘制右/底像素的屏幕。
这可能是由于不同的原因: 我期望将opengl线基元从像素绘制到包含像素,最后一个像素实际上是否排他?是吗? 我的投影矩阵不正确? 我有一个错误的假设,当我有一个960x540的后备缓冲区时,实际上有一个像素更多? 还有别的吗?
有人可以帮帮我吗?我一直在研究这个问题很长一段时间,每当我认为它没问题的时候,我看了一会儿它实际上没有。
这是我的一些代码,我试图尽可能地删除它。当我调用我的线函数时,每个坐标都加上0.375,0.375,以使它在ATI和nvidia适配器上都正确。
int width = resX();
int height = resY();
for (int i = 0; i < height; i += 2)
rm->line(0, i, width - 1, i, vec4f(1, 0, 0, 1));
for (int i = 1; i < height; i += 2)
rm->line(0, i, width - 1, i, vec4f(0, 1, 0, 1));
// when I do this, one pixel to the right remains undrawn
void rendermachine::line(int x1, int y1, int x2, int y2, const vec4f &color)
{
... some code to decide what std::vector the coordinates should be pushed into
// m_z is a z-coordinate, I use z-buffering to preserve correct drawing orders
// vec2f(0, 0) is a texture-coordinate, the line is drawn without texturing
target->push_back(vertex(vec3f((float)x1 + 0.375f, (float)y1 + 0.375f, m_z), color, vec2f(0, 0)));
target->push_back(vertex(vec3f((float)x2 + 0.375f, (float)y2 + 0.375f, m_z), color, vec2f(0, 0)));
}
void rendermachine::update(...)
{
... render target object is queried for width and height, in my test it is just the back buffer so the window client resolution is returned
mat4f mP;
mP.setOrthographic(0, (float)width, (float)height, 0, 0, 8000000);
... all vertices are copied to video memory
... drawing
if (there are lines to draw)
glDrawArrays(GL_LINES, (int)offset, (int)lines.size());
...
}
// And the (very simple) shader to draw these lines
// Vertex shader
#version 120
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 mP;
varying vec4 vColor;
void main(void) {
gl_Position = mP * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
// Fragment shader
#version 120
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor.rgb;
}
答案 0 :(得分:15)
在OpenGL中,使用“Diamond Exit”规则对行进行栅格化。这几乎与说结束坐标是独占的相同,但不完全......
这是OpenGL规范所说的: http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
另请参阅OpenGL常见问题解答,http://www.opengl.org/archives/resources/faq/technical/rasterization.htm,项目“14.090如何获得线条的精确像素化?”。它说“OpenGL规范允许使用各种线性渲染硬件,因此根本不可能进行精确的像素化。”
许多人认为你根本不应该在OpenGL中使用行。他们的行为是基于古老的SGI硬件的工作原理,而不是基于什么是有意义的。 (宽度> 1的线几乎不可能以看起来很好的方式使用!)
答案 1 :(得分:6)
请注意,OpenGL坐标空间没有整数概念,一切都是浮点数,OpenGL像素的“中心”实际上是0.5,0.5而不是左上角。因此,如果你想要从0,0到10,10(含)的1px宽线,你真的必须画一条从0.5,0.5到10.5,10.5的线。
如果你打开消除锯齿效果会很明显,如果你有抗锯齿并尝试从50,0到50,100绘制,你可能会看到模糊的2px宽线,因为线条落在两个像素之间