用于在基于着色器的游戏中渲染的OO架构

时间:2011-07-05 12:58:30

标签: oop opengl graphics shader

在构建我的课程看起来像这样的游戏引擎时,我一直在遇到这个问题:

interface Entity {
  draw();
}

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

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

但是使用基于着色器的图形,这往往会非常低效甚至不可行。每个实体类型可能都有自己的着色器程序。为了最大限度地减少程序更改,需要将一起绘制每种特定类型的所有实体。简单类型的实体(如粒子)也可能希望以其他方式聚合其绘图,例如共享一个大的顶点数组。并且它通过混合变得非常毛茸茸,例如某些实体类型需要在特定时间相对于其他实体类型呈现,或者甚至在不同时间通过不同通道呈现。

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

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

2 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:1)

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

据我所知,它通过内置材质脚本将顶点数据与材质组件(着色器)分开。渲染器本身知道要以什么顺序绘制网格,以及使用什么着色器(以及它的遍历)。

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