1

我使用 openGL 创建幻灯片应用程序。不幸的是,与gnome 图像查看器相比,使用openGL渲染的图像看起来很模糊。

这是2个屏幕截图

(opengl) http://tinyurl.com/dxmnzpc

(图像查看器)http://tinyurl.com/8hshv2a

这是基本图像: http ://tinyurl.com/97ho4rp

该图像具有我的屏幕的本机尺寸。(2560x1440)

#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();                                                                                                 
}     
4

2 回答 2

3

您遇到的是栅栏问题的一种变体,它源于 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)

但是,如果您想将纹理与屏幕像素完美对齐,请记住您指定的坐标不是四边形的像素,而是边缘,根据投影,边缘可能与屏幕像素边缘对齐,而不是中心,因此可能需要其他纹理坐标。

请注意,如果您遵循这一点,那么无论您的过滤模式和 mipmap 是什么,您的图像都将始终看起来清晰明快,因为插值恰好符合您的采样支持,即您的输入图像。切换到另一种过滤模式,如 GL_NEAREST 乍一看可能看起来不错,但实际上是不正确的,因为它会给您的样本起别名。所以不要这样做。


您的代码也几乎没有其他问题,但它们并不是一个大问题。首先,您选择了一种相当神秘的方式来查看视口尺寸。您(可能没有进一步考虑)发现默认 OpenGL 视口是创建上下文的窗口的大小这一事实。您正在使用 SDL,它具有副作用,只要您坚持使用 SDL-1,这种方法就不会对您不利。但是切换到任何其他框架,它可能会通过代理绘制创建上下文,并且您遇到了问题。

规范的方法通常是从窗口系统(在您的情况下为 SDL)检索窗口大小,然后在显示函数中的第一个操作中设置视口。

另一个问题是您使用gluBuildMipmaps,因为 a) 您不想使用 mipmap 和 b) 由于 OpenGL-2 您可以上传任意大小的纹理图像(即您不限于尺寸的 2 次方),其中完全消除了对 gluBuildMipmaps 的需求。所以不要使用它。只需直接使用 glTexImage2D 并切换到非 mipmapping 过滤模式即可。

由于问题更新而更新

您计算纹理坐标的方式仍然看起来不正确。看起来你从 1 开始计数。纹理像素的基础索引为 0,所以……</p>

这就是我的做法:

假设投影映射视口

    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 以进行纹理坐标映射。因此,我们还在 s1, t1 坐标的分子中使用常数 1。

鉴于您选择的投影,其余的看起来还可以

    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();
于 2012-08-08T13:20:12.017 回答
0

我不确定这是否真的是问题,但我认为你不需要/想要这里的 mipmap。您是否尝试过使用glTexImage2D而不是gluBuild2DMipmaps与最近邻过滤(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN/MAG_FILTER, GL_NEAREST);)结合使用?

于 2012-08-07T13:00:47.837 回答