Как уменьшить «мерцание» тонких элементов на изображении / текстуре? - PullRequest
0 голосов
/ 11 января 2019

Название может показаться немного запутанным, но я не хочу делать его слишком длинным, поэтому, пожалуйста, потерпите меня и читайте дальше ...

Я пишу очень простую демонстрацию OpenGL, которая загружает изображение в качестве текстуры, а затем бесконечно прокручивает изображение горизонтально по экрану. Вот как я загружаю текстуру и отрисовываю один кадр:

void load_texture(char* filename)
{
    glEnable(GL_TEXTURE_2D);
    gl_texture = SOIL_load_OGL_texture(filename, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
    glBindTexture(GL_TEXTURE_2D, gl_texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);
}

void render_single_frame()
{
    glBindTexture(GL_TEXTURE_2D, gl_texture);
    {
        glBegin(GL_QUADS);
        {
            float delta = fmod(1.0f / FRAME_RATE / pan_seconds * current_frame, 1.0f);
            glTexCoord2f(0.0f + delta, 0.0f); glVertex2f(-1.0f, -1.0f);
            glTexCoord2f(1.0f + delta, 0.0f); glVertex2f(+1.0f, -1.0f);
            glTexCoord2f(1.0f + delta, 1.0f); glVertex2f(+1.0f, +1.0f);
            glTexCoord2f(0.0f + delta, 1.0f); glVertex2f(-1.0f, +1.0f);
        }
        glEnd();
    }
    glBindTexture(GL_TEXTURE_2D, 0);
    glutSwapBuffers();
    glFinish();
    current_frame++;
}

... где FRAME_RATE - целевая частота кадров, а pan_seconds - секунды, необходимые для прокрутки всего изображения.

В целом демонстрация работает довольно хорошо, но, к сожалению, я создал тестовое изображение, содержащее очень тонкие элементы - несколько тонких текстов и вертикальную линию шириной 1 пиксель (справа) на черном фоне.

Test image

Когда это изображение подается в демонстрационную версию и когда значение pan_seconds высокое (то есть изображение медленно прокручивается), возникает проблема - все эти элементы будут заметно мерцать (колебаться по яркости), что наиболее очевидно присутствует для вертикальной линии.

Мой анализ состоит в том, что высокий pan_seconds приводит к дробным delta с, то есть к движению субпикселя, и OpenGL придется фильтровать текстуру, чтобы определить цвет пикселя. Возьмем, к примеру, вертикальную линию: интерполяция билинейной фильтрации (GL_LINEAR) в большинстве случаев будет давать ширину серую шириной 2 пикселя, которую человеческий глаз воспринимает как 1-пиксельный широкий, но в то же время будет казаться менее ярким по сравнению с оригинальной белой линией.

Это не поможет решить проблему, хотя ... Изменение режима фильтра на GL_NEAREST нарушит эффект плавной прокрутки; изменение на GL_LINEAR_MIPMAP_LINEAR устраняет мерцание, но за счет значительного размытия изображения, что не является приемлемым результатом.

Есть ли способ уменьшить это мерцание, не теряя особой резкости, или я должен доверять своему собственному теоретическому анализу и назвать его невозможным?

1 Ответ

0 голосов
/ 11 января 2019

Вы можете работать с координатами, равными пикселям, например,

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-w/2.f, +w/2.f, -h/2.f, h/2.f, ZNEARCLIP * -1.f, ZFARCLIP * -1.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glViewport(0, 0, w, h);

Если вы теперь рисуете линию, когда x и y являются целыми числами, линия должна иметь ширину 1 пиксель и не охватывать 2 пикселя с интерполяцией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...