編譯效果 (Direct3D 11)
撰寫效果之後,下一個步驟是編譯器代碼來檢查語法問題。
您可以呼叫其中一個編譯 API (D3DX11CompileFromFile、 D3DX11CompileFromMemory或 D3DX11CompileFromResource ) 。 這些 API 會叫用效果編譯器fxc.exe,以編譯 HLSL 程式碼。 這就是為什麼效果中的程式碼語法看起來非常類似 HLSL 程式碼。 (稍後會處理幾個例外狀況) 。 效果編譯器/hlsl 編譯器fxc.exe可在 [公用程式] 資料夾中的 SDK 中使用,因此如果您選擇的話,著色器 (或效果) 可以離線編譯。 請參閱從命令列執行編譯器的檔。
範例
以下是編譯效果檔案的範例。
WCHAR str[MAX_PATH];
DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL10.fx" );
hr = D3DX11CompileFromFile( str, NULL, NULL, pFunctionName, pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL, NULL, &pBlob, &pErrorBlob, NULL );
Includes
編譯 API 的其中一個參數是 include 介面。 如果您想要在編譯器讀取 Include 檔案時包含自訂行為,請產生其中一個。 編譯器會在每次建立或編譯使用 include 指標) 的效果 (執行這個自訂行為。 若要實作自訂的 Include 行為,請從 ID3DInclude 介面衍生類別。 這會提供您的類別和兩種方法: Open 和 Close。 在這些方法中實作自訂行為。
搜尋 Include 檔案
編譯器將 pParentData 參數傳遞至 include 處理常式 Open 方法的指標,可能不會指向包含編譯器編譯器代碼所需#include檔案的容器。 也就是說,編譯器可能會在pParentData中傳遞Null。 因此,我們建議您的 include 處理常式搜尋自己的內容包含位置清單。 您的 Include 處理常式可以在呼叫其 Open 方法時動態新增包含位置。
在下列範例中,假設著色器程式碼的 Include 檔案都儲存在 某處else 目錄中。 當編譯器呼叫 include 處理常式的 Open 方法以開啟並讀取 某處else\foo.h的內容時,include 處理常式可以儲存 某處else 目錄的位置。 稍後,當編譯器呼叫 include 處理常式的Open方法以開啟並讀取bar.h的內容時,include 處理常式可以在bar.h的某處自動搜尋。
Main.hlsl:
#include "somewhereelse\foo.h"
Foo.h:
#include "bar.h"
巨集
效果編譯也可以取得其他位置所定義之宏的指標。 例如,假設您想要修改 BasicHLSL10 中的效果,以使用兩個宏:零和一。 此處會顯示使用兩個宏的效果程式碼。
if( bAnimate )
vAnimatedPos += float4(vNormal, zero) *
(sin(g_fTime+5.5)+0.5)*5;
Output.Diffuse.a = one;
以下是兩個宏的宣告。
D3D10_SHADER_MACRO Shader_Macros[3] = { "zero", "0", "one", "1.0f", NULL, NULL };
宏是 Null 終止的宏陣列;其中每個宏都是使用 D3D10_SHADER_MACRO 結構來定義。
修改編譯效果呼叫,以取得宏的指標。
D3DX11CompileFromFile( str, Shader_Macros, NULL, pFunctionName,
pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL,
NULL, &pBlob, &pErrorBlob, NULL );
HLSL 著色器旗標
著色器旗標會將著色器條件約束指定給 HLSL 編譯器。 這些旗標會以下列方式影響著色器編譯器所產生的程式碼:
- 優化程式碼大小。
- 包括防止流量控制的偵錯資訊。
- 影響編譯目標,以及著色器是否可以在舊版硬體上執行。
如果您尚未指定兩個衝突的特性,則可以以邏輯方式結合這些旗標。 如需旗標的清單,請參閱 D3D10_SHADER 常數。
FX 旗標
當您建立效果以定義編譯行為或執行時間效果行為時,請使用這些旗標。 如需旗標的清單,請參閱 D3D10_EFFECT 常數。
檢查錯誤
如果在編譯期間發生錯誤,API 會傳回包含效果編譯器錯誤的介面。 這個介面稱為 ID3DBlob。 它無法直接讀取;不過,藉由傳回包含資料 (為字串) 緩衝區的指標,您可以看到任何編譯錯誤。
此範例包含 BasicHLSL.fx 中的錯誤,第一個變數宣告會發生兩次。
//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
float4 g_MaterialAmbientColor; // Material's ambient color
// Declare the same variable twice
float4 g_MaterialAmbientColor; // Material's ambient color
此錯誤會導致編譯器傳回下列錯誤,如 Microsoft Visual Studio 中 [監看式] 視窗的下列螢幕擷取畫面所示。
因為編譯器會在 LPVOID 指標中傳回錯誤,所以請將它轉換成 [監看式] 視窗中的字元字串。
以下是從失敗編譯傳回錯誤的程式碼。
// Read the D3DX effect file
WCHAR str[MAX_PATH];
ID3DBlob* l_pBlob_Effect = NULL;
ID3DBlob* l_pBlob_Errors = NULL;
hr = DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL10.fx" );
hr = D3DX11CompileFromFile( str, NULL, NULL, pFunctionName,
pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL,
NULL, &pBlob, &pErrorBlob, NULL );
LPVOID l_pError = NULL;
if( pErrorBlob )
{
l_pError = pErrorBlob->GetBufferPointer();
// then cast to a char* to see it in the locals window
}
相關主題