Ich suche nach einer eleganten Möglichkeit, Eingabelayouts in meinem directx11-Code zu verarbeiten.
Das Problem, das ich habe, ist, dass ich eine Effektklasse und eine Elementklasse habe. Die Effektklasse kapselt Shader und ähnliche Einstellungen, und die Element-Klasse enthält etwas, das gezeichnet werden kann (3D-Modell, Landschaft usw.).
Mein Zeichencode legt die Geräte-Shader usw. mit dem angegebenen Effekt fest und ruft dann die Zeichenfunktion des Elements auf, um die darin enthaltene tatsächliche Geometrie zu zeichnen.
Das Problem ist folgendes: Ich muss irgendwo ein D3D11InputLayout erstellen. Dies gehört wirklich zur Element-Klasse, da es für den Rest des Systems keine Sache ist, wie dieses Element sein Scheitelpunkt-Layout darstellt. Um das Objekt zu erstellen, benötigt die API jedoch den Vertex-Shader-Bytecode für den Vertex-Shader, der zum Zeichnen des Objekts verwendet wird. In directx9 war es einfach, es gab keine Abhängigkeit, so dass mein Element seine eigenen Eingabelayoutstrukturen enthalten und diese festlegen konnte, ohne dass der Effekt beteiligt war.
Das Element sollte jedoch eigentlich nichts über den Effekt wissen müssen, mit dem es gezeichnet wird. Es handelt sich lediglich um Rendereinstellungen, und das Element ist dazu da, Geometrie bereitzustellen.
Ich weiß also nicht genau, wo ich speichern soll und wie ich das InputLayout für jeden Draw-Aufruf auswählen soll. Ich meine, ich habe etwas zum Laufen gebracht, aber es scheint sehr hässlich.
Dies führt dazu, dass ich entweder etwas Offensichtliches übersehen habe oder dass mein Design, alle Rendereinstellungen in einem Effekt, die Geometrie in einem Element und einen Drittanbieter, der alles zeichnet, zu haben, einfach fehlerhaft ist.
Sie fragen sich nur, wie jemand anderes seine Eingabelayouts in directx11 auf elegante Weise handhabt?
Vielen Dank für die Antworten, sie sind sehr hilfreich. Ich werde eine Antwort auf meine eigene Frage hinzufügen, weil ich von dort aus ein bisschen weitergezogen bin.
Am Ende wurde mir klar, dass es vielleicht ein Fehler war, die Shader vollständig von den ziehbaren Gegenständen trennen zu wollen. Sie sind im "realen Leben" grundsätzlich miteinander verbunden, so dass es vielleicht kein Problem ist, dass sie im Design sind.
Zum Beispiel funktioniert ein Wasser-Shader nur mit einem Element, das Wasser ziehen möchte. Nur so können die benötigten Daten bereitgestellt werden. Ein Shader, der animierte Modelle zeichnet, funktioniert nur mit einem animierten Modellelement. Ich kann mich nicht plötzlich für einen Wassershader mit einem animierten Modell entscheiden. Es kann einfach nicht funktionieren.
Der Versuch, eine abstrakte Shader-Klasse zu erstellen, die jeden Shader laden und mit jedem zeichnbaren Element arbeiten kann, ist ein Fehler. Es spiegelt nicht wider, wie sie in der Realität verwendet werden können.
Also habe ich stattdessen Shader-Klassen AnimatedModelShader, WaterShader, LandscapeShader erstellt. Jede dieser Optionen verfügt möglicherweise über Optionen, die dazu führen, dass unterschiedliche physische Shader-Dateien geladen werden. Sie verfügen jedoch notwendigerweise immer über dieselbe grundlegende Benutzeroberfläche, da ein Landscape-Shader immer dieselbe Art von Dateneingabe benötigt.
Der Shader ist nun für die Erstellung seines eigenen Eingabelayouts verantwortlich und teilt dem verwendeten Element mit, wie seine Scheitelpunkte zu gestalten sind, indem ein öffentliches typedef namens vertexType verwendet wird, das das Element verwendet, wenn es diesen Shader verwenden möchte.
Überhaupt nicht mein ursprüngliches Design, aber wie sich herausstellte, war der Wunsch, die beiden Konzepte zu trennen, sowieso nicht sehr nützlich.
quelle
Ich mache etwas Ähnliches wie dotminic - ich habe eine Routine, an die ich ein Array von D3D11_INPUT_ELEMENT_DESC übergebe, das dann einen gefälschten Vertex-Shader mit einer passenden Eingabesignatur erstellt, kompiliert, ein Layout daraus erstellt und schließlich den gefälschten Shader freigibt.
Ja, es ist hässlich, und ja, es bedeutet, eine Milbe vorsichtiger sein zu müssen, als ich es sonst tun würde, wenn ich es richtig machen würde, aber es sind Kompromisse, die ich derzeit im Austausch für eine sauberere Trennung akzeptieren möchte.
quelle
Sieht für mich so aus, als müssten Sie sich wirklich keine Sorgen machen. Nachdem ich mir die MSDN-Dokumentation für CreateInputLayout angesehen hatte, stieß ich auf Folgendes:
http://msdn.microsoft.com/en-gb/library/windows/desktop/ff476512(v=vs.85).aspx
Dies macht deutlich, dass Sie Ihre Eingabelayouts fast genauso behandeln sollten wie Ihre alten DX9-Vertex-Deklarationen. Wenn Sie beim ersten Erstellen einen Shader-Bytecode angeben, kann DX11 diese nur validieren. Und anscheinend ist das Schlimmste, was passieren wird, wenn Sie diesen Schritt vermeiden oder fehlschlagen, eine Laufzeitwarnung, die Sie ignorieren können.
DX11 "erstellt also keine Abhängigkeit" zwischen Ihren Eingabelayouts und Ihren Shadern ... es bietet eine kostenlose Validierung! : D.
quelle
CreateInputLayout
kann auch verwendet werden, um einen Shader anhand eines vorhandenen Eingabelayouts zu validieren, sodass Sie alle Shader überprüfen können, die ihn verwenden würden - was ich zumindest in Debug-Builds aus Sicherheitsgründen empfehlen würde.D3D11_INPUT_ELEMENT_DESC
s gemeint, mit dem es erstellt wurde. Dies kann anhand des Bytecodes eines anderen Shaders überprüft werden, ohne dass ein neues Eingabe-Layout-Objekt erstellt werden muss.