Verwenden von Shadern in Direct3D 10
Die Pipeline verfügt über drei Shaderstufen, die jeweils mit einem HLSL-Shader programmiert sind. Alle Direct3D 10-Shader sind in HLSL geschrieben und richten sich an Shadermodell 4.
Unterschiede zwischen Direct3D 9 und Direct3D 10:
- Im Gegensatz zu Direct3D 9-Shadermodellen, die in einer Zwischenassemblysprache erstellt werden können, werden Shadermodell 4.0-Shader nur in HLSL erstellt. Die Offlinekompilierung von Shadern in vom Gerät nutzbaren Bytecode wird weiterhin unterstützt und für die meisten Szenarien empfohlen.
In diesem Beispiel wird nur ein Vertex-Shader verwendet. Da alle Shader aus dem allgemeinen Shaderkern erstellt werden, ähnelt das Erlernen der Verwendung eines Vertex-Shaders der Verwendung eines Geometrie- oder Pixel-Shaders.
Nachdem Sie einen HLSL-Shader erstellt haben (in diesem Beispiel wird der Scheitelpunkt-Shader HLSLWithoutFX.vsh verwendet), müssen Sie ihn für die jeweilige Pipelinephase vorbereiten, die ihn verwendet. Dazu müssen Sie:
- Kompilieren eines Shaders
- Erstellen eines Shaderobjekts
- Festlegen des Shaderobjekts
- Wiederholen für alle drei Shaderstufen
Diese Schritte müssen für jeden Shader in der Pipeline wiederholt werden.
Kompilieren eines Shaders
Der erste Schritt besteht darin, den Shader zu kompilieren, um zu überprüfen, ob Sie die HLSL-Anweisungen ordnungsgemäß codiert haben. Dazu wird D3D10CompileShader aufgerufen und mit mehreren Parametern angegeben, wie hier gezeigt:
IPD3D10Blob * pBlob;
// Compile the vertex shader from the file
D3D10CompileShader( strPath, strlen( strPath ), "HLSLWithoutFX.vsh",
NULL, NULL, "Ripple", "vs_4_0", dwShaderFlags, &pBlob, NULL );
Diese Funktion verwendet die folgenden Parameter:
Der Name der Datei ( und die Länge der Namenszeichenfolge in Bytes ), die den Shader enthält. In diesem Beispiel wird nur ein Vertex-Shader verwendet (in der Datei HLSLWithoutFX.vsh, wobei die Dateierweiterung .vsh eine Abkürzung für vertex shader ist).
Der Name der Shaderfunktion. In diesem Beispiel wird ein Vertex-Shader aus der Funktion "Pixels" kompiliert, der eine einzelne Eingabe annimmt und eine Ausgabestruktur zurückgibt (die Funktion stammt aus dem HLSLWithoutFX-Beispiel):
VS_OUTPUT Ripple( in float2 vPosition : POSITION )Ein Zeiger auf alle makros, die vom Shader verwendet werden. Verwenden Sie D3D10 _ SHADER _ MACRO, um Ihre Makros zu definieren. Erstellen Sie einfach eine Namenszeichenfolge, die alle Makronamen enthält (wobei jeder Name durch ein Leerzeichen getrennt ist) und eine Definitionszeichenfolge (wobei jeder Makrotext durch ein Leerzeichen getrennt ist). Beide Zeichenfolgen müssen NULL-terminiert sein.
Ein Zeiger auf alle anderen Dateien, die Sie enthalten müssen, um Ihre Shader zum Kompilieren zu erhalten. Hierbei wird die ID3D10Include-Schnittstelle verwendet, die über zwei benutzerimplementierte Methoden verfügt: Öffnen und Schließen. Damit dies funktioniert, müssen Sie den Text der Open- und Close-Methoden implementieren. Fügen Sie in der Open-Methode den Code hinzu, den Sie zum Öffnen beliebiger include-Dateien verwenden würden. Fügen Sie in der Close-Funktion den Code hinzu, um die Dateien zu schließen, wenn Sie damit fertig sind.
Der Name der zu kompilierende Shaderfunktion. Dieser Shader kompiliert die Funktion "Ethereum".
Das Shaderprofil, auf das beim Kompilieren ausgerichtet werden soll. Da Sie eine Funktion in einen Scheitelpunkt, eine Geometrie oder einen Pixel-Shader kompilieren können, teilt das Profil dem Compiler mit, mit welchem Shadertyp und welchem Shadermodell der Code verglichen werden soll.
Shadercompilerflags. Diese Flags teilen dem Compiler mit, welche Informationen in die kompilierte Ausgabe aufgenommen werden sollen und wie der Ausgabecode optimiert werden soll: für Geschwindigkeit, für Debuggen usw. Eine Liste der verfügbaren Flags finden Sie unter Effektkonstanten (Direct3D 10). Das Beispiel enthält Code, mit dem Sie die Compilerflagwerte für Ihr Projekt festlegen können. Dies ist hauptsächlich eine Frage, ob Sie Debuginformationen generieren möchten.
Ein Zeiger auf den Puffer, der den kompilierten Shadercode enthält. Der Puffer enthält auch alle eingebetteten Debug- und Symboltabelleninformationen, die von den Compilerflags angefordert werden.
Ein Zeiger auf einen Puffer, der eine Liste von Fehlern und Warnungen enthält, die während der Kompilierung aufgetreten sind. Dies sind die gleichen Meldungen, die in der Debugausgabe angezeigt werden, wenn Sie den Debugger beim Kompilieren des Shaders ausführen. NULL ist ein akzeptabler Wert, wenn die Fehler nicht an einen Puffer zurückgegeben werden sollen.
Wenn der Shader erfolgreich kompiliert wird, wird ein Zeiger auf den Shadercode als ID3D10Blob-Schnittstelle zurückgegeben. Sie wird als Blob-Schnittstelle bezeichnet, da der Zeiger auf eine Position im Arbeitsspeicher zeigt, die aus einem Array von DWORD besteht. Die -Schnittstelle wird bereitgestellt, damit Sie einen Zeiger auf den kompilierten Shader abrufen können, den Sie im nächsten Schritt benötigen.
Ab dem SDK vom Dezember 2006 ist der DirectX 10 HLSL-Compiler jetzt sowohl in DirectX 9 als auch in DirectX 10 der Standardcompiler. Weitere Informationen finden Sie unter Effektcompilertool.
Abrufen eines Zeigers auf einen kompilierten Shader
Mehrere API-Methoden erfordern einen Zeiger auf einen kompilierten Shader. Dieses Argument wird in der Regel als pShaderBytecode bezeichnet, da es auf einen kompilierten Shader verweist, der als Sequenz von Bytecodes dargestellt wird. Um einen Zeiger auf einen kompilierten Shader abzurufen, kompilieren Sie zuerst den Shader, indem Sie D3D10CompileShader oder eine ähnliche Funktion aufrufen. Wenn die Kompilierung erfolgreich ist, wird der kompilierte Shader in einer ID3D10Blob-Schnittstelle zurückgegeben. Verwenden Sie abschließend die GetBufferPointer-Methode, um den Zeiger zurückzugeben.
Erstellen eines Shaderobjekts
Nachdem der Shader kompiliert wurde, rufen Sie CreateVertexShader auf, um das Shaderobjekt zu erstellen:
ID3D10VertexShader ** ppVertexShader
ID3D10Blob pBlob;
// Create the vertex shader
hr = pd3dDevice->CreateVertexShader( (DWORD*)pBlob->GetBufferPointer(),
pBlob->GetBufferSize(), &ppVertexShader );
// Release the pointer to the compiled shader once you are done with it
pBlob->Release();
Um das Shaderobjekt zu erstellen, übergeben Sie den Zeiger auf den kompilierten Shader an CreateVertexShader. Da Sie den Shader zuerst erfolgreich kompilieren mussten, wird dieser Aufruf mit ziemlicher Sicherheit erfolgreich ausgeführt, es sei denn, Sie haben ein Speicherproblem auf Ihrem Computer.
Sie können beliebig viele Shaderobjekte erstellen und einfach Zeiger darauf beibehalten. Dieser Mechanismus funktioniert für Geometrie- und Pixel-Shader, vorausgesetzt, Sie stimmen mit den Shaderprofilen (wenn Sie die Kompilierungsmethode aufrufen) mit den Schnittstellennamen überein (wenn Sie die create-Methode aufrufen).
Festlegen des Shaderobjekts
Im letzten Schritt wird der Shader auf die Pipelinephase festgelegt. Da die Pipeline drei Shaderstufen umfasst, müssen Sie drei API-Aufrufe durchführen, einen für jede Phase.
// Set a vertex shader
pd3dDevice->VSSetShader( g_pVS10 );
Beim Aufruf von VSSetShader wird der Zeiger auf den in Schritt 1 erstellten Vertexshader verwendet. Dadurch wird der Shader auf dem Gerät festgelegt. Die Vertex-Shaderphase wird nun mit ihrem Vertex-Shadercode initialisiert. Alles, was übrig bleibt, ist das Initialisieren aller Shadervariablen.
Wiederholen Für alle drei Shaderstufen
Wiederholen Sie diese Schritte, um einen Vertex- oder Pixel-Shader oder sogar einen Geometrie-Shader zu erstellen, der an den Pixelshader ausgegeben wird.