Freigeben über


Portiere das GLSL

Wichtige APIs

Nachdem Sie den Code zum Erstellen und Konfigurieren Ihrer Puffer und Shader-Objekte übertragen haben, ist es an der Zeit, den Code innerhalb dieser Shader von der GL Shader Language (GLSL) von OpenGL ES 2.0 in die High-level Shader Language (HLSL) von Direct3D 11 zu portieren.

In OpenGL ES 2.0 geben Shader Daten nach der Ausführung mithilfe systeminterner Elemente wie gl_Position, gl_FragColoroder gl_FragData[n] zurück (wobei n der Index für ein bestimmtes Renderziel ist). In Direct3D gibt es keine spezifischen systeminternen Elemente, und die Shader geben Daten als Rückgabetyp ihrer jeweiligen Main()-Funktionen zurück.

Daten, die zwischen Shaderphasen interpoliert werden sollen, z. B. die Vertexposition oder normal, werden mithilfe der unterschiedlichen-Deklaration behandelt. Direct3D verfügt jedoch nicht über eine solche Deklaration. Stattdessen müssen alle Daten, die zwischen Shaderphasen übergeben werden sollen, mit einer HLSL-Semantikgekennzeichnet werden. Die ausgewählte semantische Semantik gibt den Zweck der Daten an und ist. Beispielsweise deklarieren Sie Vertexdaten, die zwischen dem Fragmentshader interpoliert werden sollen, als:

float4 vertPos : POSITION;

oder

float4 vertColor : COLOR;

Dabei ist POSITION die Semantik, die zum Angeben von Vertexpositionsdaten verwendet wird. POSITION ist auch ein Sonderfall, da nach der Interpolation nicht vom Pixelshader darauf zugegriffen werden kann. Daher müssen Sie Eingaben für den Pixelshader mit SV_POSITION angeben, und die interpolierten Vertexdaten werden in dieser Variablen platziert.

float4 position : SV_POSITION;

Semantik kann für die Hauptmethoden von Shadern deklariert werden. Für Pixelshader ist SV_TARGET[n], das ein Renderziel angibt, für die Body-Methode erforderlich. (SV_TARGET ohne numerisches Suffix rendert standardmäßig zum Zielindex 0.)

Beachten Sie außerdem, dass Vertex-Shader zum Ausgeben der SV_POSITION Systemwertsemantik erforderlich sind. Diese Semantik löst die Vertexpositionsdaten in Koordinatenwerte auf, wobei x zwischen -1 und 1 liegt, y zwischen -1 und 1, z wird durch den ursprünglichen homogenen Koordinatenwert w (z/w) dividiert, und w ist 1 dividiert durch den ursprünglichen w-Wert (1/w). Pixelshader verwenden die SV_POSITION Systemwertsemantik, um die Pixelposition auf dem Bildschirm abzurufen, wobei x zwischen 0 und der Breite des Renderziels und y zwischen 0 und der Höhe des Renderziels liegt (jeweils um 0,5 versetzt). Feature-Ebene 9_x Pixel-Shader können nicht aus dem SV_POSITION-Wert lesen.

Konstantenpuffer müssen mit cbuffer deklariert und einem bestimmten Startregister für das Nachschlagen zugeordnet werden.

Direct3D 11: Eine HLSL-Konstantenpufferdeklaration

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

Hier verwendet der Konstantenpuffer das Register b0, um den gepackten Puffer zu halten. Auf alle Register wird in der Form von b# verwiesen. Weitere Informationen zur HLSL-Implementierung von Konstantenpuffern, Registern und Datenverpackung finden Sie unter Shader-Konstanten (HLSL).

Anweisungen

Schritt 1: Portierung des Vertex-Shaders

In unserem einfachen OpenGL ES 2.0-Beispiel verfügt der Vertex-Shader über drei Eingaben: eine konstante 4x4-Matrix für die Modellansicht-Projektion und zwei 4-Koordinaten-Vektoren. Diese beiden Vektoren enthalten die Scheitelpunktposition und ihre Farbe. Der Shader transformiert den Positionsvektor in perspektivische Koordinaten und weist ihn der gl_Position intrinsischen Variable zur Rasterung zu. Die Vertexfarbe wird zur Interpolation während der Rasterung auch in eine variierende Variable kopiert.

OpenGL ES 2.0: Vertex-Shader für das Würfelobjekt (GLSL)

uniform mat4 u_mvpMatrix; 
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 destColor;

void main()
{           
  gl_Position = u_mvpMatrix * a_position;
  destColor = a_color;
}

In Direct3D ist die Modell-Ansicht-Projektionsmatrix in einem konstanten Puffer enthalten, der in Register b0 gepackt ist, und die Vertex-Position und -Farbe sind mit den entsprechenden HLSL-Semantiken POSITION und COLOR markiert. Da unser Eingabelayout eine bestimmte Anordnung dieser beiden Vertexwerte vorgibt, erstellen Sie eine Struktur, um sie zu repräsentieren, und deklarieren diese als Typ für den Eingabeparameter der Shader-Körperfunktion (main). (Sie können sie auch als zwei einzelne Parameter angeben, aber das könnte umständlich werden.) Sie geben auch einen Ausgabetyp für diese Stufe an, der die interpolierte Position und Farbe enthält, und deklarieren diesen als Rückgabewert der Funktion des Vertex-Shader-Körpers.

