EGE专栏:EGE专栏

上一篇:EGE基础入门篇(八):清屏与重绘

下一篇:

文章目录

  • 一、双缓冲机制
    • 1. 单缓冲绘图
      • 1.1 单缓冲绘图的缺点
      • 1.2 系统读取帧缓冲
    • 2. 双缓冲绘图
      • 2.1 双缓冲绘图流程
      • 2.2 缓冲区之间的数据交换操作 : SwapBuffers()
  • 二、EGE中的双缓冲机制与手动渲染模式
    • 1. EGE双缓冲
    • 2. 如何触发SwapBuffers操作?
    • 3. EGE手动渲染模式
      • 3.1 EGE中的渲染模式
        • 3.1.1 自动渲染模式
        • 3.1.2 手动渲染模式
      • 3.2 渲染模式的设置
        • 3.2.1 在窗口初始化时设置
        • 3.2.2 setrendermode函数

一、双缓冲机制

  双缓冲是一种基本的动画技术,主要用于解决单缓冲清除图像图像绘制过程所带来的窗口闪烁问题。

  双缓冲指的是使用两块用于画面显示的帧缓冲区的一种绘图技术,只使用一块帧缓冲区的则称为单缓冲

1. 单缓冲绘图

  单缓冲是指程序只使用一块帧缓冲来进行绘图显示。这时帧缓冲既要被系统读取并显示屏幕上,又要作为程序绘图的目标。

1.1 单缓冲绘图的缺点

  程序绘图需要一定的时间,系统读取帧缓冲和程序绘图的时间并不是同步的,也就是说程序并不确切知道系统什么时候要来读取帧缓冲
  这样一来就有个很大的问题,如果在程序还没有将下一帧图像绘制完成的时候,系统就来读帧缓存,就会出现如下这种情况:

  “哟,大哥!您怎么来了?”
  “这不是到点了吗,我来收画了!快把你的画拿来,我临摹一份,拿出去给上级看看!”
  “哎哟,我这的时钟不准,忽快忽慢的。这不,我看到外边的景物变了,想对照着重画一幅呢。没想到这么巧,刚画了一半,您就来了!”
  “外边的人都等不及了,那就这样,这次画的就算了,把上次画的那份拿来吧,样子都差不多,那份也行。”
  “哎呀!您不是不知道,我家里就只有这么一块宝贝画板。要重新画,只能之前画的擦掉了,不然看着乱糟糟的。”
  “就你小子事多,怎么这么抠门,画板也不舍得多买一块!唉,算了,直接把你这份给我吧,没画完就没画完吧,总好过没得交差,不然上头怪罪下来,非把你给辞了不可!这次我先帮你担着,下次要给我好好表现!”
  “大哥放心,下次一定,下次一定!”
  话毕,大哥临摹了一幅半成品就急匆匆跑下一家去了。
  …
  看着墙上的时钟,大哥掐好了点出门,跑了几家后,看着手上拿着的几幅佳作,很是满意。不久后,大哥再次走到了那扇门前。“这次几幅画都很不错,上级肯定会多多夸奖我几句!上次就这小子的画出了问题,上级虽然嘴上没说什么,但心里肯定有点不愉快。这次可别给整我出什么幺蛾子了!”
  大哥怀着期待的心情推开了门,一进屋,那种似曾相识的感觉扑面而来。。。随后留下两人看着那块空白的画板大眼瞪小眼。
  …

  你:“什么垃*程序,窗口闪成这样!”,退出卸载删除一键三连

  系统通常会以每秒60次的频率读取窗口帧缓冲,然后显示到屏幕上。通常程序绘图和系统读取窗口帧缓冲的时间很难保持同步,很有可能窗口正在绘图的时候系统来读取帧缓存,此时就将不完整的一帧显示到了屏幕上
  如果这些没有绘制完成的相邻帧之间有很大的反差,那么人眼就会感觉到窗口闪烁。

1.2 系统读取帧缓冲

  由于系统读取帧缓冲和程序绘图的时间并不同步,所以程序的帧缓冲很有可能在绘图的任意阶段被系统读取。
  如下图所示,在一个绘图周期中分为绘图阶段绘图完成阶段。在绘图阶段程序尚未完成绘图,此时不应被系统读取,否则未完成的图形将会被显示到屏幕上。此时显示到屏幕上将是绘图过程中的任意一个图形,如果绘图过程图形的变化极大,那么极容易引起闪烁。绘图阶段占整个绘图周期的比例越大,闪烁发生的概率越高。
  在绘图完成阶段缓冲区中已是完整的一帧,此时允许被系统读取。

  在绘图阶段被读取时,图形变化过程中的任意一个图形都有可能被显示到屏幕上,而且顺序是不定的。在屏幕上图形不断的变化中,人眼就能明显地感觉到闪烁。

