草庐IT

QGraphicsView图形视图框架使用(五)渲染优化

码农飞飞 2023-11-20 原文

文章目录


当视图中的复杂图元比较多的时候,图形框架应用的性能会下降很多。这时候,我们就需要对默认的渲染策略进行调整从而提升用户体验。图形视图框架的优化方向主要分为以下几种:
1.调整图元的二叉树结构
2.对图元的绘制函数进行缓存
3.优化视图渲染
4.采用OpenGL进行渲染

下面分别介绍一下几种优化策略

调整图元二叉树

在图元视图框架内部,各个Item的位置采用二叉树数据结构来进行存储。这种数据结构的优势是是查询比较快,也就是通过items()或者itemAt()来定位查找图元的时候会比较快,这对于图元的碰撞检测也是很有帮助的。但是这种数据结构也有问题,就是如果移动了一个图元,那么框架就需要更新整个二叉树,如果图元比较多的时候这个更新操作是很耗时的。

如果图元比较多,且你不需要图元的位置信息二叉树的时候,可以通过下面的函数来禁用索引信息,从而提升视图的渲染性能。

scene()->setItemIndexMethod(QGraphicsScene::NoIndex);

没有位置信息二叉树的时候,调用items()或者itemAt()查找元素的时候,就需要遍历所有的元素进行查找,如果图元比较多的话,查找也会引发性能问题。所以这个配置要根据自己项目的具体场景选择是否开启。

如果无法完全放弃二叉树索引,我们也可以通过setBspTreeDepth()修改二叉树的深度来优化性能,不过这个参数设置也要和具体场景结合起来。

绘制缓存

如果某个图元的绘制函数是很耗时的,我们可以开启该图元的缓存模式来进行优化,默认的情况,缓存模式是被关闭的。缓存模式开启的函数如下:

//@1缓存模式
//@2逻辑换存的大小
void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize = QSize())

常见的缓存模式如下表所示:

模式说明
NoCache默认缓存模式被禁用,每次图元需要重绘的时候 QGraphicsItem::paint()函数都会被调用。
ItemCoordinateCache给图元指定一个QSize()大小的缓存,缓存里面的图像可以用来进行后续的绘制和位移变换。如果想调整缓存图像的质量和分辨率,可以通过调用setCacheMode()分配一块更大的空间。
DeviceCoordinateCache绘制设备级别的缓存优化,主要适用于那些可以移动,但不会发生位移变化(旋转、缩放、剪切)的图元。如果图元发生了位移变化,那么缓存会自动更新。和ItemCoordinateCache不同 DeviceCoordinateCache不需要指定缓存空间大小,它始终以最高质量进行渲染。

视图优化

默认的情况下QGraphicsView在绘制背景和图元的时候会保护pianter的绘制状态。如果我们通过setPen()或者setBrush()修改了绘制状态,该状态会被一直保持,如果图元比较多的时候该绘制状态保持操作是比较耗时的,View中每个图元都需要执行对应的操作。我们可以通过下面的配置来禁用这种配置:

setOptimizationFlag(DontSavePainterState, true); 

在禁用了自动绘制状态保持之后,我们就需要负责对painter()的状态进行控制了。禁用了自动绘制状态保持之后,标准控件也会影响painter()的状态。因此,如果同时使用标准图元和自定义图元,保持默认行为或设置 DontSavePainterState之后,在每次paint()绘制完毕的时候都需要将画笔和画刷恢复默认值。

默认情况下如果图元开启了抗锯齿操作,渲染的时候由于差值的影响很可能渲染的范围就超出了图元的边界,这就导致了渲染范围增大,从而影响了渲染性能。我们可以通过下面的配置来禁用边界以外的渲染行为:

setOptimizationFlag(DontAdjustForAntialiasing, true); 

启用了该配置之后,抗锯齿渲染便不再渲染边界以外的图形,从而提升渲染性能。这个配置的副作用就是,以抗锯齿的模式绘制的图元在移动时候,会在Scene上留下绘制轨迹。

除了上面的配置之外,还可以通过指定QGraphicsView的渲染更新范围来优化图形框架的性能。对应的配置接口如下:

setViewportUpdateMode(ViewportUpdateMode mode);

更新模式分为五种分别如下:

模式说明
FullViewportUpdate更新整个viewport中的图元
MinimalViewportUpdate只更新需要更新的图元
SmartViewportUpdateQGraphicsView会寻找最优的更新模式
BoundingRectViewportUpdateQt检测需要重绘的区域,然后在viewport上寻找一个矩形范围,将所有需要重绘的区域包含进去,对找到的矩形范围进行更新。
NoViewportUpdate当场景改变时, QGraphicsView永远不会更新它的视口,用户控制所有更新。

如果图元比较多,找需要更新的图元的时间大于更新整个viewport更新的时间,我们可以选择FullViewportUpdate模式,相反如果找需要更新的图元的时间小于更新整个viewport的时间,我们可以选择MinimalViewportUpdate模式。

OpenGL渲染优化

QGraphicsView默认的viewport是基于QWidget的性能受限制,我们可以通过使用
OpenGL widget替代QWidget来提升渲染性能。对应的配置如下:

QGraphicsView view; 
view.setViewport(new QOpenGLWidget());

通常配置OpenGL替代QWidget能提升渲染性能,但Qt的图形视图框架并不是针对GPU设计的,并不能充分发挥GPU的性能。如果想使用可以利用GPU加速的图形框架,可以参考Qt Quick中对应的模块。

上面提到的优化策略,都是有局限性的,我们在实际使用的时候,要考虑自己的业务场景和软硬件性能,不能盲目套用,要不有可能对性能产生负面影响。最好能在优化前后对对应的指标进行测试,确保优化策略确实提升了性能。

有关QGraphicsView图形视图框架使用(五)渲染优化的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