openGL图像质量(模糊)

时间:2012-08-07 12:51:11

标签: image opengl sdl

我使用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();                                                                                                 
}     

2 个答案:

答案 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);)结合使用?