【问题标题】:How are blinking carets often implemented?闪烁插入符号通常是如何实现的?
【发布时间】:2017-09-19 12:50:06
【问题描述】:

我正在尝试实现一个占用尽可能少系统资源的跨平台 UI 库。我正在考虑使用我自己的软件渲染器或 opengl。

对于固定控制一切都很好,我只能在需要时重新绘制。然而,在实现动画时,尤其是像 sublime 文本中的“阶段”插入符号这样的动画闪烁插入符号,我看不到平衡资源使用和性能的简单方法。

对于闪烁的插入符号,需要非常频繁地重新绘制插入符号(我猜至少每秒 15-20 次)。一方面,软件渲染器支持部分重绘,但速度太慢而无法实用(大型重绘区域为 3-4 fps,例如 1000x800,这使得无法实现动画)。另一方面,据我所知,opengl 并不能很好地支持部分重绘,这意味着整个屏幕需要不断地以 15-20 fps 的速度渲染。

所以我的问题是:

  1. 插入符号通常如何在各种 UI 系统中实现?
  2. 有没有办法让 opengl 只渲染到屏幕的一部分?
    • 我知道 glViewport 可以渲染到屏幕的一部分,但由于双缓冲或其他原因,屏幕的其余部分不会保持原样。这样我还是需要重新渲染整个屏幕。

【问题讨论】:

  • 如果你每秒画任何东西 15-20 次,人眼无法感知变化。这就是为什么 15-20 fps 是所需帧速率的基础。闪烁的插入符号应该以 0.3-0.6 fps 的速度绘制。
  • 好吧,如果你看一下 sublime text 的插入符号,你会发现它实际上是平滑动画的,所以我猜这需要比没有动画时更高的 fps。

标签: user-interface opengl cross-platform caret


【解决方案1】:

首先你需要问自己。 我真的需要部分重绘屏幕吗?

OpenGL 或者更好的说法是 GPU 可以轻松绘制数千个三角形。因此,在您开始调整屏幕的部分重绘之前,您应该改为进行基准测试,看看它是否值得研究。

但这并不意味着您必须无休止地重新绘制屏幕。您仍然可以在发生更改时重新绘制它。

因此,如果您的光标每 500 毫秒闪烁一次,那么您每 500 毫秒重绘一次。如果您正在运行动画,那么您会在该动画播放时(或每次动画进行需要重绘的更改时)不断地重绘。

这就是 Chrome、Firefox 等所做的。如果您打开开发者工具 (F12) 并转到“时间轴”选项卡,您可以看到这一点。

看看下面的截图。时间线的第一行显示 Chrome 重绘窗口的频率。

  • 第一部分显示了很多连续重绘。 这是因为我在页面上滚动。
  • 最后一节显示了每 500 毫秒一次的重绘。 光标在文本框中闪烁。

在新标签页中打开图片,以更好地了解正在发生的事情。

请注意,它无法判断 Chrome 是完全重绘窗口还是仅重绘窗口的一部分。它只是显示重绘的频率。 (如果你想看到重绘的区域,那么 Firefox 和 Chrome 都有“显示绘制矩形”。

为了规避双缓冲和部分重绘的问题。然后,您可以改为绘制到帧缓冲区对象。现在您可以随意使用glScissor()。如果您有各种静态的东西,而只有少数动态的东西。然后你可以有多个帧缓冲区对象,只绘制一次静态内容,并不断更新包含动态内容的帧缓冲区。

但是(我不能强调这一点)基准测试并检查是否需要这样做。拥有两个帧缓冲区对象可能比总是重绘所有内容更昂贵。与将所有矩形打包在一个缓冲区中相比,每个矩形都有一个缓冲区也是如此。

最后举个例子,让我们以NanoGUI (a minimalistic GUI library for OpenGL)为例。 NanoGUI 不断重绘屏幕。 不只是不断重绘屏幕的问题是,现在您需要一个系统来发出重绘。现在在标签上调用setText() 需要回调并告诉窗口重绘。现在如果添加标签的父面板不可见怎么办?然后setText()刚刚发出了多余的画面重绘。

我想说的是,如果你有一个系统来发布屏幕重绘。那么这可能更容易出错。因此,除非不断重绘是一个问题,否则这绝对是一个更理想的起点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-09
    相关资源
    最近更新 更多