Graphics 脏矩形

Graphics 脏矩形,graphics,framebuffer,bounding-box,dirtyrectangle,Graphics,Framebuffer,Bounding Box,Dirtyrectangle,在哪里可以找到实现算法的参考资料,该算法用于计算“脏矩形”,以最小化帧缓冲区更新?一种显示模型,允许任意编辑并计算更新显示所需的最小“位blit”操作集。要构建包含所有需要重新绘制的区域的最小矩形: 从一个空白区域开始(可能是一个设置为0,0,0,0的矩形-可以检测为“无需更新”) 对于添加的每个脏区域: 使新区域正常化(即确保左侧小于右侧,顶部小于底部) 如果脏矩形当前为空,请将其设置为提供的区域 否则,将脏矩形的左坐标和上坐标设置为{dirty,new}中的最小坐标,将右坐标和下坐标设

在哪里可以找到实现算法的参考资料,该算法用于计算“脏矩形”,以最小化帧缓冲区更新?一种显示模型,允许任意编辑并计算更新显示所需的最小“位blit”操作集。

要构建包含所有需要重新绘制的区域的最小矩形:

  • 从一个空白区域开始(可能是一个设置为0,0,0,0的矩形-可以检测为“无需更新”)
对于添加的每个脏区域:

  • 使新区域正常化(即确保左侧小于右侧,顶部小于底部)
  • 如果脏矩形当前为空,请将其设置为提供的区域
  • 否则,将脏矩形的左坐标和上坐标设置为{dirty,new}中的最小坐标,将右坐标和下坐标设置为{dirty,new}中的最大坐标
Windows至少维护了一个更新区域,其中包含通知它的更改,以及由于窗口被遮挡和显示而需要进行的任何重新绘制。区域是由许多可能不连续的矩形、多边形和椭圆组成的对象。您可以通过调用InvalidateBu立来告诉Windows需要重新绘制的屏幕部分-对于更复杂的区域,还有一个InvalidateRgn函数。如果您选择在下一个WM_PAINT消息到达之前进行一些绘制,并且希望将其从脏区中排除,则有validateBu立和ValidateRgn函数

使用BeginPaint开始绘制时,将提供一个PAINTSTRUCT,Windows将在其中填充有关需要绘制的内容的信息。其中一个成员是包含无效区域的最小矩形。如果要在存在多个小无效区域时最小化图形,则可以使用GetUpdateRgn获取区域本身(必须在BeginPaint之前调用此函数,因为BeginPaint会将整个窗口标记为有效)


我认为,当最初编写这些环境时,在Mac和X上最小化绘图是很重要的,因此有相同的机制来维护更新区域。

您使用的是什么语言?在Python中,Pygame可以为您做到这一点。使用“渲染更新”组和一些具有图像和矩形属性的精灵对象

例如:

#!/usr/bin/env python
import pygame

class DirtyRectSprite(pygame.sprite.Sprite):
    """Sprite with image and rect attributes."""
    def __init__(self, some_image, *groups):
        pygame.sprite.Sprite.__init__(self, *groups)
        self.image = pygame.image.load(some_image).convert()
        self.rect = self.image.get_rect()
    def update(self):
        pass #do something here

def main():
    screen = pygame.display.set_mode((640, 480))
    background = pygame.image.load(open("some_bg_image.png")).convert()
    render_group = pygame.sprite.RenderUpdates()
    dirty_rect_sprite = DirtyRectSprite(open("some_image.png"))
    render_group.add(dirty_rect_sprite)

    while True:
        dirty_rect_sprite.update()
        render_group.clear(screen, background)
        pygame.display.update(render_group.draw(screen))
如果您没有使用Python+Pygame,我会这样做:

  • 创建一个名为update()的精灵类, move()etc.方法设置“dirty” 旗帜
  • 为每个精灵保留一个矩形
  • 如果您的API支持更新矩形列表,请在精灵脏的矩形列表上使用该列表。在SDL中,这是SDL_updates
  • 如果您的API不支持更新rect列表(我从来没有机会使用SDL以外的任何东西,所以我不知道),那么测试一下,看看使用大rect多次或一次调用blit函数是否更快。我怀疑任何API使用一个大rect都会更快,但再一次,除了SDL之外,我还没有使用任何东西

听起来您需要的是一个边界框,用于渲染到屏幕上的每个形状。请记住,多边形的边界框可以定义为“左下”(最小点)和“右上”(最大点)。也就是说,最小点的x分量定义为多边形中每个点的所有x分量的最小值。对y分量(在2D情况下)和边界框的最大点使用相同的方法

如果每个多边形有一个边界框(也称为“脏矩形”)就足够了,那么就完成了。如果您需要一个整体复合边界框,同样的算法也适用,只是您可以用最小点和最大点填充单个框


现在,如果您在Java中执行所有这些操作,您可以获得
区域的边界框(您可以从任何
形状构建该边界框)通过直接使用.

我最近刚刚编写了一个Delphi类来计算两幅图像的不同矩形,它的运行速度之快让我感到非常惊讶——它的运行速度足以在一个短计时器内以及在鼠标/键盘消息之后记录屏幕活动