2. 双缓冲绘图

  双缓冲绘图使用两块帧缓冲,一块帧缓冲用于显示,另一块帧缓冲用于绘图。

用于显示的帧缓冲称为屏幕缓冲区(on-screen buffer),也叫前台缓冲区(front buffer)
用于绘图的帧缓冲称为离屏缓冲区(off-screen buffer),也叫后台缓冲区(back buffer)

2.1 双缓冲绘图流程

  系统会不断地从前台缓冲区(屏幕缓冲区)中读取图像数据,程序绘图则需要保证前台缓冲区的数据都是完整的一帧,只在后台缓冲区(离屏缓冲区)上绘图
  当绘图完成后,才会交换两个缓冲区中的数据,使得前台缓冲区中的图像数据变成和原来后台缓冲区中的一致。这样就完成了一帧的绘图操作并平滑地显示在了屏幕上。

  这个交换缓冲区数据操作,通常是复制或者直接交换两个缓冲区首地址指针,取决于各平台的实现。在windows平台中通常是通过复制操作来实现。
  参见 Front, Back, and Other Buffers 和 Buffer Functions


  由于系统只从前台缓冲区中读取图像数据,而我们是在后台缓冲区上绘制,绘制完成后才快速交换数据。所以绘图过程中的不完整帧,不会被系统读取到,也就不会被显示到屏幕上,这样就避免了闪烁

2.2 缓冲区之间的数据交换操作 : SwapBuffers()

  上面提到,当在后台缓冲区绘制完一帧后,需要将这一帧的图像数据交换到前台缓冲区中。
  这个操作通常称为交换缓冲区(Swap Buffers)。这里的交换并不是真的就是两个缓冲区互换,而是有两种不同的实现方式:

  一种是通过数据复制来实现,直接将后台缓冲区里的数据复制到前台缓冲区上,这也是windows上的常用实现。(参见 Front, Back, and Other Buffers 和 Buffer Functions),当然,这种方式无疑会有不小的开销。

  另一种是通过交换缓冲区的指针或引用来实现,而这一种实现也被称作页交换。交换仅仅只需要改变一个指针的操作,非常高效。


  这两种不同的实现方式各有利弊,至于使用哪种实现,各平台有自己的考量。这里仅列出《游戏编程模式》中的解释:

参考链接:《游戏编程模式》双缓冲模式

二、EGE中的双缓冲机制与手动渲染模式

1. EGE双缓冲

  除了窗口本身的帧缓冲外,EGE还额外创建了一块帧缓冲,构成双缓冲
  EGE以内部的帧缓冲作为后台缓冲区,绘图都是在这块缓冲区中进行,绘图完成后,调用特定的函数即可将后台缓冲区中的数据复制到前台缓冲区中,完成图像显示。

2. 如何触发SwapBuffers操作?

  EGE中的 SwapBuffers 操作是通过复制缓冲区实现,而不是交换缓冲区指针。

  EGE触发SwapBuffers有两种方式,一种是靠内部50ms定时器触发,另一种是调用EGE延时及阻塞类函数时触发。

  EGE延时及阻塞类函数包括 getch(), getkey(), getmouse(),delay_fps(),delay_ms() 等,这些函数的调用会触发SwapBuffers操作,前提是调用了EGE的绘图函数,让其检测有绘图操作。

  由内部50ms定时器触发的SwapBuffers操作,这个是十分不建议的。因为双缓冲本身就是为了防止因未完成的图形内容显示到屏幕上造成的闪烁,如果绘图未完成时定时器触发了SwapBuffers操作,那么就会使得未完成的图形内容在屏幕上显示,无法达到避免闪烁的效果。这样也仅仅是将闪烁频率从60Hz降到了20Hz而已,只能用于不断叠加绘制的绘图中,一旦清屏重绘,闪烁将十分明显。
  内部50ms定时器是默认开启的,那么通过什么设置可以关闭定时器触发SwapBuffers操作呢?这就是接下来的手动渲染模式

