The title might sound a bit confusing, but I don't want to make it too long, so please bear with me and read on...
I'm writing a very simple OpenGL demo that loads an image as texture, then scrolls the image horizontally across the screen infinitely. Here's how I load the texture and render a single frame:
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++;
}
...where FRAME_RATE is the target frame rate and pan_seconds is the seconds it should take to scroll across an entire image.
Overall the demo runs quite well, but to nitpick I crafted a test image containing very thin elements - some thin texts and a 1-pixel-wide vertical line (on the very right) on a black background.
When this image is fed into the demo, and when pan_seconds is high (i.e. image scrolls slowly), the problem emerges - all these elements would noticeably flicker (fluctuate in brightness), most obviously present for the vertical line.
My analysis is that the high pan_seconds results in fractional deltas, i.e. subpixel movements, and OpenGL would have to filter the texture to determine the color of a pixel. Take the vertical line as an example, the interpolation of Bilinear filtering (GL_LINEAR) will for most of the time produce a 2-pixel-wide gray line, which the human eye perceives as 1-pixel-wide, but at the same time will appear less bright compared to the original white line.
This doesn't help with solving the problem though... Changing filter mode to GL_NEAREST will break the smooth scrolling effect; changing to GL_LINEAR_MIPMAP_LINEAR does eliminate the flicker, but at the cost of significantly blurring the image, which is not an acceptable outcome.
Is there a way to reduce this flickering without losing much sharpness, or do I have to trust my own theoretical analysis and call it impossible?
