Scene Management ---Node Update
作者:clayman
仅供个人学习使用,请勿转载,勿用于任何商业用途。
很多人都见过这张图吧,这是David Eberly介绍scene node updating时的插图,其中灰色表示发生过改变的节点。Eberly大师告诉我们,理想的更新方式,应该从a,b开始,但最关键的部分: 如何找到最靠近根节点的变化节点,却没有讨论。本文在这里尝试补上这一部分讨论,和以往的文章一样,只是讨论,并不一定能作为实际解决方案;)
整个scene update的代价等于更新每个节点的代价加上遍历相关节点的代价。假设每个节点更新的代价已经固定,那么唯一能做的就是减少遍历次数,避免访问不必更新的节点。用以下公式表示整个更新代价:
cost = treeWalk + nodeUpdate + findingUpdateRoot;
显然,最差情况为:
cost = fullTreeWalk + nodeUpdate;
因此,要保证treeWalk + findingUpdateRoot <= fullTreeWalk,否则所谓的优化就没意义了。这个不等式有可能成立吗?不一定,当大部分或者所有节点都需要更新时,treeWalk + findingUpdateRoot很可能大于fullTreeWalk。如果你的游戏属于这种情况,那么不用费力找潜在的a,b节点了,直接遍历整个树吧。另一方面,当仅有少部分节点需要更新时,寻找最靠近根节点的变化节点就很有意义了。我们把这种方法称为bucketed update,如其名称所示,发生改变的节点把自己放到bucket中, 更新时,检查bucket中是否有节点,如果有则更新节点及其子节点。这里很重要的一个问题是,当a,b,c,d都在bucket中时,必须找出最靠近根的那个。最简单的方法: 不同高度的节点放到不同bucket中,从最底层bucket开始更新。你可能会说scene graph的树高为n的话,岂不是需要n个bucket组? 确实如此,好在对一般游戏来说,scene graph的结构通常很平(flat),不会太深,有些引擎更是把高度n限制在一个非常小的值,比如3,因此这种方法在很大程度上还是相当可行。
sceneNode.setXXX()
{
...........
if(!requireUpdate)
requireUpdate=true;
AddToBucket(treeLevel,this)
}
//updating phase
foreach bucket in bucketGroup
foreach node in bucket
if(node.requireUpdate)
node.Update;