Umgang mit Materialien in einem Entity / Component-System

13

Meine E / C-Implementierung ist die grundlegende, bei der Entitäten nur IDs sind, Komponenten Daten sind und Systeme auf die Daten einwirken. Im Moment habe ich Probleme mit Objektmaterialien und Rendering im Allgemeinen. Für einfache Objekte habe ich a ModelComponent, gebunden an a RenderSystem, ModelComponentdie Vertex-Buffer-IDs, die das Rendering-System verwendet. Eine einfache MaterialComponentDatei hätte wahrscheinlich eine Farb - oder Spiegelstärke usw., aber ich wollte, dass sie flexibel genug ist, um mehr als einen Renderdurchlauf und allgemeine "Effekte" zu ermöglichen, die nicht so einfach sind wie eine einfache Variable in der MaterialComponent.

Um diese Probleme zu lösen, habe ich zwei Lösungen gefunden:

1 - Supergenerische Materialkomponente

Etwas wie das:

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

und im Render-System würde ich die Uniformen schleifen und an den Shader weitergeben. Ich nehme an, das wäre langsam, aber schnell genug für meine Zwecke.

2 - Eine weitere Abstraktionsebene, MaterialData

Wenn die Basisklasse über eine Klasse verfügt, die bestimmte Materialien umschließt, die von jedem speziellen Material geerbt werden könnten, ist dies in etwa so, void set_shader_constants(ShaderData* d)aber die Implementierung hängt von jeder Klasse ab, und MaterialComponentsie verfügt über einen Zeiger auf ein MaterialData-Objekt.

Ich bin mir nicht sicher, welchen Ansatz ich bevorzugen würde, aber keiner davon berührt das Thema von mehreren Durchgängen oder anderen komplexen Rendering-Techniken.

Irgendeine Idee, wie dies erreicht werden kann?

Luke B.
quelle

Antworten:

26

Materialien sind ein Grafikkonzept und gehören in Ihren Renderer. Ein Renderer ist eine Architektur auf einer zu niedrigen Ebene, als dass er auf einem Entitätssystem aufbauen könnte. Entitätssysteme sollten für übergeordnete Spielobjekte sein. Nicht alles muss eine Komponente sein, und in der Tat ist es im Allgemeinen eine schlechte Idee, alles in ein einziges Paradigma wie dieses zu zwingen. Es wird eine Lösung mit dem kleinsten gemeinsamen Nenner erstellt.

Folglich würde ich raten, dass Sie einen anderen Ansatz verfolgen:

  • Ein Material ist nur ein anderer Typ in Ihrem Renderer.
  • Ihr Renderer hat einen Typ, der "eine Sache darstellt, die auf dem Bildschirm gezeichnet werden soll". Häufig werden diese als "Renderinstanzen" oder "Renderables" oder sogar "Modelle" bezeichnet. Dieser Typ enthält einen Verweis auf das Material, das beim Zeichnen verwendet wird, und stellt eine öffentliche API bereit, mit der ein Benutzer des Renderers das Material auf die gewünschten Werte einstellen kann.

Dies bedeutet im Wesentlichen, dass Sie Ihre nehmen ModelComponentund umbenennen müssen Model, um die Abhängigkeit von der Entity / Component-Ebene zu beseitigen und sie auf eine niedrigere Abstraktionsebene zusammen mit dem Rest Ihres Renderers zu verschieben.

Dann machst du das:

  • In derselben Abstraktionsebene wie Ihre anderen Komponenten befindet sich eine Art "Aspektkomponente", die die visuelle Darstellung einer Entität darstellt. Diese Komponente enthält lediglich einen Verweis auf eine Renderable (wie oben beschrieben), die wiederum den Verweis auf ein Material enthält. Die Komponente kann eine API bereitstellen, um das Renderable verfügbar zu machen (sodass Clients es manipulieren können), oder sie kann die API des Renderable umschließen, um das Exposure zu steuern. Das liegt an dir.

Dies behebt das Problem der gegenseitigen Abhängigkeit von Komponenten, indem sowohl Modelle als auch Materialien Komponenten sein müssen. Eine Entität sollte entweder einen Aspekt haben oder nicht, und dieser Aspekt sollte in der Lage sein, alles über die Darstellung der Entität, einschließlich des Materials, zu kodieren.

Dies bietet Ihnen auch die Flexibilität, andere Ansätze mit dem materiellen Objekt zu verfolgen, die mit diesem Objekt als Komponente aufgrund der mangelnden Parität mit dem Rest der Rendering-System-Abstraktion schwerer umzusetzen wären.

Das Problem, komplexere Effekte und mehrere Durchläufe zuzulassen, kann in erster Linie im Material gelöst werden, indem Funktionen zum Abfragen und Festlegen benannter Shader-Konstanten verfügbar gemacht werden, die in der Shader-Datei des Materials verfügbar gemacht werden. Dies gilt insbesondere dann, wenn Sie Effektdateien (in D3D) verwenden, die mehrere Durchgänge und dergleichen unterstützen. Selbst wenn Sie keine Effektdateien verwenden, können Sie die Idee von mehreren Durchläufen des Materials mit jeweils unterschiedlichen Shadern offenlegen und der Material-API erlauben, Manipulatoren dafür bereitzustellen. Die Integration in die Rendering-API wäre am wahrscheinlichsten einfacher und sauberer, da sich das Material jetzt auf derselben Abstraktionsebene befindet.


quelle
1
Vielen Dank für Ihre Antwort, dieses Problem plagte mich schon seit einiger Zeit, aber es ist viel einfacher, einen Renderer ohne die Einschränkungen von E / C zu erstellen.
Luke B.