Я работаю над движком 2d. Он уже работает неплохо, но я продолжаю получать пиксельные ошибки.
Например, мое окно имеет размер 960x540 пикселей, я рисую линию от (0, 0) до (959, 0). Я ожидал бы, что каждый пиксель на линии сканирования 0 будет установлен в цвет, но нет: правый пиксель не нарисован. Та же проблема, когда я рисую вертикально на пиксель 539. Мне действительно нужно рисовать (960, 0) или (0, 540), чтобы нарисовать его.
Как я родился в эпоху пикселей, я убежден, что это не правильный результат. Когда мой экран был размером 320x200 пикселей, я мог рисовать от 0 до 319 и от 0 до 199, и мой экран был бы заполнен. Теперь я заканчиваю тем, что экран с правым/нижним пикселем не нарисован.
Это может быть связано с разными вещами: где я ожидаю, что примитив линии opengl будет отрисован от пикселя до пикселя включительно, что последний пиксель просто является исключительным? Это оно? моя проекционная матрица неверна? Я под ложным предположением, что, когда у меня есть backbuffer 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;
}