如何:设计外壳着色器

外壳着色器是三个阶段中的第一个阶段,它们协同工作以实现 细化 , (另外两个阶段是细化器和域着色器) 。 本主题演示如何设计外壳着色器。

外壳着色器需要两个函数:main外壳着色器,以及补丁常量函数。 外壳着色器在每个控制点上实现计算;外壳着色器还调用补丁常量函数,该函数在每个补丁上实现计算。

设计外壳着色器后,请参阅 如何:创建外壳着色器 ,了解如何创建外壳着色器。

设计外壳着色器

  1. 定义外壳着色器输入控制和输出控制点。

    // Input control point
    struct VS_CONTROL_POINT_OUTPUT
    {
        float3 vPosition : WORLDPOS;
        float2 vUV       : TEXCOORD0;
        float3 vTangent  : TANGENT;
    };
    
    // Output control point
    struct BEZIER_CONTROL_POINT
    {
        float3 vPosition    : BEZIERPOS;
    };
    
  2. 定义输出修补常量数据。

    // Output patch constant data.
    struct HS_CONSTANT_DATA_OUTPUT
    {
        float Edges[4]        : SV_TessFactor;
        float Inside[2]       : SV_InsideTessFactor;
    
        float3 vTangent[4]    : TANGENT;
        float2 vUV[4]         : TEXCOORD;
        float3 vTanUCorner[4] : TANUCORNER;
        float3 vTanVCorner[4] : TANVCORNER;
        float4 vCWts          : TANWEIGHTS;
    };
    

    对于四边形域, SV_TessFactor 定义 4 个边缘分割因子, (细化) 边缘,因为固定函数细化器需要知道要细化多少。 三角形域和等线域所需的输出不同。

    固定函数细化器不查看任何其他外壳着色器输出,例如其他修补常量数据或任何控制点。 域着色器(针对固定函数细化器生成的每个点调用)将视为其输入,即外壳着色器的所有输出控制点和所有输出补丁常量数据;着色器在其位置评估修补程序。

  3. 定义修补程序常量函数。 修补常量函数为每个补丁执行一次,以计算整个补丁 (的任何数据,而不是每个控制点数据(在外壳着色器) 中计算)。

    
    #define MAX_POINTS 32
    
    // Patch Constant Function
    HS_CONSTANT_DATA_OUTPUT SubDToBezierConstantsHS( 
        InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POINTS> ip,
        uint PatchID : SV_PrimitiveID )
    {   
        HS_CONSTANT_DATA_OUTPUT Output;
    
        // Insert code to compute Output here
    
        return Output;
    }
    

    修补程序常量函数的属性包括:

    • 一个输入指定包含修补程序 ID 的变量,由 SV_PrimitiveID 系统值标识, (在着色器模型 4) 中看到 语义
    • 一个输入参数是输入控制点,在本示例中 VS_CONTROL_POINT_OUTPUT 中声明。 补丁函数可以查看每个修补程序的所有输入控制点,在此示例中,每个修补程序有 32 个控制点。
    • 作为最小值,函数必须计算使用 SV_TessFactor 标识的细化器阶段的每补丁细化因子。 四边形域需要四个边缘分割因子, (SV_InsideTessFactor) 标识的另外两个因素来分割补丁内部。 固定函数细化器不会查看任何其他外壳着色器输出 (,例如修补常量数据或) 的任何控制点。
    • 输出通常由 结构定义,在此示例中由 HS_CONSTANT_DATA_OUTPUT 标识;结构取决于域类型,对于三角形或等线域,结构会有所不同。

    另一方面,针对固定函数细化器生成的每个点调用域着色器,并且需要从外壳着色器) 查看输出控制点和输出补丁常量数据 (,以评估其位置的补丁。

  4. 定义外壳着色器。 外壳着色器标识补丁的属性,包括补丁常量函数。 为每个输出控制点调用一次外壳着色器。

    [domain("quad")]
    [partitioning("integer")]
    [outputtopology("triangle_cw")]
    [outputcontrolpoints(16)]
    [patchconstantfunc("SubDToBezierConstantsHS")]
    BEZIER_CONTROL_POINT SubDToBezierHS( 
        InputPatch<VS_CONTROL_POINT_OUTPUT, MAX_POINTS> ip, 
        uint i : SV_OutputControlPointID,
        uint PatchID : SV_PrimitiveID )
    {
        VS_CONTROL_POINT_OUTPUT Output;
    
        // Insert code to compute Output here.
    
        return Output;
    }
    

    外壳着色器使用以下属性:

每个外壳着色器调用都可以看到 (VS_CONTROL_POINT_OUTPUT) 标识的所有输入控制点。 在此示例中,有 32 个输入控制点。

每个输出控制点调用一次外壳着色器, (使用 SV_PrimitiveID) 标识的每个补丁 (SV_OutputControlPointID) 。 此特定着色器的目的是计算输出 i,该输出被定义为 BEZIER 控制点, (此示例具有由 outputcontrolpoints) 定义的 16 个输出控制点。

外壳着色器 (补丁常量函数) 每个补丁运行一次例程,以最小) 计算修补常量数据 (细化因子。 另外,外壳着色器在每个补丁上运行一个名为 SubDToBezierConstantsHS) (修补程序常量函数,以计算修补常量数据,例如细化器阶段的细化因子。

如何使用 Direct3D 11

细化概述