看了文档上关于当前脏矩形的一些说明,也尝试进行使用了一下。发现有些建议希望提一下。
--------------------------------------来自Creator文档--------------------------------------------------------
脏矩形的开关和调试
在 Creator 中,脏矩形默认处于开启状态。开启和关闭脏矩形的API是
//enable dirty region
cc.renderer.enableDirtyRegion(true);
//disable dirty region
cc.renderer.enableDirtyRegion(false);
//check dirty region enable state
var isEnabled = cc.renderer.isDirtyRegionEnabled();
当屏幕上有大量的物体都在运动时,使用脏矩形的效率会更低,因此引擎提供Threshold机制, 在大量物体运动的情况下,渲染自动切换到原始渲染逻辑。默认情况下,threshold是10。
//set dirty region threshold
cc.renderer.setDirtyRegionCountThreshold(threshold);
------------------------过往的设计方案--------------------------------------------------------------------------------------------
这里是我对文档的理解和测试:
这里的阈值是10,我猜想应该是记录发生了移动的物体的数目,文档的意思是,当超过比10更大的某个数字时,这个脏矩形的收集工作已经非常耗时,已经不能优化,甚至降低原有的性能。
我测试了一下,确实是这样,我原有项目的DrawCall是600左右,当我把这个阈值调整到500,画面顿时变得非常卡顿。
脏矩形可以带来渲染效率上的提高,但是一定要谨慎它追踪计算逻辑的开销。
关于脏矩形,我以前的方案:
最早期做J2me手机游戏时,我曾经做过一套脏矩形的方案,这个方案源自于卡马克卷轴算法,所以先说说这个卡马克卷轴算法。
对于连续平铺的方格地图来说,整个世界是由16x16、24x24或者32x32这种方格连续绘制而成的的,当角色移动时,方格整体在世界中发生移动,比如一个一个屏幕的尺寸是256x256,当采用16x16的方格图片填充时,那么横向和纵向需要至少16行x16列,当发生卷动时,由于不是恰好处于边缘,显示要多出1个,也就是17x17=289次绘图,就相当于现在所说的DrawCall(实际上与真正的DrawCall差别很大),但是从最基本的理解来说,绘制次数X*单次绘制时间就是绘制的性能消耗。在256x256的非常小屏幕上都需要289绘制,如果换做更大的屏幕,显然更不能忍受。
于是出现了卡马克卷轴算法,原理是使用一张全屏缓存,在发生卷动时,先更新这个缓存,然后向屏幕绘制的实际上是这个缓存,更新缓存时,由于卷动世界时,新出现的地图单元只发生在横向或者纵向的行走方向,所以,只是更新这一行或者一列到缓存中,也就是说,性能消耗基本上可以认为是,在人物行动时,降低为原先的1/列数或者行数,在不卷动时,降低为原先的1/列数x行数,最简单来说,当人物没有行走,世界地图没发生变化时,缓存无需更新,直接绘制缓存到屏幕就可以。
我觉得卡马克卷轴算法的核心就是,统计哪些内容发生过变化,只更新那些变化。所以,后来我基于这个算法进行扩展,制作了自己的一个算法,也就是首先仍然使用地图卷动的逻辑去更新缓存。再增加一张全屏透明缓存,用作世界中的动画缓存,也就是,每帧内追踪那些发生过变化的动画,找出他们的污染区域,然后清空那些区域,让那些区域的动画重绘,由于要考虑到边缘计算,移动时的线型变化区域,以及动画之间的遮挡关系,所以算法变得异常复杂,有些时候也就发现了,追踪算法的成本已经超越了渲染性能的节约。与现在Creator脏矩形应该是一致的。
于是,我在想这个问题的简化方法,如何避开那些复杂的变化追踪算法。
------------------------建议的设计方案--------------------------------------------------------------------------------------------
后来,我想这个问题应该通过手动配置去解决,也就是说,画面内容有的部分变化剧烈,有的部分基本无变化,或者在玩家有输入时才发生变化。举个最简单的例子,一串长长的菜单列表,里面有很多子元素,但是菜单列表大部分时候是不会变化的,而只有玩家输入才会发生变化。因此我们可以对这个列表做单独的脏矩形优化。而列表的卷动过程与方格地图很类似,因此用卡马克卷轴算法来更新列表是很高效的。而有些菜单内容的更新并没有规律可言,那么我们可以在其频繁变化时(比如一个对话框的整体颜色在渐渐淡入),关闭缓存,而当其不需要变化时,重新开启缓存,但是这个缓存依然是只针对于这个整体对话框的。那么如果不是对话框自己变化,而只是相对于屏幕发生变化时,也不需要更新这个缓存。而对于变化更频繁的内容,比如子弹横飞,不断跑动的人物,这些就放弃做脏矩形处理。
因此,这里通过手动分类和配置,也就没有了原先复杂而性能消耗巨大的脏矩形搜索的过程,会极大提升绘制效率。