典型的 OpenGL 实现会将大量调用排队,以将它们批处理成活动突发,以最佳利用可用的通信带宽和 GPU 时间资源。
您要做的基本上与双缓冲渲染相反,即在每个绘图步骤立即可见的地方进行渲染。一种方法是渲染到单个缓冲窗口并glFinish()
在每一步之后调用。主要缺点:它可能无法在使用合成窗口管理器等的现代系统上运行良好。
我推荐的另一种方法是使用单独的缓冲区进行增量绘图,并不断刷新主帧缓冲区。关键主题是Frame Buffer Object和Render To Texture。
首先,您创建一个 FBO(大量教程以及 StackOverflow 上的答案)。FBO 基本上是一种抽象,您可以将目标缓冲区(如纹理或渲染缓冲区)连接到它,并且可以将其绑定为绘图调用的目的地。
那么如何解决你的问题呢?首先,您不应该通过延迟绘图循环来制作动画。这有几个原因,但主要问题是,您因此失去了程序的交互性。相反,您在动画中的哪一步维护一个(全局)计数器。让我们称之为step
:
int step = 0;
然后在您的绘图功能中,您必须分阶段:1)纹理更新 2)屏幕刷新
第一阶段包括将帧缓冲区对象绑定为渲染目标。为此,目标纹理必须是未绑定的
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, animFBO);
glViewport(0, 0, fbo.width, fbo.height);
set_animFBO_projection();
现在的诀窍是,您只清除一次 animFBO,即在创建之后,然后再也不清除。现在您根据动画步骤绘制线条
draw_lines_for_step(step);
并增加计步器(可以作为复合语句执行此操作,但这更明确)
step++;
更新动画 FBO 后,是时候更新屏幕了。首先解绑animFBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);
我们现在在主要的屏幕帧缓冲区上
glViewport(0, 0, window.width, window.height);
set_window_projection(); //most likely a glMatrixMode(GL_PROJECTION); glOrtho(0, 1, 0, 1, -1, 1);
现在绑定 FBO 附加纹理并将其绘制到一个完整的视口四边形
glBindTexture(GL_TEXTURE_2D, animFBOTexture);
draw_full_viewport_textured_quad();
最后做缓冲区交换以显示动画步骤迭代
SwapBuffers();