3. EGE手动渲染模式

  EGE通过设置手动渲染模式,直接禁用由内部定时器触发的 SwapBuffers 操作。这样后台缓冲区和前台缓冲区的交换操作,只能由用户调用延时及阻塞类函数来触发,不会有在绘图过程中莫名触发交换缓冲区的情况发生。
  用户就可以在完成一帧的绘制后手动调用延时及阻塞类函数来进行缓冲区交换,完成双缓冲消除闪烁的功能。

  当程序有清屏重绘的操作时,就需要设置手动渲染模式,来避免图形闪烁。
  设置为手动渲染模式后,通过调用常用的delay_fps()或delay_ms(), getch()等来触发SwapBuffers。

下面是简单的一个设置示例:

#include <graphics.h>int main()
{//创建窗口,设置手动渲染模式initgraph(640,480, INIT_RENDERMANUAL);//帧循环,通过delay_fps()触发缓冲区交换for ( ; is_run(); delay_fps(60)) {//清屏cleardevice();//绘图,中途可使用getch()暂停,或者调用delay_ms(0)触发缓冲区交换}closegraph();return 0;
}

  在初始化参数中传入INIT_RENDERMANUAL便能简单地完成手动渲染模式的设置。下面则更为详细地介绍EGE中的自动渲染模式手动渲染模式。

3.1 EGE中的渲染模式

渲染模式 分为 自动渲染手动渲染默认为自动渲染

3.1.1 自动渲染模式

  自动渲染模式,即调用绘图类的函数后,由库决定何时刷新(50ms定时),把绘画的内容显示到窗口上。

  优点:绘画后显示
  缺点:少量绘制后便会刷新一次窗口,当绘制复杂时,多次刷新比较费时,造成绘制慢。因为不确定刷新时间点,可能在没有绘制完一帧时就显示内容,容易出现窗口闪烁现象。

3.1.2 手动渲染模式

  手动渲染模式,即需要自己调用 delay_fps, delay_ms, getch()带有等待特性并具有刷新功能的函数来刷新窗口,加快绘制速度,避免闪烁。

  优点:减少刷新次数,加快绘制。并且只在调用某些延时类函数时刷新,避免显示不完整的一帧,减少闪烁。
  缺点:不调用延时函数时不会刷新窗口,如果整个循环没有调用带刷新功能延时类函数,将看不到绘制内容。

  绘制时推荐一直使用手动渲染模式,这将提高绘制效率并将减少闪烁情况。 当有刷新窗口、查看显示内容的需要时,可以插入delay_ms(0) 来手动刷新,或者加入 getch() 暂停来查看。

  如果你的程序有清屏之类窗口颜色变化极大的,那就必须设置为手动渲染模式,否则画面容易出现问题。

3.2 渲染模式的设置

3.2.1 在窗口初始化时设置

  调用initgraph() 初始化图形环境时,在初始化模式参数中传入INIT_RENDERMANUAL即可设置成 手动渲染模式, 默认为 自动渲染模式

initgraph(640, 480, INIT_RENDERMANUAL);

  初始化模式参数也可在 setinitmode() 中设置。

setinitmode(0, 0, INIT_RENDERMANUAL);
initgraph(640, 480);

3.2.2 setrendermode函数

  setrendermode(), 用于改变渲染模式,需要在初始化窗口 initgraph() 之后调用

void setrendermode(rendermode_e mode);

参数 mode,
值有两个可选:自动模式用于简单静态绘图,手动模式用于制作动画或者游戏

  • RENDER_AUTO (自动渲染,默认模式)

  • RENDER_MANUAL (手动渲染)


EGE专栏:EGE专栏

上一篇:EGE基础入门篇(八):清屏与重绘

下一篇:

