Opengl像素完美二维绘图

Opengl像素完美二维绘图,opengl,drawing,pixel-perfect,Opengl,Drawing,Pixel Perfect,我在做2d引擎。它已经工作得很好了,但我不断得到像素错误 例如,我的窗口是960x540像素,我画了一条从(0,0)到(959,0)的线。我希望扫描线0上的每个像素都将设置为一种颜色,但不是:没有绘制最右边的像素。当我垂直于像素539绘制时也会出现同样的问题。我真的需要画到(960,0)或(0540)才能画出来 由于我出生在像素时代,我确信这不是正确的结果。当我的屏幕是320x200像素大的时候,我可以从0到319,从0到199,我的屏幕就会满了。现在,我的屏幕上没有绘制右/下像素 这可能是由于

我在做2d引擎。它已经工作得很好了,但我不断得到像素错误

例如,我的窗口是960x540像素,我画了一条从(0,0)到(959,0)的线。我希望扫描线0上的每个像素都将设置为一种颜色,但不是:没有绘制最右边的像素。当我垂直于像素539绘制时也会出现同样的问题。我真的需要画到(960,0)或(0540)才能画出来

由于我出生在像素时代,我确信这不是正确的结果。当我的屏幕是320x200像素大的时候,我可以从0到319,从0到199,我的屏幕就会满了。现在,我的屏幕上没有绘制右/下像素

这可能是由于不同的原因造成的: 我希望opengl线条原语是从一个像素到一个像素(包括一个像素),最后一个像素实际上是唯一的?是这样吗? 我的投影矩阵不正确? 我有一个错误的假设,当我有一个960x540的backbuffer时,它实际上多了一个像素? 还有别的吗

有人能帮我吗?我已经研究这个问题很长一段时间了,每次当我认为它是好的,过了一段时间,我发现它实际上不是

这是我的一些代码,我试着尽可能地删除它。当我调用我的line函数时,每个坐标都添加了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;
    }
int-width=resX();
int height=resY();
对于(int i=0;iline(0,i,width-1,i,vec4f(1,0,0,1));
对于(int i=1;iline(0,i,width-1,i,vec4f(0,1,0,1));
//当我这样做时,右边的一个像素保持未绘制状态
void rendermachine::line(int-x1、int-y1、int-x2、int-y2、const-vec4f和color)
{
…一些代码来决定坐标应推入哪个std::vector
//m_z是z坐标,我使用z缓冲来保持正确的绘图顺序
//vec2f(0,0)是一个纹理坐标,线是在没有纹理的情况下绘制的
目标->向后推(顶点(vec3f((浮点)x1+0.375f,(浮点)y1+0.375f,m_z),颜色,vec2f(0,0));
目标->推回(顶点(vec3f((浮点)x2+0.375f,(浮点)y2+0.375f,m_z),颜色,vec2f(0,0));
}
void rendermachine::update(…)
{
…查询渲染目标对象的宽度和高度,在我的测试中,它只是后缓冲区,因此返回窗口客户端分辨率
mat4f-mP;
mP.设置正交(0,(浮动)宽度,(浮动)高度,0,0,8000000);
…所有顶点都复制到视频内存中
绘画
如果(有要绘制的线)
gldrawArray(GL_线,(int)偏移,(int)线.size());
...
}
//和(非常简单的)着色器来绘制这些线
//顶点着色器
#版本120
属性向量3;
属性向量4;颜色;
均匀mat4mp;
可变vec4颜色;
真空总管(真空){
gl_位置=mP*vec4(1.0);
vColor=excolor;
}
//片段着色器
#版本120
#国际财务报告准则
高精度浮点;
#恩迪夫
可变vec4颜色;
真空总管(真空){
gl_FragColor=vColor.rgb;
}

请注意,OpenGL坐标空间没有整数的概念,一切都是一个浮点,OpenGL像素的“中心”实际上位于0.5,0.5,而不是其左上角。因此,如果你想要一条1px宽的线,从0,0到10,10(含0,10),你必须画一条从0.5,0.5到10.5,10.5的线


如果启用抗锯齿功能,这一点尤其明显。如果使用抗锯齿功能,并尝试从50,0到50100绘制,您可能会看到一条模糊的2px宽的线,因为该线位于两个像素之间。

请注意,OpenGL坐标空间没有整数的概念,一切都是一个浮点和“中心”OpenGL像素的位置实际上是0.5,0.5,而不是它的左上角。因此,如果你想要一条1px宽的线,从0,0到10,10(含0,10),你必须画一条从0.5,0.5到10.5,10.5的线


如果启用抗锯齿,这一点尤其明显。如果使用抗锯齿,并尝试从50,0到50100绘制,则可能会看到一条2倍宽的模糊线,因为该线位于两个像素之间。

在OpenGL中,使用“菱形退出”规则对线进行栅格化。这几乎等同于说端点坐标是独占的,但不完全是

这就是OpenGL规范所说的:

还可以查看OpenGL常见问题解答,项目“14.090如何获得精确的线像素化?”。它说“OpenGL规范允许广泛的线渲染硬件,所以精确的像素化可能根本不可能。”


许多人会争辩说,您根本不应该在OpenGL中使用线条。他们的行为是基于古代SGI硬件的工作方式,而不是基于什么是合理的。(宽度大于1的线几乎不可能以看起来很好的方式使用!)

在OpenGL中,线是使用“菱形退出”规则光栅化的。这几乎等同于说端点坐标是独占的,但不完全是

这就是OpenGL规范所说的:

还可以查看OpenGL常见问题解答,项目“14.090如何获得精确的线像素化?”。它说“OpenGL规范允许广泛的线渲染硬件,所以精确的像素化可能根本不可能。”


许多人会争辩说,您根本不应该在OpenGL中使用线条。他们的行为是基于古代SGI硬件的工作方式,而不是基于什么是合理的。(宽度大于1的线条几乎不可能以看起来很好的方式使用!)

我完全理解你在说什么,但这不是问题所在。通过使用正确的投影矩阵并为每个像素添加0.375,ATI和nvidia将对数字进行四舍五入,以便坐标为精确的像素。如果苹果操作系统不是像素完美的,那么还有什么其他方法可以绘制像素完美的窗口呢?@scipie:你实际上应该添加0.5。0.5是中间值