c++ - OpenGL Scale單像素線




line sdl (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 !!!
    }

並預覽:

我在一些 英特爾高清 顯卡上測試了這個(上帝知道哪個版本)我得到了它並且它可以工作(而標準渲染到紋理方法不是)。

我想製作一個內部為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輸出畫布?


沒有“320x240 glOrtho canvas”。 只有窗口的實際分辨率:960x720。

您所做的只是縮放渲染圖元的坐標。 所以,你的代碼說要渲染一條線,例如,(20,20)到(40,40)。 OpenGL(最終)在每個維度上將這些坐標縮放3:(60,60)和(120x120)。

但那隻是處理 終點問題 。 中間發生的事情仍然基於你在窗口的實際分辨率下渲染的事實。

即使您使用 glLineWidth 來改變線條的寬度,也只能修復線條寬度。 它不能解決線條柵格化基於您渲染的實際分辨率這一事實。 所以對角線不會有你想要的像素化外觀。

正確地做到這一點的唯一方法是,正確地做到這一點。 渲染到實際為320x240的圖像,然後將其繪製到窗口的實際分辨率。

您必須創建該大小的紋理,然後將其附加到 幀緩衝對象 。 將FBO綁定到渲染並渲染到它(將視口設置為圖像的大小)。 然後取消綁定FBO,並將該紋理繪製到窗口(將視口設置為窗口的分辨率)。







pixel