EGE基础入门篇(九):双缓冲与手动渲染相关推荐

  1. EGE基础入门篇(八):清屏与重绘

    EGE专栏:EGE专栏 上一篇:EGE基础入门篇(七):组合图形 下一篇:EGE基础入门篇(九):双缓冲与手动渲染 一.清屏   清屏即 清除屏幕(clear screen) ,可以将窗口上的输出内容 ...

  2. EGE基础入门篇(六):基本图形

    EGE专栏:EGE专栏 上一篇:EGE基础入门篇(五):窗口简单操作 下一篇:EGE基础入门篇(七):组合图形 一.EGE提供的基本图形 EGE绘制图形相关库函数文档 https://xege.org ...

  3. EGE基础入门篇(二):开始使用EGE

    EGE专栏:EGE专栏 上一篇:EGE基础入门篇(一):绘图基础知识 下一篇:EGE基础入门篇(三):开场动画 EGE基础入门篇(二) 文章最后修改时间:2021年6月23日19:30:47 文章目录 ...

  4. EGE基础入门篇(三):开场动画

    EGE专栏:EGE专栏 上一篇:EGE基础入门篇(二):开始使用EGE 下一篇:EGE基础入门篇(四):窗口简单操作 文章目录 开场动画 1. EGE开场动画的默认方式 2. 开场动画的开启 3. 开 ...

  5. EGE基础入门篇(七):组合图形

    EGE专栏:EGE专栏 上一篇:EGE基础入门篇(六):基本图形 下一篇:EGE基础入门篇(八):清屏与重绘 一. 组合图形 1. 复杂图形由基本图形组合而成   复杂的图形可以由基本图形组合而成,如 ...

  6. FPGA基础入门篇(四) 边沿检测电路

    FPGA基础入门篇(四)--边沿检测电路 一.边沿检测 边沿检测,就是检测输入信号,或者FPGA内部逻辑信号的跳变,即上升沿或者下降沿的检测.在检测到所需要的边沿后产生一个高电平的脉冲.这在FPGA电 ...

  7. JAVA中整型常量的长度,Java基础入门篇(三)——Java常量、变量,

    Java基础入门篇(三)--Java常量.变量, 一.Java常量 (一)什么是常量 常量指的是在程序中固定不变的值,是不能改变的数据.在Java中,常量包括整型常量.浮点型常量.布尔常量.字符常量等 ...

  8. 1、Latex学习笔记之基础入门篇

    目录 一.Latex基础 1.架构 2.引用.脚注 3.单栏.双栏 4.常用快捷键 5.宏包 6.空格 7.换行.行间距 8.换段 9.下划线 10.引号 11.注释 12.字体 13.缩进 14.超 ...

  9. 《Ansible权威指南 》一 第一篇 Part 1 基础入门篇

    本节书摘来自华章出版社<Ansible权威指南 >一书中的第1章,第1.1节,李松涛 魏 巍 甘 捷 著更多章节内容可以访问云栖社区"华章计算机"公众号查看. 第一篇 ...

最新文章

  1. vim的简单介绍与使用
  2. final类是否可以被代理_设计模式——代理模式
  3. QT的QStackedWidget类的使用
  4. Matlab中plot函数绘图基本用法
  5. AngularJS + Java---前台网页与后台数据库传递数据 基本结构
  6. 1. ansible-playbook 变量定义与引用
  7. python内置函数升序降序_python内置函数之sorted
  8. 项目管理必看书籍推荐
  9. 大专学历计算机专业可以积分,持有大专紧缺急需专业可直接申请上海居住证积分?...
  10. 家用计算机如何连无线网,电脑上怎么连接wifi_怎样连接自己家的wifi-win7之家
  11. (小程序) 客户签名及签名后页面整体转图片后上传
  12. mysql忘记密码怎么处理
  13. TensorRT(8):动态batch进行推理
  14. RDD(python
  15. 计算机专业简历的自我介绍,计算机专业简历自我介绍范文 .docx
  16. 桌面快捷图标左下角有蓝色问号解决方法
  17. CorelDRAW VBA - 遍历文档、页面、图层和形状对象
  18. excel统计求和:如何在合并后的单元格中复制求和公式
  19. 可能是MacOS中最好用的集成开发工具-Xcode初学者(C/C++ 新生)教程
  20. ARFoundation环境配置及项目打包

热门文章

  1. 《C语言小程序篇---1》——实现一个“富婆通讯录“(超详细)
  2. 老铁啊,我同你讲, 这年头不会点 Git 真不行!!!
  3. 驱寒药不妨试试这几种食物
  4. 羽素登陆《岭南大医生》专业顾问带你避雷护肤误区
  5. Win11怎么连接宽带?
  6. linux文件中插入多行技巧
  7. NASA CEA 安装指南
  8. python经典小游戏贪吃蛇_Python开发贪吃蛇小游戏
  9. 灵活组合复合图元模板,电路图状态图业务定义可配置,浮云E绘图软件源码开发
  10. 在Home Assistant中配置天气信息