Direct3D 11: Vertex-Shader für das Würfelobjekt (HLSL)

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
  float3 pos : POSITION;
  float3 color : COLOR;
};

// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
  float3 pos : SV_POSITION;
  float3 color : COLOR;
};

PixelShaderInput main(VertexShaderInput input)
{
  PixelShaderInput output;
  float4 pos = float4(input.pos, 1.0f); // add the w-coordinate

  pos = mul(mvp, projection);
  output.pos = pos;

  output.color = input.color;

  return output;
}

Der Ausgabedatentyp PixelShaderInput wird während der Rasterung aufgefüllt und dem Fragment- (Pixel-) Shader bereitgestellt.

Schritt 2: Portierung des Fragmentshaders

Unser Beispielfragmentshader in GLSL ist extrem einfach: Versorgen Sie die intrinsische Funktion gl_FragColor mit dem interpolierten Farbwert. OpenGL ES 2.0 schreibt es in das Standardrenderziel.

OpenGL ES 2.0: Fragment-Shader für das Kubus-Objekt (GLSL)

varying vec4 destColor;

void main()
{
  gl_FragColor = destColor;
} 

Direct3D ist fast so einfach. Der einzige wesentliche Unterschied besteht darin, dass die Körperfunktion des Pixel-Shaders einen Wert zurückgeben muss. Da es sich bei der Farbe um einen 4-Koordinatenwert (RGBA) handelt, geben Sie float4 als Rückgabetyp an, und geben Sie dann das Standardrenderziel als SV_TARGET Systemwertsemantik an.

Direct3D 11: Pixelshader für das Cube-Objekt (HLSL)

struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR;
};


float4 main(PixelShaderInput input) : SV_TARGET
{
  return float4(input.color, 1.0f);
}

Die Farbe für das Pixel an der Position wird in das Renderziel geschrieben. Sehen wir uns nun an, wie sie den Inhalt dieses Renderziels in Zeichnen auf den Bildschirmanzeigen!

Vorheriger Schritt

Vertexpuffer und -daten portieren

Nächster Schritt

Zeichne auf den Bildschirm

Bemerkungen

Das Verständnis der HLSL-Semantik und der Anordnung von Konstantenpuffern kann Ihnen einige Debugging-Kopfschmerzen ersparen und Optimierungsmöglichkeiten bieten. Falls Sie die Gelegenheit haben, lesen Sie Variablensyntax (HLSL), Einführung in Puffer in Direct3D 11und So erstellen Sie einen konstanten Puffer. Wenn nicht, hier sind ein paar Tipps zu den Themen Semantik und konstante Puffer, die Sie beachten sollten:

  • Überprüfen Sie immer den Direct3D-Konfigurationscode Ihres Renderers, um sicherzustellen, dass die Strukturen für die Konstantenpuffer mit den cbuffer-Strukturdeklarationen in Ihrem HLSL übereinstimmen und dass die Komponentenskalartypen in beiden Deklarationen übereinstimmen.
  • Verwenden Sie im C++-Code des Renderers DirectXMath- Typen in Ihren Konstantenpufferdeklarationen, um eine ordnungsgemäße Datenverpackung sicherzustellen.
  • Die beste Möglichkeit zum effizienten Verwenden von Konstantenpuffern besteht darin, Shadervariablen basierend auf ihrer Aktualisierungshäufigkeit in Konstantenpuffer zu organisieren. Wenn Sie beispielsweise einige einheitliche Daten haben, die einmal pro Frame aktualisiert werden, und andere einheitliche Daten, die nur aktualisiert werden, wenn die Kamera verschoben wird, sollten Sie diese Daten in zwei separate Konstantenpuffer unterteilen.
  • Semantiken, die Sie vergessen haben anzuwenden, oder die Sie falsch angewendet haben, sind die früheste Quelle Ihrer Shaderkompilierungsfehler (FXC). Überprüfen Sie sie nochmal! Die Dokumente können etwas verwirrend sein, da viele ältere Seiten und Beispiele auf verschiedene Versionen der HLSL-Semantik vor Direct3D 11 verweisen.
  • Stellen Sie sicher, dass Sie wissen, auf welche Direct3D-Featureebene Sie für jeden Shader abzielen. Die Semantik für Featureebene 9_* unterscheidet sich von denen für 11_1.
  • Die SV_POSITION Semantik löst die zugeordneten Positionsdaten nach der Interpolation in Koordinatenwerte auf, wobei x zwischen 0 und der Breite des Renderziels liegt, y zwischen 0 und der Höhe des Renderziels liegt, z wird durch den ursprünglichen homogenen Koordinatenwert w (z/w) dividiert, und w ist 1 dividiert durch den ursprünglichen w-Wert (1/w).

Anleitung: Einen einfachen OpenGL ES 2.0 Renderer auf Direct3D 11 portieren

Shaderobjekte portieren

Vertexpuffer und -daten portieren

Zeichne auf den Bildschirm