Próbuję stworzyć silnik do gier 2D za pomocą OpenGL ES 2.0 (na razie iOS). Napisałem warstwę aplikacji w celu C i osobny samodzielny RendererGLES20 w C ++. Poza rendererem nie jest wykonywane żadne specyficzne wywołanie GL. Działa idealnie.
Ale mam pewne problemy z projektowaniem podczas korzystania z shaderów. Każdy moduł cieniujący ma swoje unikalne atrybuty i mundury, które należy ustawić tuż przed głównym wywołaniem losowania (w tym przypadku glDrawArrays). Na przykład, aby narysować geometrię, zrobiłbym:
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(.......);
}
Jak widać, ten kod jest wyjątkowo sztywny. Gdybym miał użyć innego modułu cieniującego, powiedzmy efekt falowania, musiałbym przekazać dodatkowe mundury, atrybuty wierzchołków itp. Innymi słowy, musiałbym zmienić kod źródłowy renderowania RendererGLES20, aby włączyć nowy moduł cieniujący.
Czy istnieje sposób, aby obiekt modułu cieniującego był całkowicie ogólny? Co jeśli chcę po prostu zmienić obiekt modułu cieniującego i nie martwić się ponowną kompilacją źródła gry? Jakikolwiek sposób na uczynienie renderera agnostycznym dla mundurów i atrybutów itp.? Nawet jeśli musimy przekazywać dane do mundurów, jakie jest najlepsze miejsce do tego? Klasa modelowa? Czy klasa modelu zna mundury i atrybuty modułu cieniującego?
Następujące pokazy Klasa aktora:
class Actor : public ISceneNode
{
ModelController * model;
AIController * AI;
};
Model kontrolera klasy: klasa ModelController {klasa IShader * moduł cieniujący; int textureId; odcień vec4; pływak alfa; struct Vertex * vertexArray; };
Klasa Shader zawiera tylko obiekt modułu cieniującego, kompilację i łączenie podprogramów itp.
W klasie Game Logic faktycznie renderuję obiekt:
void GameLogic::update(float dt)
{
IRenderer * renderer = g_application->GetRenderer();
Actor * a = GetActor(id);
renderer->render(a->model);
}
Pamiętaj, że chociaż Actor rozszerza ISceneNode, nie rozpocząłem jeszcze wdrażania SceneGraph. Zrobię to, jak tylko rozwiążę ten problem.
Wszelkie pomysły, jak to poprawić? Powiązane wzorce projektowe itp.?
Dziękuję za przeczytanie pytania.