Uso degli shader in Direct3D 10
La pipeline ha tre fasi shader e ognuna è programmata con uno shader HLSL. Tutti gli shader Direct3D 10 sono scritti in HLSL, destinati al modello di shader 4.
Differenze tra Direct3D 9 e Direct3D 10:
- A differenza dei modelli shader Direct3D 9 che possono essere creati in un linguaggio di assembly intermedio, gli shader del modello 4.0 vengono creati solo in HLSL. La compilazione offline degli shader in bytecode consumabile dal dispositivo è ancora supportata e consigliata nella maggior parte dei casi.
In questo esempio viene usato solo un vertex shader. Poiché tutti gli shader vengono creati dal core dello shader comune, imparare a usare un vertex shader è molto simile all'uso di una geometria o di un pixel shader.
Dopo aver creato uno shader HLSL (in questo esempio viene usato il vertex shader HLSLWithoutFX.vsh), sarà necessario prepararlo per la fase della pipeline specifica che verrà usata. A tale scopo, è necessario:
- Compilare un shader
- Creare un oggetto shader
- Impostare l'oggetto shader
- Ripeti per tutte le tre fasi dello shader
Questi passaggi devono essere ripetuti per ogni shader nella pipeline.
Compilare uno shader
Il primo passaggio consiste nel compilare lo shader, per verificare di aver codificato correttamente le istruzioni HLSL. A tale scopo, chiamare D3D10CompileShader e fornirlo con diversi parametri, come illustrato di seguito:
IPD3D10Blob * pBlob;
// Compile the vertex shader from the file
D3D10CompileShader( strPath, strlen( strPath ), "HLSLWithoutFX.vsh",
NULL, NULL, "Ripple", "vs_4_0", dwShaderFlags, &pBlob, NULL );
Questa funzione accetta i parametri seguenti:
Nome del file ( e lunghezza della stringa del nome in byte ) che contiene lo shader. Questo esempio usa solo un vertex shader (nel file HLSLWithoutFX.vsh in cui l'estensione del file vsh è un'abbreviazione per vertex shader).
Nome della funzione shader. Questo esempio compila un vertex shader dalla funzione Ripple che accetta un singolo input e restituisce uno struct di output (la funzione proviene dall'esempio HLSLWithoutFX):
VS_OUTPUT Ripple( in float2 vPosition : POSITION )
Puntatore a tutte le macro utilizzate dallo shader. Usare D3D10_SHADER_MACRO per definire le macro; è sufficiente creare una stringa di nome contenente tutti i nomi di macro (con ogni nome separato da uno spazio) e una stringa di definizione (con ogni corpo della macro separato da uno spazio). Entrambe le stringhe devono essere terminate con NULL.
Un puntatore a qualsiasi altro file necessario per compilare i tuoi shader. Viene usata l'interfaccia ID3D10Include che include due metodi implementati dall'utente: Open e Close. Per eseguire questa operazione, è necessario implementare il corpo dei metodi Open e Close; nel metodo Open aggiungere il codice da usare per aprire i file di inclusione desiderati, nella funzione Close aggiungere il codice per chiudere i file al termine dell'operazione.
Nome della funzione shader da compilare. Questo shader compila la funzione Ripple.
Il profilo dello shader da mirare durante la compilazione. Poiché è possibile compilare una funzione in un vertice, una geometria o un pixel shader, il profilo indica al compilatore quale tipo di shader e quale modello di shader confrontare il codice.
Opzioni del compilatore shader. Questi flag indicano al compilatore quali informazioni inserire nell'output compilato e come si vuole ottimizzare il codice di output: per velocità, debug e così via. Vedi Costanti effetto (Direct3D 10) per un elenco dei flag disponibili. L'esempio contiene codice che è possibile usare per impostare i valori dei flag del compilatore per il progetto. Si tratta principalmente di una questione relativa alla generazione o meno di informazioni di debug.
Puntatore al buffer che contiene il codice dello shader compilato. Il buffer contiene anche tutte le informazioni di debug e tabella dei simboli incorporate richieste dai flag del compilatore.
Puntatore a un buffer contenente un elenco di errori e avvisi rilevati durante la compilazione, che sono gli stessi messaggi visualizzati nell'output di debug se si esegue il debugger durante la compilazione dello shader. NULL è un valore accettabile quando non si desidera che gli errori vengano restituiti a un buffer.
Se lo shader viene compilato con successo, viene restituito un puntatore al codice dello shader sotto forma di interfaccia ID3D10Blob. Si chiama interfaccia BLOB perché il puntatore si trova in una posizione in memoria costituita da una matrice di DWORD. L'interfaccia viene fornita in modo da poter ottenere un puntatore allo shader compilato che sarà necessario nel passaggio successivo.
A partire da dicembre 2006 SDK, il compilatore DirectX 10 HLSL è ora il compilatore predefinito sia in DirectX 9 che in DirectX 10. Per informazioni dettagliate, vedere lo strumento Effect-Compiler.
Ottenere un puntatore a uno shader compilato
Diversi metodi API richiedono un puntatore a uno shader compilato. Questo argomento viene in genere chiamato pShaderBytecode perché punta a uno shader compilato rappresentato come sequenza di codici di byte. Per ottenere un puntatore a uno shader compilato, compilare prima di tutto lo shader chiamando D3D10CompileShader o una funzione simile. Se la compilazione ha esito positivo, lo shader compilato viene restituito in un'interfaccia ID3D10Blob. Usare infine il metodoGetBufferPointerper restituire il puntatore.
Creare un oggetto shader
Dopo aver compilato lo shader, chiamare CreateVertexShader per creare l'oggetto shader:
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();
Per creare l'oggetto shader, passare il puntatore allo shader compilato in CreateVertexShader. Poiché è stato necessario compilare correttamente lo shader per primo, questa chiamata passerà quasi certamente, a meno che non si sia verificato un problema di memoria nel computer.
È possibile creare tutti gli oggetti shader desiderati e semplicemente mantenere i puntatori a tali oggetti. Questo stesso meccanismo funziona per gli shader di geometria e pixel, presupponendo che corrispondano ai profili shader (quando si chiama il metodo di compilazione) e ai nomi di interfaccia (quando si chiama il metodo di creazione).
Impostare l'oggetto Shader
L'ultimo passaggio consiste nel configurare lo shader per la fase della pipeline. Poiché nella pipeline sono presenti tre fasi dello shader, è necessario effettuare tre chiamate API, una per ogni fase.
// Set a vertex shader
pd3dDevice->VSSetShader( g_pVS10 );
La chiamata a VSSetShader porta il puntatore al vertex shader creato nel passaggio 1. Questo imposta lo shader nel dispositivo. La fase del vertex shader è ora inizializzata con il relativo codice, rimane solo da inizializzare le variabili dello shader.
Ripetere tutte e tre le fasi dello shader
Ripetere gli stessi passaggi per creare qualsiasi vertex o pixel shader o anche un geometry shader che ha come output al pixel shader.
Argomenti correlati
Argomenti correlati
-
Guida alla programmazione di per HLSL