我只是想做一些移动物体的简单动画(例如在C ++中使用OpenGL) - 让我们说从左到右的方形的简单水平移动。
在OpenGL中,我可以使用“双缓冲”方法,假设用户(使用动画运行我的应用程序)已经打开“垂直同步” - 所以每次监视器刷新时我都可以调用某些函数(我可以实现这一点,例如使用Qt toolkit及其函数“swapBuffers”。
所以,我认为,我能够实现的“最流畅”的动画是“每次监视器刷新时移动方块例如1个像素(可以是其他值)”,所以在每个“帧”处,方块是进一步增加1个像素 - “我已经测试了这个,而且它的工作时间很平稳”。
但是当我想要“游戏逻辑”的“单独”线程(向右移动1个像素)和“动画”(在屏幕上显示正方形的当前位置)时,问题就出现了。因为我们假设游戏逻辑线程是一个while循环,我将方块移动1个像素,然后“休眠”一段时间,例如10毫秒,我的监视器每隔16毫秒刷新一次 - 方块的移动“将不会100%平滑”,因为有时显示器将刷新两次,其中方块仅移动1个像素而不是2个像素(因为监视器和游戏逻辑线程有两个“不同”频率) - 以及移动会看起来“有点生涩”。
所以,从逻辑上讲,我可以使用第一个超顺畅的方法,但是,它不能用于例如“多人游戏”(例如“服务器 - 客户端”)游戏 - 因为不同的计算机具有不同的监视频率(所以我应该为游戏逻辑(在服务器上)和动画(在客户端上)使用不同的线程。)
所以我的问题是: 是否有一些方法,使用不同的线程进行游戏逻辑和动画,对某些移动物体进行“100%平滑”动画,如果存在,请在此处描述,或者当我只有一些“更复杂的渲染场景”时,我只是不会看到我现在看到的那种“小生涩的动作”,当我横向移动一些简单的方形时,我深深地专注于它:)?
答案 0 :(得分:6)
嗯,这实际上是典型的单独游戏循环行为。您可以在一个线程中管理所有与物理(运动)相关的操作,让渲染线程完成其工作。这实际上是可取的。
不要忘记这种游戏循环的实现方式是在保持恒定物理速度的同时拥有最大可用帧速率。如果没有任何其他与代码相关的问题,则在更高的FPS下,您无法通过任何机会看到此效果。例如,在帧率和物理之间有一些挂钩。
如果要实现所描述的完美平滑,可以将物理引擎与VSync同步。只需在刷新之前完成所有物理操作,而不是等待另一个。
但这一切都适用于恒速物体。如果你有动态速度的对象,你永远不知道何时绘制它是“同步”。出现同样的问题,那么你想要多个具有不同恒定速度的物体。
此外,这不是你想要的复杂场景。 V-sync的整个想法是限制屏幕撕裂效果。绝对不应该挂钩你的物理或渲染代码来显示刷新率。您希望您的物理代码独立于用户运行显示刷新率。例如,这可能是多人游戏中的真正痛苦。首先,请查看此页面:How A Game Loop Works
编辑: 我说你对完美光滑的看法是不现实的。您可以使用Kevin写的技术来掩盖它。但是,您将始终努力克服硬件限制作为刷新率或显示像素化。例如,您有640x480像素的窗口。现在,您希望对象水平移动。您可以通过向右箭头向前移动对象,但必须按浮点数(640/480)增加对象坐标。但在渲染中,你会转向整数。所以你的对象移动了锯齿状。没办法解决这个问题。在很小的速度,你可以注意到它。你可以模糊它,或者让它移动得更快,但永远不要摆脱它......
答案 1 :(得分:5)
允许您的对象移动一小部分像素。在OpenGL中,可以通过将正方形绘制到纹理(即一个像素或更大的边框)上而不是让它只是多边形边缘来为广场的示例完成此操作。如果你正在渲染2D精灵图形,那么你会非常自动地得到它(但是如果你有1:1的像素艺术,它会在穿过像素边界时模糊/锐利/模糊)。
平滑(抗锯齿)多边形边缘(GL_POLYGON_SMOOTH)。这种技术的问题在于它不能用于基于Z缓冲区的渲染,因为它会导致透明度,但是如果你正在做2D场景,你可以确保始终从前到后绘制。
启用多重采样/超采样抗锯齿,这种方法比较昂贵,但没有上述问题。
让你的物体具有足够的动画外观,使得像素移动不容易被注意到,因为在那个边缘有更多的东西(即它本身在远远超过1个像素/帧的位置移动)
让你的游戏变得足够复杂和引人入胜,让玩家分心观看像素。 :)