使用 OpenGL 和 SDL 处理窗口大小调整
Posted
技术标签:
【中文标题】使用 OpenGL 和 SDL 处理窗口大小调整【英文标题】:Handling window resizing using OpenGL and SDL 【发布时间】:2012-02-04 05:03:20 【问题描述】:根据我在应用程序窗口周围绘制和移动正方形的程序的代码,我在调整应用程序窗口大小时遇到了问题。当我相应地处理调整大小并更改状态时,屏幕上应该绘制并且在调整大小之前的所有内容都消失了。我不知道为什么,因为在调整窗口大小期间没有任何对象内部坐标发生变化。
我的问题是谁能指出我正确的方向来解决我的问题。(代码编译得很好)
void ResizeWindow()
screen_width = event.resize.w;
screen_height = event.resize.h;
SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF);
glViewport(0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION);
glOrtho(0, screen_width, 0, screen_height, -1, 1);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
主循环:
while (running == true)
while(SDL_PollEvent(&event))
switch(event.type)
case SDL_VIDEORESIZE: ResizeWindow(); break; // resizing called here
case SDL_QUIT: running = false; break;
case SDL_KEYDOWN: square.Handle_Input(down); break;
case SDL_KEYUP: square.Handle_Input(up); break;
square.Move();
square.Check_Collision();
glClear(GL_COLOR_BUFFER_BIT);
square.Draw();
SDL_GL_SwapBuffers();
在调整窗口大小之前,一切都运行良好。
【问题讨论】:
我看到了您之前的问题,但当时无法指出所有问题。我相信你还没有解决你之前的问题。您可能应该发布您所做的更改以使其作为您自己的答案并关闭问题。 我的建议是否解决了问题? 自从我发布这个问题以来我一直在睡觉,你的回答很有道理,尤其是关于 SDL_SetVideoMode 的那一点,回头看,这似乎是我的一个愚蠢的错误。我之前发布的问题确实有一个问题,这是我的另一个大错误;我是凭记忆工作的,没有查找 glOrtho 参数。我认为它从左到右为 0-0。我现在就试试你的建议 在 sdl 2.0 中 resize 事件被称为SDL_WINDOWEVENT_RESIZED
【参考方案1】:
我已经复制粘贴了您的代码,我将逐行解释发生了什么。它不仅可以帮助您了解调整大小后屏幕变黑的原因,还可以帮助您删除不需要的内容。
void ResizeWindow()
接下来的几行很好!您已经从 resize 事件中获得了新的屏幕宽度和高度。我假设在您的代码中此时可以访问该事件。
screen_width = event.resize.w;
screen_height = event.resize.h;
我怀疑您是否需要致电 SDL_SetViedoMode
。我希望它仅在设置 OpenGL 窗口时使用。我目前没有使用 SDL 的经验,所以我不能确定。我确实快速查看了文档,这似乎支持按照我预期的方式使用它。
SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF);
现在我们开始讨论有趣的 GL 内容。您已调整视口的大小,这是必要的。
glViewport(0, 0, screen_width, screen_height);
现在,您正在制作一个新的投影矩阵来保持纵横比(除非我弄错了)。你已经切换了矩阵模式,设置了一个正交投影矩阵,这很明智。
glMatrixMode(GL_PROJECTION);
glOrtho(0, screen_width, 0, screen_height, -1, 1);
现在,您将投影矩阵设置为恒等式,覆盖旧的 OpenGL 投影矩阵并撤消您所做的所有出色工作。这就是屏幕变黑的原因。
glLoadIdentity();
现在,您切换到模型视图矩阵并将其设置为恒等式,这并不是必需的,只要您在其他地方正确设置即可。
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
我怀疑你真的需要下一行。无论如何,您为什么要在调整大小后清除屏幕?您确实想重绘它,但我确信您的绘图函数会清除屏幕并绘制刷新完成后将自动调用的对象。
glClear(GL_COLOR_BUFFER_BIT);
而且您绝对不需要再次将当前的模型视图矩阵重新设置为标识。 OpenGL 仍处于模型视图模式,并且该矩阵已设置为标识!请记住,OpenGL 是一个状态机!
glLoadIdentity();
【讨论】:
【参考方案2】:您可能遇到的一个问题是,使用 SDL 调整窗口大小会创建一个新的 OpenGL 上下文,这意味着您之前上传的所有内容(纹理、顶点缓冲区对象)和您设置的状态(如顶点数组指针)都是丢失。如果使用 SDL,您需要重新初始化它们。如果要保留它们,请不要使用 SDL 进行窗口管理。我推荐 GLFW。
这个
void ResizeWindow()
screen_width = event.resize.w;
screen_height = event.resize.h;
SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF);
glViewport(0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION);
glOrtho(0, screen_width, 0, screen_height, -1, 1);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
是初学者 OpenGL 代码中最常见的反模式。影响绘图的绘图命令和状态管理属于绘图功能。那就是:
glViewport(0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION);
glOrtho(0, screen_width, 0, screen_height, -1, 1);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
如果您想要一个健壮的 OpenGL 程序,请永远不要(仅)将它们放入调整大小处理程序中。它们属于其他绘图命令。
【讨论】:
我想我明白你在说什么。在 SDL 中调整大小时,真的没有最小努力的方法来保持程序正常运行吗? 所以他确实需要调用 SDL_SetVideoMode?另外,调整视口大小并在开始和调整大小期间设置投影不是明智的吗?事实上,如果我想保持纵横比,我认为这是必不可少的。至于模型视图矩阵,我会根据需要在绘图期间设置它。当然,这并没有考虑到现代 OpenGL 实践,只考虑了立即模式。 我同意状态管理和绘图命令应该放在绘图函数中。但是,我发现在做简单的事情时,在调整大小函数(和初始化函数)中设置投影矩阵和视口很方便。 对 SDL_SetVideoMode 的调用必须在某处的调整大小代码中。我现在想知道的是,如果可能的话,如何完全重置矩阵,这样我就可以在调整窗口大小时从头开始 好的,我明白了。我的目标是学习OpenGL。在我开始编程时,一位亲戚建议使用 SDL,因为它易于使用。我会试试你对 GLFW 的建议。感谢您的帮助以上是关于使用 OpenGL 和 SDL 处理窗口大小调整的主要内容,如果未能解决你的问题,请参考以下文章