enb系列吧 关注:35贴子:143
  • 14回复贴,共1

【HLSL高阶着色语言基础】——ENBseries进阶教程

只看楼主收藏回复

由于铭感字符
所以第一章只能发截图


IP属地:重庆1楼2020-10-07 17:13回复

    看起来很像C++不是?


    IP属地:重庆2楼2020-10-07 17:14
    回复
      下面开始正题
      #标量类型:
      bool--true或者false.
      int--32位有符号整数.
      half--16位浮点值.
      float--32位浮点值.
      double--64位浮点值.
      #向量类型:
      vector--4维向量,其中每一个元素都是一个float类型值。
      vector<标量类型,维数>--一个有所设维数的向量,每个元素是一个标量类型的类型。
      #例如:
      float4 fVector0;
      float fVector1[4];
      vector fVector2;
      vector<float,4> fVector3;
      定义bool类型的三元组:
      bool3 bVector0;
      bool bVector1[3];
      vector<bool,3> bVector2;
      #访问向量:
      (可单独通过每个元素来访问,也可使用swizzle)
      float4 pos = {3.0f,5.0f,2.0f,1.0f};
      float value0 = pos[0]; // value0 = 3.0f;
      float value1 = pos.x;
      float value2 = pos.g; // value2 = 5.0f;
      float2 vec0 = pos.xy;
      float2 vec1 = pos.ry; // 无效,要么用xyzw要么用rgba。
      #矩阵类型:
      float4x4 view_proj_matrix;
      float4x4 texture_matrix0;
      float3x4 mat0;
      matrix<float, 3, 4> mat1;
      #矩阵类型的访问,可通过下标如:
      float fValue = view_proj_matrix[0][0];
      #也可以使用如下模式访问:
      _m00,_m01,_m02,_m03
      _m10,_m11,_m12,_m13
      _m20,_m21,_m22,_m23
      _m30,_m31,_m32,_m33
      #或者:
      _11,_12,_13,_14
      _21,_22,_23,_24
      _31,_32,_33,_34
      _41,_42,_43,_44
      #矩阵访问也可使用数组访问方式:
      float2x2 fMat = {3.0f, 5.0f, //行1
      2.0f, 1.0f};//行2
      float value0 = fMat[0]; //value0 = 3.0f 这里发生了一个截断
      float value1 = fMat._m00; //value1 = 3.0f
      float value2 = fMat._12; //value2 = 1.0f
      float value3 = fMat[1][1]; //value3 = 1.0f
      float2 vec0 = fMat.21_22; //vec0 = {2.0f, 1.0f}
      float2 vec1 = fMat[1]; //vec1 = {2.0f, 1.0f}对应value0的取值
      #修饰符:
      不能被着色器代码改变的变量为 const 类型。
      row_major和col_major类型用于指定矩阵的布局。
      row_major表明矩阵的每行都存储在一个常量寄存器中,
      如果按列存储则使用col_major,它是默认的。


      IP属地:重庆3楼2020-10-07 17:16
      回复
        各类修饰符演示
        #存储类型修饰符
        跟C一样,变量可被声明为"static"或者"exter"n,
        这两个变量是互斥的。
        在全局域中,
        "static"标识符指明变量只能被着色器而不能被应用程序通过API来访问。
        全局域中任何非"static"类型的变量可以被应用程序通过API来修改。
        在局部域使用"static"表示变量包含的数据在函数调用中保持不变"。
        exter"n标识符如果作用在全局域,表示该变量可以在着色器外部被API修改,
        全局域中变量的默认类型为"extern",
        "shared"修饰符表示指定的全局域变量可以在不同特效中共享。
        如果对变量使用"uniform"修饰符,其值就被认为是在HLSL着色程序外设定(比如,使用Set*ShaderConstant*()函数)。
        全局变量默认已经声明为"uniform",
        但不具有const属性。
        #比如:
        extern float translucencyCoeff;
        const float gloss_bias;
        static float gloss_scale;
        float diffuse;
        变量translucencyCoeff和diffuse通过API设定,gloss_bias也可以通过API设定但是着色器程序不能更改。
        最后gloss_scale不能被API修改,
        但是能被着色器修改。


        IP属地:重庆4楼2020-10-07 17:17
        回复
          //开始编译着色器以及语法运用//
          #类型转换:
          想要写简洁高效的着色程序,
          应该对HLSL的类型转换有所了解。
          #下面的例子是把一个标量扩展到一个4D向量中:
          float4 vResult = 0.0f;// vResult = {0.0f, 0.0f, 0.0f, 0.0f};
          如果从高维向低维转换,多余的数据会忽略。
          #着色器输入:
          顶点和像素着色器有两种类型的输入数据:varying和uniform.varying类型的输入表明这个数据对每个可执行的着色器程序是唯一的。
          对于顶点着色器来说,
          varying数据(例如,位置,法向量等.)来自于顶点流。
          uniform数据(例如,材质颜色,世界坐标系转换等)是在多个着色器执行中不变的。
          如果你熟悉汇编模式,uniform数据是哪些在常量寄存器中的数据,
          varying数据是哪些存在于Vx或者Tx寄存器的数据。
          #Uniform 输入:
          HLSL中有两种方法指定Uniform数据.一般是声明一个全局变量。
          着色器中使用的任何全局变量都会导致该变量被加入到该着色器需要的uniform变量表中。
          第二个方法是在输入参数的声明处显示使用uniform修饰符,
          这同样会使该变量被添加到该着色器使用的uniform变量表中。
          #下面是一个例子:
          //声明一个全局的uniform变量
          //在常量表中登记为'UniformGlobal'
          float4 UniformGlobal;
          //声明一个uniform参数
          //在常量表中登记为'$UniformParam'
          float4 main(uniform float4 UniformParam):POSITION
          {
          return UniformGlobal*UniformParam;
          }
          着色器使用的uniform变量和应用程序通过constant table(常量表)相互联系起来。
          常量表是一个符号表,
          它定义了在着色器执行前,
          uniform变量如何被着色器加载进常量寄存器。
          参数中的uniform数据在簿记时前面加了"$"是为了防止和本地域的uniform变量名字冲突。
          常量表包含所有着色器中使用的uniform数据使用的常量寄存器地址。
          该表也包含类型信息和默认值。
          常量表被编译器生成并按照压缩的二进制形式存储。
          在运行时解释该表的API将会在后面章节介绍。


          IP属地:重庆5楼2020-10-07 17:18
          回复
            【varying数据运用】
            #varying 输入:
            varying数据用于标记输入参数,
            表明其具有输入关联语义。
            所有高层着色器输入都必须具有varying或者uniform其一的属性,
            否则将编译失败。
            输入关联表示一个用于连接给定着色器的输入和前一阶段的渲染管线的输出的名字。
            #比如:在顶点着色器中输入关联POSITION0用于指定顶点缓冲中的位置数据应该链接到什么地方。
            像素和顶点着色器具有不同的输入关联语义,
            这取决于图形管线中不同的着色单元。
            顶点着色器输入语义描述从顶点缓冲中加载的单顶点信息转化成可以被顶点着色器使用的形式(比如,位置,法向量,文理坐标,颜色,切线,二分向量等)。
            这些输入语义直接映射到D3DDECLUSAGE枚举组合中,UsageIndex用于描述顶点缓冲中的顶点元素。
            有两种方法讲输入关联分配到着色器输入中,
            第一个方法是在在输入参数声明后附加":"
            分号和关联名称。
            第二种方法是定义一个结构体。
            #下面是一个例子:
            //使用关联绑定声明一个输入结构
            struct InStruct
            {
            float4 Pos1 : POSITION1
            };
            //将Pos变量声明为包含位置的数据
            float4 main(float4 Pos: POSITION0, InStruct In) : POSITION
            {
            return Pos*In.Pos1;
            }
            //将Col变量声明为包含颜色(COLOR0)插值的参数
            float4 mainPS(float4 Col : COLOR0):COLOR
            {
            return Col;
            }


            IP属地:重庆6楼2020-10-07 17:19
            回复
              #着色器输出:
              顶点和像素着色器提供的数据供其后的图形管线使用。
              输出关联用于指定着色器产生的数据如何链接给下一阶段的输入。
              举例来说,
              顶点着色器的输出关联将顶点着色程序运算得到的结果链接到像素着色器的输入关联上。
              顶点着色器输出关联用于将着色器连接到像素着色器和光栅阶段。
              POSITION输出是每个顶点必须输出给光栅器而不暴露给像素着色器的数据,
              TEXCOORDn和COLORn表示输出用于像素着色器进行插值。
              像素着色器输出关联将其输出颜色绑定给正确的渲染目标。
              颜色输出被连接到alpha混合阶段。
              DEPTH输出关联用于改变当前光栅化位置的目标深度值。
              输出关联语义同输入关联的声明相同。


              IP属地:重庆8楼2020-10-07 17:22
              回复
                【三种不同的像素着色器】
                //三种方法从像素着色器输出
                PSOUT PSFunc1(){...}
                void PSFunc2(out float4 Color:COLOR,out float Depth:DEPTH){...}
                void PDFunc3(out PS_OUT Out){...}
                #一个着色器例子:
                float4x4 view_proj_matrix;
                float4 view_position;
                float4 light0;
                float4 light1;
                float4 light2;
                struct VS_OUTPUT
                {
                float4 Pos :POSITION;
                float3 view :TEXCOORD0;
                float3 Normal :TEXCOORD1;
                float3 Light1 :TEXCOORD2;
                float3 Light2 :TEXCOORD3;
                float3 Light3 :TEXCOORD4;
                };
                VS_OUTPUT main(float4 inPos:POSITION, float3 inNorm:NORMAL)
                {
                VS_OUTPUT out = (VS_OUTPUT) 0;
                out.Pos = mul(view_proj_matrix, inPos);
                out.Normal = inNorm;
                out.View = normalize(view_position - inPos);
                out.Light1 = normalize(light0 - inPos);
                out.Light2 = normalize(light1 - inPos);
                out.Light3 = normalize(light2 - inPos);
                return out;
                }
                #这个顶点着色器在开头声明几个全局域的变量,
                他们都隐式的声明为uniform,
                因此他们可以被API和着色器访问。
                接着我们看到一个VS_OUTPUT结构体,由结构体定义可知顶点着色器除了除数一个4D位置信息,还将输出5个3D纹理坐标信息。
                现在来看main函数,
                由一个4D向量作为位置输入,
                一个3D向量作为法向量输入。
                inPos通过mul函数操作,
                但是inNorm并没有被使用。
                最后,经过干函数运算的数据将会在多边形中进行插值。


                IP属地:重庆10楼2020-10-07 17:24
                回复


                  来自Android客户端11楼2020-10-07 17:26
                  回复
                    【着色器编译演示】
                    #下面我们来着手编译下这个文件。
                    首先,
                    我们将上面代码复制进一个文本文件并重命名为NPRMetallic.vhl。
                    然后在命令行输入如下命令:
                    "fxc -nologo -T vs_1_1 -Fc -Vd NPRMetallic.vhl".
                    因为这个顶点着色器不要求流控制,
                    我们选用vs_1_1编译目标.
                    #输出如下:
                    //
                    // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
                    //
                    // fxc -nologo -T vs_1_1 -Fc -Vd j:\NPRMetallic.vhl
                    //
                    //
                    // Parameters:
                    //
                    // float4 light0;
                    // float4 light1;
                    // float4 light2;
                    // float4 view_position;
                    // float4x4 view_proj_matrix;
                    //
                    //
                    // Registers:
                    //
                    // Name Reg Size
                    // ---------------- ----- ----
                    // view_proj_matrix c0 4
                    // view_position c4 1
                    // light0 c5 1
                    // light1 c6 1
                    // light2 c7 1
                    //
                    vs_1_1
                    dcl_position v0
                    dcl_normal v1
                    mul r0, v0.y, c1
                    mad r0, c0, v0.x, r0
                    mad r0, c2, v0.z, r0
                    mad oPos, c3, v0.w, r0
                    add r0, -v0, c4
                    dp4 r0.w, r0, r0
                    rsq r0.w, r0.w
                    mul oT0.xyz, r0.w, r0
                    add r0, -v0, c5
                    dp4 r0.w, r0, r0
                    rsq r0.w, r0.w
                    mul oT2.xyz, r0.w, r0
                    add r0, -v0, c6
                    dp4 r0.w, r0, r0
                    rsq r0.w, r0.w
                    mul oT3.xyz, r0.w, r0
                    add r0, -v0, c7
                    dp4 r0.w, r0, r0
                    rsq r0.w, r0.w
                    mul oT4.xyz, r0.w, r0
                    mov oT1.xyz, v1
                    // approximately 21 instruction slots used
                    代码上方是顶点着色器的输入参数,
                    这些参数需要通过API来设定以使着色器正常工作。
                    下面一个部分是硬件寄存器的分配。
                    租后是汇编指令,
                    一共21条。
                    现在不必要从头读到尾,
                    但应该注意dcl_position,dcl_normal两个语句,
                    他们代表这main函数的两个参数。
                    另外注意输出结果放在oPos,oT0~4这些输出寄存器中。
                    现在我们需要使用顶点着色器把几何体变换到剪裁空间并定义那些将会在多边形插值用用到的值。
                    #下面我们来进行像素着色:
                    float4 Material;
                    sampler Outline;
                    float4 main(float3 View:TEXCOORD0,
                    float3 Normal:TEXCOORD1,
                    float3 Light1:TEXCOORD2,
                    float3 Light2:TEXCOORD3,
                    float3 Light3:TEXCOORD4):COLOR
                    {
                    //标准化输入向量
                    float3 norm = normalize(Normal);
                    float4 outline = tex1D(Outline, 1 - dot(norm, normalize(View)));
                    float lighting = (dot (normalize(Light1), norm)*0.5 + 0.5) +
                    (dot (normalize(Light2), norm)*0.5 + 0.5) +
                    (dot (normalize(Light3), norm)*0.5 + 0.5) ;
                    return outline*Material*lighting;
                    }
                    使用“fxc -nologo -T ps_2_0 -Fc -Vd NPRMetallic.phl”
                    #编译产生的代码如下:
                    //
                    // Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111
                    //
                    // fxc -nologo -T ps_2_0 -Fc -Vd J:\shader\NPRMetallic.phl
                    //
                    //
                    // Parameters:
                    //
                    // float4 Material;
                    // sampler2D Outline;
                    //
                    //
                    // Registers:
                    //
                    // Name Reg Size
                    // ------------ ----- ----
                    // Material c0 1
                    // Outline s0 1
                    //
                    ps_2_0
                    def c1, 1, 0.5, 0, 0
                    dcl t0.xyz
                    dcl t1.xyz
                    dcl t2.xyz
                    dcl t3.xyz
                    dcl t4.xyz
                    dcl_2d s0
                    nrm r0.xyz, t2
                    nrm r1.xyz, t1
                    dp3 r1.w, r0, r1
                    mad r1.w, r1.w, c1.y, c1.y
                    nrm r0.xyz, t3
                    dp3 r0.x, r0, r1
                    mad r1.w, r0.x, c1.y, r1.w
                    add r1.w, r1.w, c1.y
                    nrm r0.xyz, t4
                    dp3 r0.x, r0, r1
                    mad r1.w, r0.x, c1.y, r1.w
                    add r1.w, r1.w, c1.y
                    nrm r0.xyz, t0
                    dp3 r0.x, r1, r0
                    add r0.xy, -r0.x, c1.x
                    texld r0, r0, s0
                    mul r0, r0, c0
                    mul r0, r1.w, r0
                    mov oC0, r0
                    // approximately 29 instruction slots used (1 texture, 28 arithmetic)
                    跟顶点着色器相同,开头全局域的变量需要使用API来置.
                    在ps_2_0指令后,
                    有一个def指令。
                    这个指令是汇编指令流中
                    的自由指令,
                    他定义了ALU运算使用到的常数。
                    这种常数一般
                    是HLSL着色器中出现的字面值,


                    IP属地:重庆12楼2020-10-07 17:26
                    回复
                      #比如以下代码段:
                      1 - dot (norm, normalize(view)
                      dot (nomalze(Light1), norm)*0.5 + 0.5
                      在常量定义之后,
                      有5个3d纹理坐标声明,
                      型如dcl tn.xyz.
                      这些是main函数参数的输入关联。
                      紧接着是一个采样器声明:dcl_2d s0,
                      表明0号采样器绑定了一个2D纹理。
                      texld表明纹理坐标只有其中一个元素需要处理。


                      IP属地:重庆13楼2020-10-07 17:27
                      回复
                        欢迎各位学习,资料源于网络,整理来自SC所写


                        IP属地:重庆15楼2020-10-07 17:32
                        回复


                          IP属地:广东来自Android客户端16楼2020-10-08 11:58
                          回复
                            硬核硬核,学不来


                            来自Android客户端17楼2020-10-17 05:08
                            回复
                              ddd


                              IP属地:陕西来自Android客户端18楼2020-10-27 21:32
                              回复