[英]OpenGL Scale Single Pixel Line
我想制作一個內部尺寸為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畫布”。 只有窗口的實際分辨率:960x720。
您要做的只是放大渲染圖元的坐標。 因此,您的代碼說要渲染從(20,20)到(40,40)的線。 OpenGL(最終)在每個維度上將這些坐標按3比例縮放:(60、60)和(120x120)。
但這僅涉及終點 。 中間發生的情況仍然基於您以窗口的實際分辨率進行渲染的事實。
即使您使用glLineWidth
來更改線條的寬度,也只能固定線條的寬度。 線的柵格化基於您要渲染的實際分辨率並不能解決這一事實。 因此,對角線將不會具有您可能想要的像素化外觀。
正確執行此操作的唯一方法是正確執行此操作。 渲染為實際的320x240圖像,然后將其繪制為窗口的實際分辨率。
您必須創建該大小的紋理,然后將其附加到framebuffer對象 。 綁定要渲染的FBO並將其渲染(視口設置為圖像的大小)。 然后取消綁定FBO,並將該紋理繪制到窗口(視口設置為窗口的分辨率)。
正如我在評論中提到的那樣, 英特爾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 !!!
}
並預覽:
我在我可以使用的某些Intel HD圖形(上帝知道哪個版本)上對此進行了測試,並且可以正常工作(而標准的渲染紋理方法則沒有)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.