Cómo manejar materiales en un sistema de entidad / componente

13

Mi implementación de E / C es la básica donde las entidades son solo identificaciones, los componentes son datos y los sistemas actúan sobre los datos. En este momento estoy teniendo problemas con los materiales de objetos y el renderizado en general. Para objetos simples, tengo un ModelComponent, vinculado a a RenderSystem, ModelComponenttiene los identificadores de búfer de vértices que usa el sistema de renderizado. Un simple MaterialComponentprobablemente tendría color o fuerza especular, etc., pero quería que fuera lo suficientemente flexible como para permitir más de un paso de renderizado y "efectos" generales que no son tan fáciles como una variable simple en el MaterialComponent.

Intentando resolver estos problemas se me ocurrieron dos soluciones:

1 - Componente de material súper genérico

Algo como esto:

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

y en el sistema de renderizado, me enrollaría y pasaría los uniformes al sombreador. Supongo que esto sería lento, pero lo suficientemente rápido para mis propósitos.

2 - Otra capa de abstracción, MaterialData

Al tener una clase para envolver materiales específicos, que podría ser heredada por cualquier material especializado, la clase base tendría algo parecido, void set_shader_constants(ShaderData* d)pero la implementación depende de cada clase, y MaterialComponenttendría un puntero a un objeto MaterialData.

No estoy seguro de qué enfoque preferiría, pero ninguno de estos toca el tema de múltiples pases u otras técnicas de representación complejas.

¿Alguna idea sobre cómo lograr esto?

Lucas B.
fuente

Respuestas:

26

Los materiales son un concepto gráfico y pertenecen a su renderizador. Un renderizador es una pieza de arquitectura de nivel demasiado bajo para ser construida sobre un sistema de entidad. Los sistemas de entidades deberían ser para objetos de juego de nivel superior. No todo tiene que ser un componente, y de hecho, generalmente es una mala idea tratar de forzar todo en un solo paradigma como ese. Crea una solución de mínimo común denominador.

En consecuencia, le aconsejaría que adopte un enfoque diferente:

  • Un material es solo otro tipo en su renderizador.
  • Su renderizador tiene un tipo que representa "una cosa para ser dibujada en la pantalla". Con frecuencia, estos se denominan "instancias de render" o "renderables" o incluso "modelos". Este tipo tiene una referencia al material que usará al dibujar y proporciona una API pública para permitir que un consumidor del renderizador establezca ese material a lo que desee.

Básicamente, esto le pide que tome su ModelComponentnombre y lo renombre Model, eliminando la dependencia de la capa de entidad / componente y, por lo tanto, moviéndolo a una capa inferior de abstracción, junto con el resto de su renderizador.

Entonces, haces esto:

  • En la misma capa de abstracción que sus otros componentes, tiene algún tipo de "componente de aspecto" que representa la presentación visual de una entidad. Este componente solo contiene una referencia a algunos renderizables (como se describió anteriormente), que a su vez contiene la referencia a un material. El componente puede proporcionar una API para exponer el renderizable (permitiendo así que los clientes lo manipulen) o puede envolver el API del renderizable para controlar la exposición. Eso depende de usted.

Esto aborda el problema de interdependencia de componentes con el que se encuentra al hacer que los modelos y materiales sean componentes; una entidad debería tener un aspecto o no, y ese aspecto debería ser capaz de codificar todo sobre la presentación de la entidad, incluido el material.

Esto también le brinda la flexibilidad de tomar otros enfoques con el objeto material que sería más difícil de hacer con ese objeto como componente debido a la falta de paridad con el resto de la abstracción del sistema de renderizado.

Su problema de permitir efectos más complejos y pases múltiples es uno que podría resolverse principalmente en el material, exponiendo funciones para consultar y establecer constantes de sombreador con nombre expuestas por el archivo de sombreador del material. Esto es especialmente cierto si utiliza archivos de efectos (en D3D) que admiten múltiples pases y similares. Incluso si no está utilizando archivos de efectos, puede exponer la idea de múltiples pases del material, cada uno con sombreadores distintos, y permitir que la API del material proporcione manipuladores para eso. Sería más fácil y limpio integrarlo en la API de renderizado, ya que el material está ahora en el mismo nivel de abstracción.


fuente
1
Gracias por su respuesta, este problema me estuvo atormentando durante bastante tiempo, pero crear un renderizador sin las restricciones de E / C es mucho más fácil.
Luke B.