Pipeline de renderização do motor: fazendo shaders genéricos
Eu estou tentando fazer um motor de jogo 2D usando OpenGL ES 2.0 (iOS por enquanto). Eu escrevi Application layer no Objective C e um RendererGLES20 auto-contido separado em C ++. Nenhuma chamada específica de GL é feita fora do renderizador. Está funcionando perfeitamente.
Mas eu tenho alguns problemas de design ao usar shaders. Cada shader tem seus próprios atributos e uniformes exclusivos que precisam ser definidos antes da chamada da chamada principal (glDrawArrays, neste caso). Por exemplo, para desenhar alguma geometria, eu faria:
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 você pode ver este código é extremamente rígido. Se eu fosse usar outro sombreador, digamos ripple effect, eu precisaria passar uniformes extras, atributos de vértices, etc. Em outras palavras, eu teria que mudar o RendererGLES20 para renderizar o código fonte apenas para incorporar o novo sombreador.
Existe alguma maneira de tornar o objeto shader totalmente genérico? Como se eu apenas quisesse mudar o objeto shader e não se preocupar com a recompilação da fonte do jogo? Qualquer maneira de tornar o renderizador agnóstico de uniformes e atributos etc? Mesmo que precisemos passar dados para uniformes, qual é o melhor lugar para fazer isso? Modelo de classe? A classe do modelo está ciente dos uniformes e atributos específicos do shader?
Seguinte mostra Ator classe:
class Actor : public ISceneNode
{
ModelController * model;
AIController * AI;
};
Classe de controlador de modelo: classe ModelController {class IShader * shader; int textureId; vec4 matiz; flutuar alfa; struct Vertex * vertexArray; };
A classe Shader contém apenas o objeto shader, compilando e vinculando sub-rotinas etc.
Na classe Game Logic, estou renderizando o objeto:
void GameLogic::update(float dt)
{
IRenderer * renderer = g_application->GetRenderer();
Actor * a = GetActor(id);
renderer->render(a->model);
}
Por favor, note que mesmo que o ator estenda o ISceneNode, ainda não comecei a implementar o SceneGraph. Eu farei isso assim que resolver este problema.
Alguma idéia de como melhorar isso? Padrões de design relacionados etc?