脏矩形
在哪里可以找到有关实现计算“脏矩形”以最小化帧缓冲区更新的算法的参考资料? 一种显示模型,允许任意编辑并计算更新显示所需的最小“位块传输”操作集。
Where may one find references on implementing an algorithm for calculating a "dirty rectangle" for minimizing frame buffer updates? A display model that permits arbitrary edits and computes the minimal set of "bit blit" operations required to update the display.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
Vexi 是此的参考实现。 该类是 org.vexi.util.DirtyList(Apache 许可证),并用作生产系统的一部分,即经过彻底测试,并得到很好的评论。
需要注意的是,当前的类描述有点不准确,“一种通用数据结构,用于保存需要重新绘制的矩形区域列表,并具有智能合并功能。”实际上,目前还没有这样做合并。 因此,您可以认为这是一个基本的 DirtyList 实现,因为它仅与 dirty() 请求相交,以确保没有重叠的脏区域。
此实现的一个细微差别是,区域不是使用 Rect 或其他类似的区域对象,而是存储在一个整数数组中,即一维数组中的 4 个整数块中。 这样做是为了提高运行时效率,尽管回想起来我不确定这样做是否有很多优点。 (是的,我实现了它。)用 Rect 替换正在使用的数组块应该足够简单。
该类的目的是快。 使用 Vexi,脏可能每帧被调用数千次,因此脏区域与脏请求的交集必须尽可能快。 使用不超过 4 个数字比较来确定两个区域的相对位置。
由于缺少合并,它并不完全是最佳的。 虽然它确实确保脏/绘制区域之间没有重叠,但您最终可能会得到排列并可以合并到更大区域的区域 - 从而减少绘制调用的数量。
代码片段。 完整代码 在线访问。
Vexi is a reference implementation of this. The class is org.vexi.util.DirtyList (Apache License), and is used as part of production systems i.e. thoroughly tested, and is well commented.
A caveat, the currently class description is a bit inaccurate, "A general-purpose data structure for holding a list of rectangular regions that need to be repainted, with intelligent coalescing." Actually it does not currently do the coalescing. Therefore you can consider this a basic DirtyList implementation in that it only intersects dirty() requests to make sure there are no overlapping dirty regions.
The one nuance to this implementation is that, instead of using Rect or another similar region object, the regions are stored in an array of ints i.e. in blocks of 4 ints in a 1-dimensional array. This is done for run time efficiency although in retrospect I'm not sure whether there's much merit to this. (Yes, I implemented it.) It should be simple enough to substitute Rect for the array blocks in use.
The purpose of the class is to be fast. With Vexi, dirty may be called thousands of times per frame, so intersections of the dirty regions with the dirty request has to be as quick as possible. No more than 4 number comparisons are used to determine the relative position of two regions.
It is not entirely optimal due to the missing coalescing. Whilst it does ensure no overlaps between dirty/painted regions, you might end up with regions that line up and could be merged into a larger region - and therefore reducing the number of paint calls.
Code snippet. Full code online here.
要构建包含所有需要重新绘制的区域的最小矩形:
对于每个脏区域添加:
Windows 至少维护一个更新区域,其中包含已通知的更改以及由于窗口被遮挡和显示而需要完成的任何重新绘制。 区域是由许多可能不连续的矩形、多边形和椭圆组成的对象。 您可以通过调用 InvalidateRect 告诉 Windows 屏幕的一部分需要重新绘制 - 对于更复杂的区域,还有一个 InvalidateRgn 函数。 如果您选择在下一个 WM_PAINT 消息到达之前进行一些绘制,并且希望将其从脏区域中排除,可以使用 ValidateRect 和 ValidateRgn 函数。
当您开始使用 BeginPaint 进行绘画时,您需要提供一个 PAINTSTRUCT,Windows 会用该 PAINTSTRUCT 填充有关需要绘画的内容的信息。 其中成员之一是包含无效区域的最小矩形。 如果您想在存在多个小的无效区域时最小化绘制,您可以使用 GetUpdateRgn 获取区域本身(您必须在 BeginPaint 之前调用它,因为 BeginPaint 将整个窗口标记为有效)。
我认为,由于在最初编写这些环境时最小化绘图在 Mac 和 X 上非常重要,因此存在用于维护更新区域的等效机制。
To build the smallest rectangle that contains all the areas that need to be repainted:
For each dirty area added:
Windows, at least, maintains an update region of the changes that it's been informed of, and any repainting that needs to be done due to the window being obscured and revealed. A region is an object that is made up of many possibly discontinuous rectangles, polygons and ellipses. You tell Windows about a part of the screen that needs to be repainted by calling InvalidateRect - there is also an InvalidateRgn function for more complicated areas. If you choose to do some painting before the next WM_PAINT message arrives, and you want to exclude that from the dirty area, there are ValidateRect and ValidateRgn functions.
When you start painting with BeginPaint, you supply a PAINTSTRUCT that Windows fills with information about what needs to be painted. One of the members is the smallest rectangle that contains the invalid region. You can get the region itself using GetUpdateRgn (you must call this before BeginPaint, because BeginPaint marks the whole window as valid) if you want to minimize drawing when there are multiple small invalid areas.
I would assume that, as minimizing drawing was important on the Mac and on X when those environments were originally written, there are equivalent mechanisms for maintaining an update region.
听起来您需要的是要渲染到屏幕上的每个形状的边界框。 请记住,多边形的边界框可以定义为“左下角”(最小点)和“右上角”(最大点)。 即,最小点的 x 分量定义为多边形中每个点的所有 x 分量中的最小值。 对 y 分量(在 2D 的情况下)和边界框的最大点使用相同的方法。
如果每个多边形有一个边界框(也称为“脏矩形”)就足够了,那么就完成了。 如果您需要整体复合边界框,则适用相同的算法,只不过您可以只用最小点和最大点填充单个框。
现在,如果您在 Java 中完成所有这些操作,则可以直接使用
getBound2D()方法
。
It sounds like what you need is a bounding box for each shape that you're rendering to the screen. Remember that a bounding box of a polygon can be defined as a "lower left" (the minimum point) and an "upper right" (the maximum point). That is, the x-component of the minimum point is defined as the minimum of all the x-components of each point in a polygon. Use the same methodology for the y-component (in the case of 2D) and the maximal point of the bounding box.
If it's sufficient to have a bounding box (aka "dirty rectangle") per polygon, you're done. If you need an overall composite bounding box, the same algorithm applies, except you can just populate a single box with minimal and maximal points.
Now, if you're doing all this in Java, you can get your bounding box for an
Area
(which you can construct from anyShape
) directly by using thegetBound2D()
method.您使用什么语言? 在 Python 中,Pygame 可以为你做到这一点。 使用 RenderUpdates Group 和一些具有图像和矩形属性的 Sprite 对象。
例如:
如果你不使用Python+Pygame,我会这样做:
move() 等方法设置“脏”
旗帜。
What language are you using? In Python, Pygame can do this for you. Use the RenderUpdates Group and some Sprite objects with image and rect attributes.
For example:
If you're not using Python+Pygame, here's what I would do:
move() etc. method sets a "dirty"
flag.
我最近刚刚编写了一个 Delphi 类来计算两个图像的差异矩形,并且对它的运行速度感到非常惊讶 - 速度足够快,可以在很短的计时器内以及在记录屏幕活动的鼠标/键盘消息之后运行。
其工作原理的逐步要点是:
将图像按矩形细分为逻辑 12x12。
循环遍历每个像素,如果存在差异,那么我告诉子矩形该像素属于哪个像素,其中一个像素存在差异,以及差异在哪里。
每个子矩形都会记住它自己的最左、最上、最右和最下差异的坐标。
找到所有差异后,我会遍历所有有差异的子矩形,如果它们彼此相邻,则将它们形成更大的矩形,并使用最左边、最顶部、最右边以及这些子矩形最底部的差异,以形成我使用的实际差异矩形。
这似乎对我来说效果很好。 如果您尚未实施自己的解决方案,请告诉我,如果您愿意,我会通过电子邮件将我的代码发送给您。 另外,到目前为止,我是 StackOverflow 的新用户,所以如果您喜欢我的回答,请投票。 :)
I just recently wrote a Delphi class to calculate the difference rectangles of two images and was quite suprised by how fast it ran - fast enough to run in a short timer and after mouse/keyboard messages for recording screen activity.
The step by step gist of how it works is by:
Sub-dividing the image into logical 12x12 by rectangles.
Looping through each pixel and if there's a difference then I tell the sub-rectangle which the pixel belongs to that there's a difference in one of it's pixels and where.
Each sub-rectangle remembers the co-ordinates of it's own left-most, top-most, right-most and bottom-most difference.
Once all the differences have been found, I loop through all the sub-rectangles that have differences and form bigger rectangles out of them if they are next to each other and use the left-most, top-most, right-most and bottom-most differences of those sub-rectangles to make actual difference rectangles I use.
This seems to work quite well for me. If you haven't already implemented your own solution, let me know and I'll email you my code if you like. Also as of now, I'm a new user of StackOverflow so if you appreciate my answer then please vote it up. :)
查看 R-tree 和 四叉树 数据结构。
Look into R-tree and quadtree data structures.