在 Direct3D 10 中使用着色器

管道有三个着色器阶段,每个阶段都使用 HLSL 着色器进行编程。 所有 Direct3D 10 着色器都以 HLSL 编写,面向着色器模型 4。

Direct3D 9 和 Direct3D 10 之间的差异:

  • 与可以使用中间程序集语言创作的 Direct3D 9 着色器模型不同,着色器模型 4.0 着色器仅在 HLSL 中创作。 仍支持将着色器脱机编译为设备消耗型字节码,并且建议在大多数情况下使用。

此示例仅使用顶点着色器。 由于所有着色器都是从通用着色器核心构建的,因此学习如何使用顶点着色器与使用几何图形或像素着色器非常相似。

(此示例使用顶点着色器 HLSLWithoutFX.vsh) 创作 HLSL 着色器后,需要为使用该着色器的特定管道阶段做好准备。 为此,需要:

需要对管道中的每个着色器重复这些步骤。

编译着色器

第一步是编译着色器,检查以查看是否已正确编码 HLSL 语句。 这是通过调用 D3D10CompileShader 并为其提供多个参数来完成的,如下所示:

    IPD3D10Blob * pBlob;
    
        
    // Compile the vertex shader from the file
    D3D10CompileShader( strPath, strlen( strPath ), "HLSLWithoutFX.vsh", 
        NULL, NULL, "Ripple", "vs_4_0", dwShaderFlags, &pBlob, NULL );

此函数采用以下参数:

  • 文件的名称 (,以及包含着色器) 的名称字符串的长度(以字节为单位)。 此示例仅使用文件 HLSLWithoutFX.vsh 文件中 (顶点着色器,其中文件扩展名 .vsh 是顶点着色器) 的缩写。

  • 着色器函数名称。 此示例从采用单个输入的 Ripple 函数编译顶点着色器,并返回输出结构, (函数来自 HLSLWithoutFX 示例) :

    VS_OUTPUT Ripple( in float2 vPosition : POSITION )
    
  • 指向着色器使用的所有宏的指针。 使用 D3D10_SHADER_MACRO 帮助定义宏;只需创建一个名称字符串,其中包含 (所有宏名称,每个名称由空格) 分隔,定义字符串 (每个宏正文由空格) 分隔。 这两个字符串都需要以 NULL 结尾。

  • 指向要编译的着色器所需的任何其他文件的指针。 这将使用 ID3D10Include 接口,该接口具有两个用户实现的方法:Open 和 Close。 若要执行此操作,需要实现 Open 和 Close 方法的正文;在 Open 方法中添加用于打开所需任何包含文件的代码,在 Close 函数中添加代码以在完成文件时关闭这些文件。

  • 要编译的着色器函数的名称。 此着色器编译纹波函数。

  • 编译时要面向的着色器配置文件。 由于可以将函数编译为顶点、几何图形或像素着色器,因此配置文件会告知编译器哪种类型的着色器以及要与哪个着色器模型进行比较的代码。

  • 着色器编译器标志。 这些标志告知编译器要将哪些信息放入编译的输出中,以及如何优化输出代码:速度、调试等。有关可用标志的列表,请参阅 Direct3D 10) (效果常量 。 此示例包含一些代码,可用于为项目设置编译器标志值 - 这主要是是否要生成调试信息的问题。

  • 指向包含已编译着色器代码的缓冲区的指针。 缓冲区还包含编译器标志请求的任何嵌入式调试和符号表信息。

  • 指向缓冲区的指针,该缓冲区包含编译期间遇到的错误和警告的列表,这些消息与在编译着色器时运行调试器时在调试输出中看到的消息相同。 如果不希望错误返回到缓冲区,则 NULL 是可接受的值。

如果着色器编译成功,则指向着色器代码的指针将作为 ID3D10Blob 接口返回。 它称为 Blob 接口,因为指针指向内存中由 DWORD 数组组成的位置。 提供了 接口,以便你可以获取指向下一步中需要的已编译着色器的指针。

从 2006 年 12 月 SDK 开始,DirectX 10 HLSL 编译器现在是 DirectX 9 和 DirectX 10 中的默认编译器。 有关详细信息 ,请参阅效果编译器工具

获取指向已编译着色器的指针

一些 API 方法需要指向已编译着色器的指针。 此参数通常称为 pShaderBytecode ,因为它指向表示为字节代码序列的已编译着色器。 若要获取指向已编译着色器的指针,请先通过调用 D3D10CompileShader 或类似函数来编译着色器。 如果编译成功,则会在 ID3D10Blob 接口中返回已编译的着色器。 最后,使用 GetBufferPointer 方法返回指针。

创建着色器对象

编译着色器后,调用 CreateVertexShader 来创建着色器对象:

    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();

若要创建着色器对象,请将指向已编译着色器的指针传递到 CreateVertexShader。 由于必须首先成功编译着色器,因此此调用几乎肯定会通过,除非计算机上存在内存问题。

可以根据需要创建任意数量的着色器对象,并仅保留指向它们的指针。 这种相同的机制适用于几何图形和像素着色器,假设调用编译方法时) 与调用 create 方法) 时 (接口名称 (着色器配置文件匹配。

设置着色器对象

最后一步是将着色器设置为管道阶段。 由于管道中有三个着色器阶段,因此需要进行三个 API 调用,每个阶段一次。

    // Set a vertex shader
    pd3dDevice->VSSetShader( g_pVS10 );

对 VSSetShader 的调用会将指针指向步骤 1 中创建的顶点着色器。 这会在设备中设置着色器。 顶点着色器阶段现在使用其顶点着色器代码进行初始化,剩下的只是初始化任何着色器变量。

对所有 3 个着色器阶段重复

重复这些相同的步骤集,生成任何顶点或像素着色器,甚至输出到像素着色器的几何着色器。

编译着色器

HLSL 编程指南