(Direct3D 11) 编译效果

创作效果后,下一步是编译代码以检查语法问题。

为此,可以调用 (D3DX11CompileFromFileD3DX11CompileFromMemoryD3DX11CompileFromResource ) 的编译 API 之一。 这些 API 调用编译 HLSL 代码fxc.exe效果编译器。 这就是效果中代码的语法非常类似于 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 );

包括

编译 API 的一个参数是 include 接口。 如果要在编译器读取包含文件时包含自定义行为,请生成其中之一。 编译器每次创建或编译使用 include 指针) 的效果 (时,都会执行此自定义行为。 若要实现自定义的 include 行为,请从 ID3DInclude 接口派生类。 这为类提供了两种方法: OpenClose。 在这些方法中实现自定义行为。

搜索“包含文件”

编译器在 pParentData 参数中传递给 include 处理程序的 Open 方法的指针可能不会指向包含编译器编译着色器代码所需的 #include 文件的容器。 也就是说,编译器可能会在 pParentData 中传递 NULL。 因此,建议 include 处理程序搜索其自己的包含位置列表以获取内容。 包含处理程序可以在调用其 Open 方法时接收这些位置时动态添加新的包含位置。

在以下示例中,假设着色器代码的包含文件都存储在 某处目录中 。 当编译器调用 include 处理程序的 Open 方法以打开和读取 somewhereelse\foo.h 的内容时,include 处理程序可以保存 某处 目录的位置。 稍后,当编译器调用 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 中“监视”窗口的以下屏幕截图所示。

visual studio watch 窗口的屏幕截图,显示0x01997fb8错误

由于编译器在 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
}

(Direct3D 11) 呈现效果