其工作原理的分步要点如下:

  • 通过矩形将图像细分为逻辑12x12

  • 循环遍历每个像素,如果有差异,我会告诉子矩形,像素属于哪个,其中一个像素有差异,在哪里

  • 每个子矩形都会记住其自身最左侧、最顶部、最右侧和最底部差异的坐标

  • 一旦发现了所有的差异,我循环遍历所有有差异的子矩形,如果它们彼此相邻,则形成更大的矩形,并使用这些子矩形中最左边、最上面、最右边和最下面的差异来产生我使用的实际差异矩形


  • 这对我来说似乎很有效。如果您还没有实现自己的解决方案,请告诉我,如果您愿意,我将通过电子邮件向您发送我的代码。另外,到目前为止,我是StackOverflow的新用户,因此如果您欣赏我的回答,请投赞成票。:)

    查看和数据结构。

    Vexi是这方面的参考实现。该类是(Apache许可证),并作为生产系统的一部分使用,即经过彻底测试,并且有很好的注释

    需要注意的是,当前的类描述有点不准确,“一种通用数据结构,用于保存需要重新绘制的矩形区域列表,具有智能合并功能。”实际上,它当前不进行合并。因此,您可以考虑这是一个基本的DRITELIST实现,因为它只交叉DRITER()请求,以确保没有重叠的脏区域。 此实现的一个细微差别是,区域存储在int数组中,而不是使用Rect或其他类似的区域对象
    public class DirtyList {
    
        /** The dirty regions (each one is an int[4]). */
        private int[] dirties = new int[10 * 4]; // gets grown dynamically
    
        /** The number of dirty regions */
        private int numdirties = 0;
    
        ...
    
        /** 
         *  Pseudonym for running a new dirty() request against the entire dirties list
         *  (x,y) represents the topleft coordinate and (w,h) the bottomright coordinate 
         */
        public final void dirty(int x, int y, int w, int h) { dirty(x, y, w, h, 0); }
    
        /** 
         *  Add a new rectangle to the dirty list; returns false if the
         *  region fell completely within an existing rectangle or set of
         *  rectangles (i.e. did not expand the dirty area)
         */
        private void dirty(int x, int y, int w, int h, int ind) {
            int _n;
            if (w<x || h<y) {
                return;
            }
            for (int i=ind; i<numdirties; i++) {
                _n = 4*i;
                // invalid dirties are marked with x=-1
                if (dirties[_n]<0) {
                    continue;
                }
    
                int _x = dirties[_n];
                int _y = dirties[_n+1];
                int _w = dirties[_n+2];
                int _h = dirties[_n+3];
    
                if (x >= _w || y >= _h || w <= _x || h <= _y) {
                    // new region is outside of existing region
                    continue;
                }
    
                if (x < _x) {
                    // new region starts to the left of existing region
    
                    if (y < _y) {
                        // new region overlaps at least the top-left corner of existing region
    
                        if (w > _w) {
                            // new region overlaps entire width of existing region
    
                            if (h > _h) {
                                // new region contains existing region
                                dirties[_n] = -1;
                                continue;
                            }// else {
                            // new region contains top of existing region
                            dirties[_n+1] = h;
                            continue;
    
                        } else {
                            // new region overlaps to the left of existing region
    
                            if (h > _h) {
                                // new region contains left of existing region
                                dirties[_n] = w;
                                continue;
                            }// else {
                            // new region overlaps top-left corner of existing region
                            dirty(x, y, w, _y, i+1);
                            dirty(x, _y, _x, h, i+1);
                            return;
    
                        }
                    } else {
                        // new region starts within the vertical range of existing region
    
                        if (w > _w) {
                            // new region horizontally overlaps existing region
    
                            if (h > _h) {
                                // new region contains bottom of existing region
                                dirties[_n+3] = y;
                                continue;
                            }// else {
                            // new region overlaps to the left and right of existing region
                            dirty(x, y, _x, h, i+1);
                            dirty(_w, y, w, h, i+1);
                            return;
    
                        } else {
                            // new region ends within horizontal range of existing region
    
                            if (h > _h) {
                                // new region overlaps bottom-left corner of existing region
                                dirty(x, y, _x, h, i+1);
                                dirty(_x, _h, w, h, i+1);
                                return;
                            }// else {
                            // existing region contains right part of new region
                            w = _x;
                            continue;
                        }
                    }
                } else {
                    // new region starts within the horizontal range of existing region
    
                    if (y < _y) {
                        // new region starts above existing region
    
                        if (w > _w) {
                            // new region overlaps at least top-right of existing region
    
                            if (h > _h) {
                                // new region contains the right of existing region
                                dirties[_n+2] = x;
                                continue;
                            }// else {
                            // new region overlaps top-right of existing region
                            dirty(x, y, w, _y, i+1);
                            dirty(_w, _y, w, h, i+1);
                            return;
    
                        } else {
                            // new region is horizontally contained within existing region
    
                            if (h > _h) {
                                // new region overlaps to the above and below of existing region
                                dirty(x, y, w, _y, i+1);
                                dirty(x, _h, w, h, i+1);
                                return;
                            }// else {
                            // existing region contains bottom part of new region
                            h = _y;
                            continue;
                        }
                    } else {
                        // new region starts within existing region
    
                        if (w > _w) {
                            // new region overlaps at least to the right of existing region
    
                            if (h > _h) {
                                // new region overlaps bottom-right corner of existing region
                                dirty(x, _h, w, h, i+1);
                                dirty(_w, y, w, _h, i+1);
                                return;
                            }// else {
                            // existing region contains left part of new region
                            x = _w;
                            continue;
                        } else {
                            // new region is horizontally contained within existing region
    
                            if (h > _h) {
                                // existing region contains top part of new region
                                y = _h;
                                continue;
                            }// else {
                            // new region is contained within existing region
                            return;
                        }
                    }
                }
            }
    
            // region is valid; store it for rendering
            _n = numdirties*4;
            size(_n);
            dirties[_n] = x;
            dirties[_n+1] = y;
            dirties[_n+2] = w;
            dirties[_n+3] = h;
            numdirties++;
        }
    
        ...
    }