我正在尝试使用 OpenGL ES 2.0(目前为 iOS)制作 2D 游戏引擎。我用 Objective C 编写了应用程序层,并用 C++ 编写了一个单独的自包含 RendererGLES20。在渲染器之外不进行任何 GL 特定调用。它运行良好。
但是我在使用着色器时遇到了一些设计问题。每个着色器都有自己独特的属性和制服,需要在主绘制调用之前设置(在本例中为 glDrawArrays)。例如,为了绘制一些几何图形,我会这样做:
void RendererGLES20::render(Model * model)
{
// Set a bunch of uniforms
glUniformMatrix4fv(.......);
// Enable specific attributes, can be many
glEnableVertexAttribArray(......);
// Set a bunch of vertex attribute pointers:
glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, m->pCoords);
// Now actually Draw the geometry
glDrawArrays(GL_TRIANGLES, 0, m->vertexCount);
// After drawing, disable any vertex attributes:
glDisableVertexAttribArray(.......);
}
如您所见,此代码非常严格。如果我要使用另一个着色器,比如涟漪效应,我将需要传递额外的制服、顶点属性等。换句话说,我必须更改 RendererGLES20 渲染源代码才能合并新的着色器。
有没有办法让着色器对象完全通用?比如如果我只想更改着色器对象而不担心重新编译游戏源怎么办?有什么方法可以使渲染器与制服和属性等无关?即使我们需要将数据传递给制服,最好的地方是什么?模型课?模型类是否知道着色器特定的制服和属性?
下面显示了 Actor 类:
class Actor : public ISceneNode
{
ModelController * model;
AIController * AI;
};
模型控制器类:class ModelController { class IShader * shader; int 纹理标识;vec4 色调;浮动阿尔法;结构顶点 * 顶点数组;};
着色器类只包含着色器对象、编译和链接子例程等。
在 Game Logic 类中,我实际上是在渲染对象:
void GameLogic::update(float dt)
{
IRenderer * renderer = g_application->GetRenderer();
Actor * a = GetActor(id);
renderer->render(a->model);
}
请注意,尽管 Actor 扩展了 ISceneNode,但我还没有开始实现 SceneGraph。一旦我解决了这个问题,我就会这样做。
任何想法如何改善这一点?相关的设计模式等?