Pipeline de renderizado del motor: haciendo sombreados genéricos

Estoy tratando de hacer un motor de juego 2D utilizando OpenGL ES 2.0 (iOS por ahora). He escrito la capa de aplicación en Objective C y un RendererGLES20 independiente en C ++. Ninguna llamada específica a GL se realiza fuera del renderizador. Está funcionando perfectamente.

Pero tengo algunos problemas de diseño cuando uso sombreadores. Cada sombreador tiene sus propios atributos y uniformes únicos que deben establecerse justo antes de la llamada al cuadro principal (glDrawArrays en este caso). Por ejemplo, para dibujar alguna geometría haría:

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(.......);
}

Como puedes ver este código es extremadamente rígido. Si tuviera que usar otro sombreador, digamos efecto de onda, necesitaría pasar uniformes extra, atributos de vértice, etc. En otras palabras, tendría que cambiar el código fuente de RendererGLES20 solo para incorporar el nuevo sombreador.

¿Hay alguna manera de hacer que el objeto shader sea totalmente genérico? Me gusta ¿Qué pasa si solo quiero cambiar el objeto de sombreado y no preocuparme por la compilación de la fuente del juego? ¿Alguna forma de hacer que el renderizador sea agnóstico de uniformes y atributos, etc.? A pesar de que necesitamos pasar datos a los uniformes, ¿cuál es el mejor lugar para hacerlo? Modelo de clase? ¿La clase modelo es consciente de los uniformes y atributos específicos del sombreador?

A continuación se muestra la clase de actor:

class Actor : public ISceneNode
{
    ModelController * model;
    AIController * AI;
};

Clase de controlador de modelo: clase ModelController {class IShader * shader; int textureId; tinte vec4; flotador alfa; struct Vertex * vertexArray; };

La clase Shader solo contiene el objeto shader, compilando y enlazando sub-rutinas, etc.

En la clase de Game Logic estoy realmente renderizando el objeto:

void GameLogic::update(float dt)
{
    IRenderer * renderer = g_application->GetRenderer();

    Actor * a = GetActor(id);
    renderer->render(a->model);
}

Tenga en cuenta que a pesar de que Actor extiende ISceneNode, todavía no he comenzado a implementar SceneGraph. Lo haré tan pronto como resuelva este problema.

¿Alguna idea de cómo mejorar esto? ¿Patrones de diseño relacionados, etc.?

Respuestas a la pregunta(4)

Su respuesta a la pregunta