延迟渲染引擎的场景图


10

作为学习练习,我编写了一个延迟渲染引擎。现在,我想向该引擎添加一个场景图,但是我有点困惑如何做到这一点。

在普通的(前向渲染引擎)上,我只将所有项目(全部实现IDrawable和IUpdateAble)添加到场景图中,而不是先遍历场景图宽度并在任何地方调用Draw()。

但是,在延迟渲染引擎中,我必须分开进行绘图调用。首先,我必须先绘制几何图形,然后绘制阴影投射器,然后绘制灯光(所有灯光都绘制到不同的渲染目标),然后再将它们组合在一起。因此,在这种情况下,我不能只遍历场景图并仅调用draw。我的观察方式要么是我要遍历整个场景图3次,检查必须绘制哪种对象,要么必须创建3个以某种方式相互连接的独立场景图。这两个似乎都是较差的解决方案,我想使场景对象更透明。

我想到的另一种解决方案是像往常一样通过场景图,然后将项目添加到3个单独的列表中,分离几何图形,阴影投射器和灯光,然后迭代这些列表以绘制正确的内容,这更好吗?明智的每帧重新填充3个列表?

Answers:


6

我在C ++项目中使用的一种方法是,场景图(具有空间索引)根据当前的视锥视场填充点击的“可见” std :: vector。该可见列表由场景图管理,因此仅在摄像机移动时重新计算-图形中的移动对象在此列表中移动,并使用逻辑删除和未排序的更改列表(根据需要进行分类和合并)。

可见项列表首先按着色器ID排序,并且在每种类型中按与相机的距离排序。着色器ID的分配方式是:首先对地形进行排序,然后对建筑物进行排序,然后对建筑物进行排序,然后对射弹进行排序,然后对粒子进行排序,依此类推-这就是RTS。一些模型具有多个着色器,但是它们仅宣传其主要着色器。当要求它们绘制时,那些需要使用其他着色器绘制的位也将其自身添加到下一遍单链表中。

这样一来,绘图就通过可见数组,而在这一遍中,创建了要重新访问的那些项目的链接列表,然后又绘制了第二遍,以此类推。

前后绘制以及不透明然后透明是可以使一切保持理智的状态。

也许这并没有使着色器更改等的次数减到最少,但是它相当可行且易于实现。

我不知道XNA,它是否适用以及恐怕要创建多少这种低级的东西。然而,了解退伍军人对C ++ RTS的这种方法的看法将是最有趣的。


嗨,威尔,我真的很喜欢这个答案,特别是因为它与我到目前为止所想到的完全不同。您的方法似乎非常理智,尤其是在考虑半透明对象时(到目前为止,我基本上都避免使用此方法)。从场景图构建一个(链接的)列表以供对象访问似乎是一个好主意。是的,在XNA中,我们也必须做所有这些低级工作:)。
罗伊(Roy T.)

3

我的建议是按照您的特定要求量身定制的两步法,类似于您自己描述的方法。对于每个渲染步骤,您需要一个场景图和一个“渲染集合”,以您的阴影,几何形状,灯光为例(也许第四个是透明对象?)

场景图可以基于任何类型的关系,但我个人的偏好将基于空间关系,其中每个节点可以包含其他节点以促进快速剔除。

渲染集合可以是为特定步骤定制的任何类型的数据结构。例如,阴影集合可以是按深度排序的列表或树,以最大化早期z抑制。可以按着色器用法对几何图形集合进行排序,以最大程度地减少着色器(状态)的变化。灯光集合可以是按灯光距离,大小或它们的组合排序的列表或树,因此如果性能存在问题,则可以将灯光渲染限制为仅最有效的灯光。

无论选择哪种数据结构,请确保插入操作都是快速的,并确保它使用池化和其他技术来消除数据的任何分配/破坏,因为您将在每一帧清除并填充这些列表。

现在将它们捆绑在一起很容易。只需遍历场景图并将每个项目添加到相关的渲染集合即可。如果您的数据结构根据需求自动对新条目进行排序/结构化,则将很有帮助。完成后,按要求的顺序浏览渲染集合并进行渲染。

由于您的数据结构具有快速插入且不会产生垃圾的功能,因此,正如您提到的,重新填充列表不会受到任何惩罚。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.