【问题标题】:OpenGL Scale Single Pixel LineOpenGL 缩放单像素线
【发布时间】:2023-04-02 12:09:02
【问题描述】:

我想制作一个内部尺寸为 320x240 的游戏,但以整数倍数(640x480、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();

它在 320x240(未缩放)下完美运行:

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

如何在 320x240 glOrtho 画布而不是 960x720 输出画布上画线?

【问题讨论】:

标签: c++ opengl line sdl pixel


【解决方案1】:

没有“320x240 glOrtho 画布”。只有窗口的实际分辨率:960x720。

您所做的只是放大您渲染的图元的坐标。因此,您的代码表示要渲染从 (20, 20) 到 (40, 40) 的行。 OpenGL(最终)将这些坐标在每个维度上缩放 3 倍:(60, 60) 和 (120x120)。

但这只是处理端点。中间发生的事情仍然基于您以窗口的实际分辨率进行渲染的事实。

即使您使用glLineWidth 更改线条的宽度,也只能修复线条宽度。它不能解决线的光栅化基于您正在渲染的实际分辨率的事实。所以对角线不会有你可能想要的像素化外观。

正确执行此操作的唯一方法是正确执行此操作。渲染为实际 320x240 的图像,然后将其绘制为窗口的实际分辨率。

您必须创建该大小的纹理,然后将其附加到framebuffer object。绑定 FBO 以进行渲染并渲染到它(视口设置为图像的大小)。然后取消绑定 FBO,并将该纹理绘制到窗口(视口设置为窗口的分辨率)。

【讨论】:

  • 是的,我同意,但需要补充一点,如果您要渲染到纹理,您可以预期英特尔 gfx 卡将无法按预期工作或根本无法工作,直到他们修复旧 gfx 卡永远不会的驱动程序根据经验...在这种情况下,您可以尝试glReadPixels ...
  • @Spektre:如果您想添加讨论特定驱动程序错误的答案,请随意。我不知道你说的具体是哪些错误,或者你指的是哪些硬件,所以我没有资格讨论它。
  • 我添加了慢速 OpenGL 1.0 方法,它甚至可以在 Intel 上运行。
【解决方案2】:

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

  1. 设置低分辨率视图

    不要只更改glViewport 值的窗口分辨率。然后以低分辨率(仅占屏幕空间的一小部分)渲染您的场景

  2. 将渲染的屏幕复制到纹理中

  3. 设置目标分辨率视图
  4. 渲染纹理

    不要忘记使用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 !!!
    }

和预览:

我在一些 Intel HD 显卡(天知道是哪个版本)上测试了它,我可以使用它并且它可以工作(而标准的纹理渲染方法不是)。

【讨论】:

    猜你喜欢
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    相关资源
    最近更新 更多