我使用openGL创建幻灯片应用程序。不幸的是,与gnome图像查看器相比,使用openGL渲染的图像看起来模糊。
以下是2个截图
(opengl)http://tinyurl.com/dxmnzpc
(图片浏览器)http://tinyurl.com/8hshv2a
这是基本图像: http://tinyurl.com/97ho4rp
图片具有我的屏幕的原生尺寸。 (2560×1440)
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/freeglut.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <unistd.h>
GLuint text = 0;
GLuint load_texture(const char* file) {
SDL_Surface* surface = IMG_Load(file);
GLuint texture;
glPixelStorei(GL_UNPACK_ALIGNMENT,4);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
SDL_PixelFormat *format = surface->format;
printf("%d %d \n",surface->w,surface->h);
if (format->Amask) {
gluBuild2DMipmaps(GL_TEXTURE_2D, 4,surface->w, surface->h, GL_RGBA,GL_UNSIGNED_BYTE, surface->pixels);
} else {
gluBuild2DMipmaps(GL_TEXTURE_2D, 3,surface->w, surface->h, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels);
}
SDL_FreeSurface(surface);
return texture;
}
void display(void) {
GLdouble offset_x = -1;
GLdouble offset_y = -1;
int p_viewport[4];
glGetIntegerv(GL_VIEWPORT, p_viewport);
GLfloat gl_width = p_viewport[2];//width(); // GL context size
GLfloat gl_height = p_viewport[3];//height();
glClearColor (0.0,2.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glEnable( GL_TEXTURE_2D );
glTranslatef(0,0,0);
glBindTexture( GL_TEXTURE_2D, text);
gl_width=2; gl_height=2;
glBegin(GL_QUADS);
glTexCoord2f(0, 1); //4
glVertex2f(offset_x, offset_y);
glTexCoord2f(1, 1); //3
glVertex2f(offset_x + gl_width, offset_y);
glTexCoord2f(1, 0); // 2
glVertex2f(offset_x + gl_width, offset_y + gl_height);
glTexCoord2f(0, 0); // 1
glVertex2f(offset_x, offset_y + gl_height);
glEnd();
glutSwapBuffers();
}
int main(int argc, char **argv) {
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_DOUBLE);
glutGameModeString("2560x1440:24");
glutEnterGameMode();
text = load_texture("/tmp/raspberry/out.jpg");
glutDisplayFunc(display);
glutMainLoop();
}
更新尝试
void display(void)
{
GLdouble texture_x = 0;
GLdouble texture_y = 0;
GLdouble texture_width = 0;
GLdouble texture_height = 0;
glViewport(0,0,width,height);
glClearColor (0.0,2.0,0.0,1.0);
glClear (GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -1, 1);
//Do pixel calculatons
texture_x = ((2.0*1-1) / (2*width));
texture_y = ((2.0*1-1) / (2*height));
texture_width=((2.0*width-1)/(2*width));
texture_height=((2.0*height-1)/(2*height));
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,0);
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, text);
glBegin(GL_QUADS);
glTexCoord2f(texture_x, texture_height); //4
glVertex2f(0, 0);
glTexCoord2f(texture_width, texture_height); //3
glVertex2f(width, 0);
glTexCoord2f(texture_width, texture_y); // 2
glVertex2f(width,height);
glTexCoord2f(texture_y, texture_y); // 1
glVertex2f(0,height);
glEnd();
glutSwapBuffers();
}
答案 0 :(得分:3)
您遇到的是 fencepost问题的变体,这是由OpenGL处理纹理坐标的方式引起的。 OpenGL不解决纹理的像素(纹素),而是使用图像数据作为插值的支持,实际上覆盖了比图像像素更宽的范围。所以纹理坐标0和1不会碰到最左边/最底部和最右边/最顶部的像素,但实际上会更进一步。
假设纹理宽度为8像素:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
^ ^ ^ ^ ^ ^ ^ ^ ^
0.0 | | | | | | | 1.0
| | | | | | | | |
0/8 1/8 2/8 3/8 4/8 5/8 6/8 7/8 8/8
数字表示纹理的像素,条纹表示纹理的边缘,并且在最近的情况下过滤像素之间的边界。但是你想要点击像素的中心。所以你对纹理坐标感兴趣
(0/8 + 1/8)/ 2 = 1 /(2 * 8)
(1/8 + 2/8)/ 2 = 3 /(2 * 8)
...
(7/8 + 8/8)/ 2 = 15 /(2 * 8)
或者更一般地,对于N宽纹理中的像素i,适当的纹理坐标是
(2i + 1)/(2N)
但是,如果您想要将纹理与屏幕像素完美对齐,请记住您指定为坐标的不是四边形的像素,而是边缘,这取决于投影可能与屏幕像素边缘对齐,而不是中心,因此可能需要其他纹理坐标。
请注意,如果您遵循此操作,无论您的过滤模式和mipmaps如何,您的图像将始终看起来清晰明快,因为插值完全符合您的采样支持,即输入图像。切换到另一种过滤模式,如GL_NEAREST可能看起来正确,但它实际上不正确,因为它将为您的样本添加别名。 所以不要这样做。
您的代码也存在其他一些问题,但它们并不是一个大问题。首先,您正在选择一种相当神秘的视口尺寸方式。您(可能没有进一步考虑)了解默认OpenGL视口是创建上下文的窗口大小这一事实。您正在使用具有副作用的SDL,只要您坚持使用SDL-1,这种方法就不会让您感到厌烦。但是切换到任何其他框架,可能通过代理可绘制创建上下文,并且您遇到了问题。
规范方法通常是从窗口系统(在您的情况下为SDL)中检索窗口大小,然后在显示功能的第一个操作之一设置视口。
另一个问题是你使用gluBuildMipmaps
,因为a)你不想使用mipmap和b)因为OpenGL-2你可以上传任意大小的纹理图像(即你不限于权力尺寸为2),完全消除了对gluBuildMipmaps的需求。所以不要使用它。只需直接使用glTexImage2D并切换到非mipmapping过滤模式。
计算纹理坐标的方式仍然不正确。好像你开始计算1.纹理像素是0基索引,所以......
我就是这样做的:
假设投影映射视口
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, win_width, 0, win_height, -1, 1);
glViewport(0, 0, win_width, win_height);
我们将纹理坐标计算为
//Do pixel calculatons
glBindTexture( GL_TEXTURE_2D, text);
GLint tex_width, tex_height;
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &tex_width);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &tex_height);
texture_s1 = 1. / (2*width); // (2*0-1
texture_t1 = 1. / (2*height);
texture_s2 = (2.*(tex_width -1) + 1) / (2*width);
texture_t2 = (2.*(tex_height-1) + 1) / (2*height);
请注意,tex_width和tex_height在每个方向上给出数字像素,但坐标为0,因此您需要从纹理坐标映射中减去1。因此,我们还在分子中使用常数1作为s1,t1坐标。
考虑到您选择的投影,其余的看起来没问题
glEnable( GL_TEXTURE_2D );
glBegin(GL_QUADS);
glTexCoord2f(s1, t1); //4
glVertex2f(0, 0);
glTexCoord2f(s2, t1); //3
glVertex2f(tex_width, 0);
glTexCoord2f(s2, t2); // 2
glVertex2f(tex_width,tex_height);
glTexCoord2f(s1, t2); // 1
glVertex2f(0,tex_height);
glEnd();
答案 1 :(得分:0)
我不确定这是否真的是问题,但我认为你不需要/想要mipmap。您是否尝试将glTexImage2D
代替gluBuild2DMipmaps
与最近邻居过滤(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN
/MAG_FILTER, GL_NEAREST);
)结合使用?