呈现基于着色器的游戏

问题描述:

构建游戏引擎的时候在我的课要这个样子我一直在打这个问题OO架构:呈现基于着色器的游戏

interface Entity { 
    draw(); 
} 

class World { 
    draw() { 
    for (e in entities) 
     e.draw(); 
    } 
} 

这只是伪代码,以显示绘图大致是如何发生的。每个实体子类都实现其自己的图形。世界循环遍历所有的实体,并没有特定的顺序,并告诉他们一个接一个地画自己。

但是使用基于shader的图形,这往往是非常低效甚至不可行的。每个实体类型可能都会有自己的着色器程序。为了最小化程序变化,每种特定类型的所有实体需要一起绘制。简单类型的实体(如粒子)也可能希望以其他方式聚合其绘图,例如共享一个大顶点数组。并且它会因混合而变得很毛茸茸,并且这种情况下某些实体类型需要在某些时候相对于其他实体进行渲染,或者甚至需要多次进行不同的渲染。

我通常最终得到的是每个实体类的某种渲染器单例,它保存所有实例的列表并一次绘制它们。这并不坏,因为它将绘图与游戏逻辑分开。但渲染器需要找出要绘制的实体的哪个子集,并且它需要访问图形管道的多个不同部分。这是我的对象模型容易变得混乱的地方,有很多重复的代码,紧密耦合以及其他不好的事情。

所以我的问题是:什么是这种高效,多功能和模块化的游戏绘图的好架构?

+0

事实上,你将它与其他事物分离开来很好,它听起来像是凌乱,因为它......好...... _messy_。 **必要**混乱是不幸的,但仍然是必要的。但我怀疑你会认为这是一个答案... –

这不是一个容易回答的问题,因为有很多方法可以解决问题。一个好主意是研究一些游戏/渲染引擎,看看这是如何处理的。由于它有良好的文档和开放源代码,一个好的起点将是Ogre

据我所知,它通过内置的材质脚本将顶点数据从材质组件(着色器)中分离出来。渲染器本身知道以什么顺序以及使用什么着色器(及其传递)来绘制网格。

我知道这个答案有点含糊,但我希望我能给你一个有用的提示。

使用两个阶段的方法:首先遍历所有实体,但不是绘图让他们将引用自己插入到(图)批处理列表中。然后通过OpenGL状态和着色器使用对列表进行排序;在每个状态转换中对插入状态转换器对象排序后。

最后遍历执行列表中引用的每个对象的绘图例程的列表。

+0

如果你有不同的引擎? OpenGL,DirectX? – GorillaApe

+0

@Parhs:OpenGL和DirectX都不是引擎。他们是API。第一个叫做“帧设置”的阶段通常由渲染器代码部分完成,该渲染器代码与API对话,部分由场景管理代码完成。例如,平截头体剔除是场景代码更适合的,纹理和着色器状态应该由渲染器代码进行排序。你也不必一次完成所有事情。首先遍历(在场景代码中)遍历所有边界框以进行截锥体剔除和按深度排序是完全正确的。然后将这个列表交给渲染器进一步细化。 – datenwolf

+0

感谢您的回复。然而我的问题在这里。你说“执行每个对象的绘图程序”。如果你想使用多个API(direct2d,opengl等)怎么办?我的意思是每个对象中的draw()都应该为所有的api实现?还是渲染器也照顾绘图呢? – GorillaApe