Comment gérer les matériaux dans un système Entité / Composant

13

Mon implémentation E / C est celle de base où les entités ne sont que des ID, les composants sont des données et les systèmes agissent sur les données. En ce moment, j'ai des problèmes avec les matériaux des objets et le rendu en général. Pour les objets simples, j'ai un ModelComponent, lié à un RenderSystem, ModelComponenta les ID de tampon de vertex que le système de rendu utilise. Un simple MaterialComponentaurait probablement une couleur ou une force spéculaire, etc., mais je voulais qu'il soit suffisamment flexible pour permettre plus d'un passage de rendu et des "effets" généraux qui ne sont pas aussi faciles qu'une simple variable dans le MaterialComponent.

En essayant de résoudre ces problèmes, j'ai trouvé deux solutions:

1 - Composant matériel super générique

Quelque chose comme ça:

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

et dans le système de rendu, je bouclais et passais les uniformes au shader. Je suppose que ce serait lent, mais assez rapide pour mes besoins.

2 - Une autre couche d'abstraction, MaterialData

Ayant une classe pour envelopper des matériaux spécifiques, qui pourraient être hérités par n'importe quel matériel spécialisé, la classe de base aurait quelque chose comme, void set_shader_constants(ShaderData* d)mais l'implémentation dépend de chaque classe et MaterialComponentaurait un pointeur sur un objet MaterialData.

Je ne sais pas quelle approche je préférerais, mais ni l'un ni l'autre ne touche le sujet des passes multiples ou d'autres techniques de rendu complexes.

Une idée sur la façon d'accomplir cela?

Luke B.
la source

Réponses:

26

Les matériaux sont un concept graphique et appartiennent à votre moteur de rendu. Un moteur de rendu est un élément d'architecture de niveau trop bas pour être construit au-dessus d'un système d'entités. Les systèmes d'entités devraient être destinés aux objets de jeu de niveau supérieur. Tout ne doit pas nécessairement être un composant, et en fait, c'est généralement une mauvaise idée d'essayer de tout forcer dans un seul paradigme comme ça. Il crée une solution au plus petit dénominateur commun.

Par conséquent, je vous conseille d'adopter une approche différente:

  • Un matériau n'est qu'un autre type dans votre moteur de rendu.
  • Votre moteur de rendu a un type qui représente «une chose à dessiner à l'écran». Ils sont souvent appelés «instances de rendu» ou «rendus» ou même «modèles». Ce type a une référence au matériau qu'il utilisera lors du dessin et fournit une API publique pour permettre à un consommateur du moteur de rendu de définir ce matériau comme il le souhaite.

Cela vous demande essentiellement de prendre votre ModelComponentet de le renommer Model, en supprimant la dépendance sur la couche entité / composant et en la déplaçant ainsi vers une couche d'abstraction inférieure, à côté du reste de votre rendu.

Ensuite, vous faites ceci:

  • Dans la même couche d'abstraction que vos autres composants, vous avez une sorte de "composant d'aspect" qui représente la présentation visuelle d'une entité. Ce composant contient simplement une référence à un rendu (comme décrit ci-dessus), qui à son tour contient la référence à un matériau. Le composant peut fournir une API pour exposer le rendu (permettant ainsi aux clients de le manipuler) ou il peut envelopper l'API du rendu pour contrôler l'exposition. C'est à toi de voir.

Cela résout le problème d'interdépendance des composants que vous rencontrez en faisant en sorte que les modèles et les matériaux soient tous deux des composants; une entité devrait avoir un aspect ou non, et cet aspect devrait être en mesure de coder tout ce qui concerne la présentation de l'entité, y compris le matériel.

Cela vous donne également la possibilité d'adopter d'autres approches avec l'objet matériel qui seraient plus difficiles à faire avec cet objet en tant que composant en raison du manque de parité avec le reste de l'abstraction du système de rendu.

Votre problème d'autoriser des effets plus complexes et des passes multiples est un problème qui pourrait être résolu principalement dans le matériau, en exposant des fonctions pour interroger et définir des constantes de shader nommées exposées par le fichier de shader du matériau. Cela est particulièrement vrai si vous utilisez des fichiers d'effets (dans D3D) qui prennent en charge plusieurs passes et autres. Même si vous n'utilisez pas de fichiers d'effets, vous pouvez exposer l'idée de plusieurs passages du matériau, chacun avec des shaders distincts, et autoriser l'API du matériau à fournir des manipulateurs pour cela. Il serait plus facile et plus propre de l'intégrer dans l'API de rendu, car le matériau est maintenant au même niveau d'abstraction.


la source
1
Merci pour votre réponse, ce problème me tourmentait depuis un certain temps, mais créer un rendu sans les contraintes d'E / C est beaucoup plus facile.
Luke B.