Como manipular materiais em um sistema de entidade / componente

13

Minha implementação de E / C é básica, onde Entidades são apenas IDs, Componentes são dados e Sistemas agem nos Dados. No momento, estou tendo problemas com materiais de objetos e renderização em geral. Para objetos simples, eu tenho um ModelComponent, vinculado a um RenderSystem, ModelComponenttem os IDs do buffer de vértice que o sistema de renderização usa. Um simples MaterialComponentprovavelmente teria cor ou força especular, etc., mas eu queria que fosse flexível o suficiente para permitir mais de um passe de renderização e "efeitos" gerais que não são tão fáceis quanto uma variável simples no MaterialComponent.

Tentando resolver esses problemas, criei duas soluções:

1 - Componente material super-genérico

Algo assim:

struct Material : public Component
{
    ShaderData* shader;
    std::vector<std::pair<std::string, boost::any>> uniforms;
    [...]
};

e no sistema de renderização eu passava e passava os uniformes para o shader. Suponho que isso seria lento, mas rápido o suficiente para meus propósitos.

2 - Outra camada de abstração, MaterialData

Tendo uma classe para agrupar materiais específicos, que poderiam ser herdados por qualquer material especializado, a classe base teria algo parecido, void set_shader_constants(ShaderData* d)mas a implementação depende de cada classe e MaterialComponentteria um ponteiro para um objeto MaterialData.

Não tenho certeza de qual abordagem eu preferiria, mas nenhuma delas aborda o assunto de várias passagens ou outras técnicas complexas de renderização.

Alguma idéia de como fazer isso?

Luke B.
fonte

Respostas:

26

Os materiais são um conceito gráfico e pertencem ao seu renderizador. Um renderizador é uma peça de arquitetura de nível muito baixo para ser construída sobre um sistema de entidade. Os sistemas de entidades devem ser para objetos de jogo de nível superior.Nem tudo precisa ser um componente e, de fato, geralmente é uma má idéia tentar forçar tudo a entrar em um único paradigma como esse. Cria uma solução de denominador menos comum.

Consequentemente, aconselho que você adote uma abordagem diferente:

  • Um material é apenas outro tipo no seu renderizador.
  • Seu renderizador tem um tipo que representa "algo a ser desenhado na tela". Freqüentemente, eles são chamados de "instâncias de renderização" ou "renderizáveis" ou mesmo "modelos". Esse tipo tem uma referência ao material que ele usará ao desenhar e fornece uma API pública para permitir que um consumidor do renderizador defina esse material como desejar.

É essencialmente pedir para você pegar ModelComponente renomeá-lo Model, removendo a dependência da camada de entidade / componente e movendo-a para uma camada inferior de abstração, ao lado do resto do seu renderizador.

Então, você faz o seguinte:

  • Na mesma camada de abstração que seus outros componentes, você tem algum tipo de "componente de aspecto" que representa a apresentação visual de uma entidade. Este componente contém apenas uma referência a alguns renderizáveis ​​(como descrito acima), que por sua vez contém a referência a um material. O componente pode fornecer uma API para expor o renderizável (permitindo que os clientes o manipulem) ou pode envolver a API do renderizável para controlar a exposição. Isso é contigo.

Isso soluciona o problema de interdependência de componentes com o qual modelos e materiais são componentes; uma entidade deve ter um aspecto ou não, e esse aspecto deve ser capaz de codificar tudo sobre a apresentação da entidade, incluindo o material.

Isso também oferece a flexibilidade de adotar outras abordagens com o objeto material que seriam mais difíceis de fazer com esse objeto como um componente devido à falta de paridade com o restante da abstração do sistema de renderização.

Seu problema de permitir efeitos mais complexos e várias passagens é aquele que pode ser resolvido principalmente no material, expondo funções para consultar e definir constantes de shader nomeadas expostas pelo arquivo de shader do material. Isso é especialmente verdade se você usar arquivos de efeito (no D3D) que suportam várias passagens e similares. Mesmo se você não estiver usando arquivos de efeito, poderá expor a ideia de várias passagens do material, cada uma com sombreadores distintos, e permitir que a API do material forneça manipuladores para isso. Seria mais fácil e limpo integrar-se à API de renderização, uma vez que o material está agora no mesmo nível de abstração.


fonte
1
Obrigado pela sua resposta, esse problema me atormentou por algum tempo, mas a criação de um renderizador sem as restrições do E / C é muito mais fácil.
Luke B.