OpenGL 缩放单像素线
我想制作一个内部为 320x240 的游戏,但在屏幕上以整数倍(640x480、960,720 等)呈现.我要复古 2D 像素图形.
I would like to make a game that is internally 320x240, but renders to the screen at whole number multiples of this (640x480, 960,720, etc). I am going for retro 2D pixel graphics.
我通过 glOrtho() 设置内部分辨率实现了这一点:
I have achieved this by setting the internal resolution via glOrtho():
glOrtho(0, 320, 240, 0, 0, 1);
然后我将输出分辨率放大 3 倍,如下所示:
And then I scale up the output resolution by a factor of 3, like this:
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(未缩放)下完美运行:
It works perfectly at 320x240 (not scaled):
当我放大到 960x720 时,像素渲染一切正常!然而,似乎 GL_Line_Loop 不是在 320x240 画布上绘制并放大,而是在最终 960x720 画布上绘制.结果是 3px 世界中的 1px 线 :(
When I scale up to 960x720, the pixel rendering all works just fine! However it seems the GL_Line_Loop is not drawn on a 320x240 canvas and scaled up, but drawn on the final 960x720 canvas. The result is 1px lines in a 3px world :(
如何在 320x240 glOrtho 画布而不是 960x720 输出画布上绘制线条?
How do I draw lines to the 320x240 glOrtho canvas, instead of the 960x720 output canvas?
推荐答案
正如我在评论中提到的 Intel OpenGL 驱动程序在直接渲染到纹理方面存在问题,我不知道有任何解决方法在职的.在这种情况下,解决此问题的唯一方法是使用 glReadPixels
将屏幕内容复制到 CPU 内存中,然后将其作为纹理复制回 GPU.粗糙的比直接渲染到纹理要慢得多.所以这是交易:
As I mentioned in my comment Intel OpenGL drivers has problems with direct rendering to texture and I do not know of any workaround that is working. In such case the only way around this is use glReadPixels
to copy screen content into CPU memory and then copy it back to GPU as texture. Of coarse that is much much slower then direct rendering to texture. So here is the deal:
设置低分辨率视图
不要仅更改窗口的分辨率 glViewport
值.然后以低分辨率渲染场景(仅占屏幕空间的一小部分)
do not change resolution of your window just the glViewport
values. Then render your scene in the low res (in just a fraction of screen space)
将渲染的屏幕复制到纹理中
渲染纹理
不要忘记使用 GL_NEAREST
过滤器.最重要的是,您只能在此之后而不是之前交换缓冲区!!!否则你会有闪烁.
do not forget to use GL_NEAREST
filter. The most important thing is that you swap buffers only after this not before !!! otherwise you would have flickering.
这里是 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 显卡(天知道哪个版本)上测试了这个,我可以使用它并且它可以工作(而标准渲染到纹理方法不是).
I tested this on some Intel HD graphics (god knows which version) I got at my disposal and it works (while standard render to texture approaches are not).
相关文章