c – OpenGL Scale单像素线

我想制作一个内部为320×240的游戏,但以整数倍(640×480,960,720等)渲染到屏幕.我打算复古的2D像素图形.

我通过glOrtho()设置内部分辨率来实现这一点:

glOrtho(0, 320, 240, 0, 0, 1);

然后我将输出分辨率放大3倍,如下所示:

glViewport(0,0,960,720);
window = SDL_CreateWindow("Title", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 720, SDL_WINDOW_OPENGL);

我画这样的矩形:

glBegin(GL_LINE_LOOP);
glVertex2f(rect_x, rect_y);
glVertex2f(rect_x + rect_w, rect_y);
glVertex2f(rect_x + dst_w, dst_y + dst_h);
glVertex2f(rect_x, rect_y + rect_h);
glEnd();

它完美地工作在320×240(未缩放):

c  –  OpenGL Scale单像素线

当我扩展到960×720时,像素渲染一切正常!然而,似乎GL_Line_Loop不是在320×240画布上绘制并按比例放大,而是在最终的960×720画布上绘制.结果是3px世界中的1px行:(

c  –  OpenGL Scale单像素线

如何在320×240 glOrtho画布上绘制线条,而不是960×720输出画布?

解决方法:

正如我在评论中提到的,英特尔OpenGL驱动程序在直接渲染到纹理方面存在问题,我不知道任何有效的解决方法.在这种情况下,唯一的解决方法是使用glReadPixels将屏幕内容复制到CPU内存中,然后将其作为纹理复制回GPU.粗糙比直接渲染到纹理慢得多.所以这里是交易:

>设置低分辨率视图

不要只改变glViewport值的窗口分辨率.然后在低分辨率(仅在屏幕空间的一小部分)渲染场景
>将渲染屏幕复制到纹理中
>设置目标分辨率视图
>渲染纹理

别忘了使用GL_NEAREST过滤器.最重要的是你之后才交换缓冲区!否则你会闪烁.

这里有C源:

void gl_draw()
    {
    // render resolution and multiplier
    const int xs=320,ys=200,m=2;

    // [low res render pass]
    glViewport(0,0,xs,ys);
    glClearColor(0.0,0.0,0.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);
    // 50 random lines
    RandSeed=0x12345678;
    glColor3f(1.0,1.0,1.0);
    glBegin(GL_LINES);
    for (int i=0;i<100;i++)
     glVertex2f(2.0*Random()-1.0,2.0*Random()-1.0);
    glEnd();

    // [multiply resiolution render pass]
    static bool _init=true;
    GLuint  txrid=0;        // texture id
    BYTE map[xs*ys*3];      // RGB
    // init texture
    if (_init)              // you should also delte the texture on exit of app ...
        {
        // create texture
        _init=false;
        glGenTextures(1,&txrid);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D,txrid);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);   // must be nearest !!!
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_COPY);
        glDisable(GL_TEXTURE_2D);
        }
    // copy low res screen to CPU memory
    glReadPixels(0,0,xs,ys,GL_RGB,GL_UNSIGNED_BYTE,map);
    // and then to GPU texture
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D,txrid);         
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, xs, ys, 0, GL_RGB, GL_UNSIGNED_BYTE, map);
    // set multiplied resolution view
    glViewport(0,0,m*xs,m*ys);
    glClear(GL_COLOR_BUFFER_BIT);
    // render low res screen as texture
    glBegin(GL_QUADS);
    glTexCoord2f(0.0,0.0); glVertex2f(-1.0,-1.0);
    glTexCoord2f(0.0,1.0); glVertex2f(-1.0,+1.0);
    glTexCoord2f(1.0,1.0); glVertex2f(+1.0,+1.0);
    glTexCoord2f(1.0,0.0); glVertex2f(+1.0,-1.0);
    glEnd();
    glDisable(GL_TEXTURE_2D);

    glFlush();
    SwapBuffers(hdc);   // swap buffers only here !!!
    }

并预览:

c  –  OpenGL Scale单像素线

我在一些英特尔高清显卡上测试了这个(上帝知道哪个版本)我得到了它并且它可以工作(而标准渲染到纹理方法不是).

上一篇:Web页面布局


下一篇:SDL 开发实战(六): 使用 SDL 实现 YUV 播放器