DirectX 3D_基础之HLSL(高级着色语言) HLSL着色器程序的编制 HSLS变量 HLSL入口函数 HLSL程序编译 变量常量类型 设置方法 前缀 关键字 类型 语句 类型转换

来源:互联网 发布:网络营销服务seo 编辑:程序博客网 时间:2024/06/10 07:14

             每日一语:

 

              呆在这样的公司,的确没有什么积累,但我却应该庆幸这一段经历,不管什么东西都是有其两面性的,有得就有失,有成就有败。如果,之前没有进入这样的公司,没有这段经历,我就不会接触到手机,而且对Windows驱动有了更加深刻的认识,提高了动手实践能力。对Windows底层有了更深层次的认识。给自己的产品以及行业经验增加很重的砝码。

 

              正文:

 
             
高级着色语言:HLSL (High-Level Shading Language).
 
              接下来,我们来介绍使用HLSL来编写顶点着色器和像素着色器程序。简单来说,顶点着色器和像素着色器就是我们自行编写的一些小规模的定制程序,这些定制程序可取代固定功能流水线中某一功能模块,并可在图形卡的GPU中执行。通过这种功能替换,我们便在实行图形效果时获得了巨大的灵活性。HLSL是在DirectX 9中出现的。

 

              有一点需要注意,如果你的图形卡不支持顶点着色器和像素着色器,在运行程序时,务必切换到REF设备。

 注意:顶点着色器可用软件顶点运算方式来模拟,即在创建设备时,将设备行为标记设定为

D3DCREATE_SOFTWARE_VERTEXPROCESSING.


  
                HLSL着色器程序的编制:

 

             HLSL着色器程序可以一个长字符串的形式出现在应用程序的源文件中,但更方便也更模块化的做法是将着色器代码与应用程序代码分离。基于上述考虑,我们可在记事本中编写着色器代码,并将其保存为常规的ASCII文本文件。接下来就可以使用函数D3DXComplieShaderFromFile对着色器文本进行编译了。

 

             我们下面看一下,简单的的用HLSL编写的顶点着色器程序,这段程序对顶点实施了取景变换和投影变换,并将顶点的漫反射颜色分量设置为蓝色。我们主要是熟悉HLSL的语法和格式。
 
                                     matrix ViewProjMatrix;

 

                                     vector Blue = {0.0f,0.0f,1.0f,1.0f};

 

                                     struct VS_INPUT
                                    {
                                               vector position : POSITION;
                                    };

 

                                     struct VS_OUTPUT
                                    {
                                                vector position : POSITION;


                                                vector diffuse :  COLOR;
                                    };

 

                                    VS_OUTPUT Main(VS_INPUT input)
                                    {
                                                VS_OUTPUT output = (VS_OUTPUT)0;
 
                                                output.position = mul(input.position,ViewProjMatrix);

 

                                                output.diffuse = Blue;
 
                                                return output;
                                   }

                全局变量:
 
                首先我们来实例化两个全局变量。
 
                           matrix ViewProjMatrix;


                           vector Blue = {0.0f,0.0f,1.0f,1.0f};

 

                第一个变量ViewProjMatrix,是一个matrix类型的实例。该类型是HLSL中的内置类型,表示维数为4x4的矩阵。该变量存储了取景变换矩阵和投影变换矩阵的乘积,这样它就同时描述了两种交换。所以,我们只需进行一次向量矩阵乘法就可实现上述两种变换。注意,我们在着色器源代码中是找不到这些变量的初始化代码的。这是因为这些变量的初始化应在应用程序源代码中进行而非着色器程序代码中。应用程序与着色器程序之间经常需要进行数据通信的。

               第二个变量Blue,是HLSL内置类型vector的一个实例,该类型表示一个4D向量。

 

               输入和输出结构:

 

              声明了全局变量以后,我们定义了两种特殊的结构,称为输入输出结构。对于顶点着色器,这些结构分别定义了该着色器的输入和输出的顶点数据(即输入输出顶点的结构)

 

                          struct VS_INPUT
                          {
                                  vector position : POSITION;
                          };
 
                         struct VS_OUTPUT
                         {
                                 vector position : POSITION;


                                 vector diffuse  : COLOR;
                        };

 

             注意:像素着色器的输入和输出结构定义了像素的数据格式。
 
             在本例中,顶点着色器的输入顶点包含了一个位置分量。而顶点着色器的输出顶点中不但包含了位置分量,还包含了颜色分量。


             上面出现的和特别的冒号语法表达了一种语意,用来指定变量的用途。这与顶点结构中的灵活顶点格式(FVF)非常类似。

 

              从底层的观点看,语义语法建立了着色器中的变量与硬件寄存器之间的联系,即输入变量总是与输入寄存器项联系的,而输出变量总是与输出寄存器相联系的。例如,VS_INPUT结构的程序position将被连接到一个特定的顶点输入位置寄存器,类似地,VS_OUTPUT结构中的diffuse成员将被连接到一个特定的顶点输出颜色寄存器中。

 

              入口函数:

 

              像C++程序一样,每个HLSL程序也应该有一个入口点。在上面的着色器例程中,入口函数为Main。但是,该名称并非强制性的。在遵循函数命名规则的前提下,着色器入口函数的命名可以自由选择。入口函数必须有一个输入结构的参数,该参数将用于把输入顶点传给着色器,而且入口函数必须返回一个输出结构的实例,用来将经过处理的顶点自着色器输出。

 

              实际上,输入和输出结构的使用并非是强制性的。例如,有时会遇到类似这样的语法,该用法在像素着色器程序中尤为常见:

                             float4 Main(in float2 base:TEXCOORD0,
                                             in float2 spot:TEXCOORD1,
                                             in float2 text:TEXCOORD2):COLOR
                           {

                           }

 

 

               这些参数被输入到着色器中,在该例中,我们输入了3个纹理坐标。着色器将返回一个单个颜色作为输出,这是通过在函数签名后 ":COLOR",从语义层面表示的,该定义等价于:

 

                             struct INPUT
                             {
                                     float2 base : TEXCOORD0;
                                     float2 spot : TEXCOORD1;
                                     float2 text : TEXCOORD2;
                             };

 

                             struct OUTPUT
                            {
                                    float4 c : COLOR;
                            } 

 

                            OUTPUT Main(INPUT input)
                            {
                                          ....
                            }
 
                入口函数主要是负责依据输入顶点计算输出顶点。本例中,着色器要完成的任务仅仅是将顶点变换到观察坐标系继而变换至投影坐标系中,将顶点漫反射颜色设置为蓝色,最后将经过上述运算的顶点返回。首先,我们对一个VS_OUTPUT结构进行了实例化,并将该实例的各成员设为0.

 

                             VS_OUTPUT output = (VS_OUTPUT)0;


 
                然后;该着色器借助函数mul将输入顶点的位置向量与变量ViewProjMatrix相乘,从而实现顶点位置的变换,其中mul是HLSL的内置函数,它既可进行向量矩阵乘法,也可进行矩阵矩阵乘法,我们将经过变换的向量保存在输出结构实例的位置向量成员中。


 
                             output.position = mul(input.positon,ViewProjMatrix);

 

                接下来,我们将output的漫反射颜色成员设置为Blue.

 

                              output.diffuse = Blue;

 

                最后,返回输出顶点:


 
                            
   return output;
                              }

 

                HLSL着色器程序的编译:

 

                常量表:

 

                每个着色器都用常量表来存储器变量。为了使应用程序能够访问着色器的常量表。D3DX库提供了接口ID3DXConstantTable。借助该接口,我们可在应用程序源代码中对着色器源代码中的变量进行设置。

 

                现在,我们选取ID3DXConstantTable接口所实现的部分函数进行讲解。
  
               1,获取常量的句柄

 

               为了从应用程序的源代码中对着色器程序中的某个变量进行设置,我们需要用某种方式来引用该变量。D3DXHANDLE类型的句柄恰合此意。当给定着色器中我们期望引用的那个变量的名称时,下面的函数将返回一个引用了该变量的D3DXHANDLE类型的句柄。

 

                               D3DXHANDLE ID3DXConstantTable::GetConstantByName(
                                                                                         D3DXHANDLE hConstant,
                                                                                         LPCSTR pName
                                                                                 };

 

                hConstant : 一个D3DXHANDLE类型的句柄,标识了那个包含了我们希望获取其句柄的变量的父结构。例如,如果我们希望得到某个特定结构实例的一个单个数据成员的句柄,可为该参数传入该结构实例的句柄。如果想要获取指向顶级变量的句柄,应将该参数指定为0.

 

                pName : 我们希望获取其句柄的那个着色器源代码中的变量的名称。


 
                例如,如果期望引用的着色器中的变量名称为ViewProjMatrix,且该变量为顶级参数,我们可这样实现引用

                D3DXHANDLE h0;

 

                h0 = ConstTable -> GetConstantByName(0, "ViewProjMatrix");


 
                 常量的设置:

 

                 一旦应用程序获取了着色器代码中希望被引用的那个变量的D3DXHANDLE类型的句柄,我们就可在应用程序中使用方法ID3DXConstantTable::SetXXX对该变量进行设置,其中SetXXX表示被设置变量的类型名称,实际调用时只要用类型名称将其替换即可。例如,如果我们希望设置的变量为一个vector类型的数组,该方法对应SetVectorArray。

                              方法ID3DXConstantTable :: SetXXX的通用签名为:

 

                                    HRESULT ID3DXConstantTable::SetXXX(
                                                                LPDIRECT3DDEVICE9 pDevice,
                                                                D3DXHANDLE hConstant,
                                                                XXX value
                                                                }:

 

                                     pDevice 与常量表相关的设备指针。


 
                                     hConstant 我们想要设置的那个变量的句柄。

 

                                     value 指定了我们引用的那个着色器中的变量应被赋为何值,其中XXX应替换为该变量的类型名。对于某些类型(bool,int,float),我们传入的是该值的一个副本,而对另外一些类型(向量,矩阵,结构体),我们传入的是指向该值的指针。

 

                 如果要对数组进行设置,SetXXX方法还应增加一个参数,接收该数组的维数。例如,用于设置一个4D向量的数组的方法原型为:


                          HRESUTL ID3DXConstantTable::SetVectorArray(
                                                                          LPDIRECT3DEVICE9 pDevice,
                                                                          D3DXHANDLE hConstant,
                                                                          CONST D3DXVECTOR4* pVector,
                                                                          UINT Count
                                                                      )


               下面的列表描述了可用接口ID3DXConstantTable进行设置的类型。假定我们已经拥有了一个合法的设备指针以及所要设置的变量的句柄。

 

               SetBool  用于设置一个布尔值。调用实例:

               bool b = true;
               ConstTable -> SetBool(Device,handle,b);

 

               SetBoolArray 用于设置布尔数组,调用实例:

               bool b[3] = {true,false,true};
               ConstTable -> SetBoolArray(Device,handle,b,3);

 

               SetFloat 用于设置一个浮点数,调用实例:

               float f = 3.14f;
               ConstTable -> SetFloat(Device,handle,f);

 

               SetFloatArray 用于设置一个浮点数组,调用实例;


               float f[2] = {1.0f,2.0f};
               ConstTable -> SetFloatArray(Device,handle,f,2);

 

               SetInt 用于设置一个整数,调用实例:


               int x = 4;
               ConstTable -> SetInt(Device,handle,x);

 

               SetIntArray 用于设置一个整数数组,调用实例:


               int x[4] = {1,2,3,4};
               ConstTable -> SetIntArray(Device,handle,x,4);

 

               SetMatrix 用于设置一个4X4矩阵,调用实例:


               D3DXMATRIX M(..);
               ConstTable -> SetMatrix(Device,handle,&M);

 

              SetMatrixArray 用于设置一个4X4矩阵数组,调用实例:


              D3DXMATRIX M[4];
              ConstTable -> SetMatrixArray(Device,handle,M,4);

 

              SetMatrixPointerArray 用于设置一个4X4矩阵的指针数组,调用实例:

              D3DXMATRIX * M[4];
              ConstTable -> SetMatrixPointerArray(Device,handle,M,4);

 

              SetMatrixTranspose 用于设置一个4X4的转置矩阵,调用实例:


              D3DXMATRIX M(...);
              D3DXMatrixTranspose(&M,&M);
              ConstTable -> SetMatrixTranspose(Device,handle,&M);

 

              SetMatrixTransposeArray 用于设置一个4X4的转置矩阵数组,调用实例:


              D3DXMATRIX M[4];
              ConstTable -> SetMatrixTransposeArray(Device,handle,M,4);

 

              SetMatrixTransposePointerArray 用于设置4X4的转置矩阵的数组指针,调用实例:


 

              D3DXMATRIX *M[4];
              ConstTable -> SetMatrixTransposePointerArray(Device,handle,M,4);

 

              SetVector 用于设置一个D3DXVECTOR4类型的变量,调用实例:


 

              D3DXVECTOR4 v(1.0f,2.0f,3.0f,4.0f);
              ConstTable -> SetVector(Device,handle,&v);

 

              SetVectorArray 用于设置向量数组类型的变量,调用实例:


 

              D3DXVECTOR4 v[3];
              ConstTable -> SetVectorArray(Device,handle,v,3);

 

              SetValue 用于设置大小任意的类型,例如结构体。在下面的调用中,我们用该函数对一个D3DXMATRIX类型的变量进行了设置。


                              D3DXMATRIX M(...);
 
                              ConstTable -> SetValue(Device,handle,(void *)&M,sizeof(M));

 

               设置常量的默认值:
 
              下面的方法仅是将常量设置为默认值,即那些在变量声明时被赋予的初值。该方法在应用程序的设置过程中,应调用一次。
  
                             HRESULT ID3DXConstantTable::SetDefault(
                                                               LPDIRECT3DEVICE9 pDevice
                                                                );

 

               HSLS着色器程序的编译:


 
               我们可用如下函数对保存在文本文件中的着色器程序进行编译:

 

 

                               HRESULT D3DXComplieShaderFromFile(
                                                                       LPCSTR pSrcFile,
                                                                       CONST D3DXMACRO* pDefines,
                                                                       LPD3DXINCLUDE pInclude,
                                                                       LPCSTR pFuntionName,
                                                                       LPCSTR  pTarget,
                                                                       LPCSTR  Flags,
                                                                       LPD3DXBUFFER* ppShader,
                                                                       LPD3DXBUFFER* ppErrorMsgs,
                                                                       LPD3DXCONSTANTTABLE* ppConstantTable
                                                                       );


 
                              pSrcFile 我们想要进行编译的,保存了着色器源代码的那个文本文件的名称。


  
                              pDefines 该参数可选,我们将该参数设置为NULL.


 
                              pInclude 指向ID3DXInterface接口的指针。应用程序应实现该接口,以重载默认的include行为。通常,默认的include行为已足够满足要求,我们将其指定为NULL.

 

                              pFunctionName 一个指定了着色器入口函数名称的字符串。例如,如果着色器的入口函数为Main,该参数应赋为"Main";

 

                              pTarget 指定了要将HLSL源代码编译成的着色器版本,该参数为一字符串。合法的顶点着色器版本有,vs_1_1,vs_2_0,vs_2_sw.合法的像素着色器的版本有:ps_1_1,ps_1_2,ps_1_3,ps_1_4,ps_2_0,ps_2_sw.例如,如果我们想将将顶点着色器编译为2.0版本,则需要将该参数指定为vs_2_0.

 

                             注意,这种能编译为不同着色器版本的能力是HLSL比汇编语言的一个重大优势。

 

                              Flags 可选的编译选项。若该参数为0,表示不使用任何选项。合法的选项包括:

 

                                         D3DXSHADER_DEBUG 指示编译器写入调试信息。


                                         D3DXSHADER_SKIPVALIDATION 指示编译器不要进行任何代码验证。仅当正在使用一个已确定可用的着色器时,该参数才使用。


 

                                         D3DXSHADER_SKIPOPTIMIZATION 指示编译器不要对代码进行任何优化。实际上,仅在调试时该选项有用,因为调试时不希望编译器对代码做任何改动。

 

                           ppShader 返回一个指向接口ID3DXBuffer的指针,该接口包含了编译后的着色器代码。然后,编译后的着色器代码就可作为另一个函数的参数来创建实际的顶点着色器或像素着色器。


 
                          ppErrorMsgs 返回一个指向接口ID3DXBuffer的指针,该接口包含了一个存储了错误代码和消息的字符串。

 

                          ppConstantTable 返回一个指向接口ID3DXConstantTable的指针,该接口包含了该着色器的常量表数据。

 

              变量类型:

 

 

             HLSL支持下列标量类型:


 
                       bool 布尔值,注意,HLSL提供了关键词true和false.
                       int 32位的有符号整数。

                       half 16位的浮点数。

                       float 32位的浮点数。

                       double 64位的浮点数。

 

                       向量类型:

                       HLSL支持下列向量类型:

                       vector 一个4D向量,其中每个元素的类型都是float.
 
                       vector<T,n> 一个n维向量,其中每个元素的类型均为标量类型T.维数n必须介于1~4之间。下面是一个二维double型向量的例子。


                                   vector(double,2) vec2;

 

                        我们可通过数组下标语法来访问向量的每个元素。例如,要想对向量vec中的第i个元素进行设置,可这样做:

                                      vec[i] = 2.0f;

 

                        此外,借助一些已定义的分量名x,y,z,w,r,g,b,a,我们还可像访问结构体中成员那样访问向量vec的分量:

                                       vec.x = vec.r = 1.0f;等等。

                        这些名称r,g,b,a与想x,y,z,w一样,分别精确地指向同一分量,当用向量表示颜色时,我们要倾向于使用RGBA表示法,因为这将有助于强调该向量代表了某种颜色的事实。我们还可使用其他预定义类型来分别表示2D向量,3D向量和4D向量。
 
                                        float2 vec2;

                                        float3 vec3;

                                        float4 vec4;

 

                      下面考虑另外一个问题,给定向量u = (ux,uy,uz,uw),假定我们要将向量u的各分量复制到向量v中,使得v = (ux,uy,uz,uw).最直接的方法是将u的各元素逐个复制到v中。但是HLSL提供了一种特殊的语法 "替换调配"来专门用来完成这种不关心顺序的复制操作。

 

                                        vector u = (1.0f,2.0f,3.0f,4.0f);

 

                                        vector v = (0.0f,0.0f,0.0f,0.0f);

 

                                        v = u.xyzw.

 

                        对向量进行复制时,我们不一定非要对每个分量进行复制。例如我们可仅复制x和y分量。

 

                                         v.xy = u;

 

                       矩阵类型:

 

                      HLSL具有下列内置的矩阵类型:

 

                      matrix 表示一个4X4矩阵,该矩阵中每个元素的类型均为float.

 

                      matrix<T,m,n> 表示一个m x n矩阵,其中的每个元素都为标量类型T.该矩阵的维数m和n必须介于1~4之间,例如要表示一个2x2的整数矩阵:

 

                                     matrix<int,2,2> m2x2;

 

                     我们还可用如下语法来定义一个m x n矩阵,其中m和n必须皆为1~4之间。

 

                                     floatmxn matmxn;

                                     float2x2 mat2x2;
                                     float3x3 mat3x3;
                                     float4x4 mat4x4;
                                     float2x4 mat2x4;
  
                     注意,矩阵类型可以不是float类型,我们也可使用其他类型。例如如果我们想定义整型矩阵,可以写为

                                       int2x2 i2x2;
                                       int3x3 i3x3;
                                       int2x4 i2x4;

 

                    我们可用数组的双下标来访问矩阵的各项元素。例如,要对矩阵M中的第i行,第j列的项进行设置,可以这样。
                                     M[i][j] = value;

 

                    此外,我们还可以项访问结构体中的成员那样访问矩阵M中的项,HLSL已定义了下列项名称。

 

                    下标从1开始:

 

                                   M._11 = M._12 = M._13 = M._14 = 0.0f;

                                   M._21 = M._22 = M._23 = M._24 = 0.0f;

                                   M._31 = M._32 = M._33 = M._34 = 0.0f;

                                   M._41 = M._42 = M._43 = M._44 = 0.0f;

 

                   下标从0开始:

 

                                  M._m00 = M._m01 = M._m02 = M._m03 = 0.0f;

                                  M._m10 = M._m11 = M._m12 = M._m13 = 0.0f;

                                  M._m20 = M._m21 = M._m22 = M._m23 = 0.0f;

                                  M._m30 = M._m31 = M._m32 = M._m33 = 0.0f;

 

                  有时,我们想要引用矩阵中的某一特定行,我们可通过数组单下标语法来实现。例如,要想引用矩阵M的第i行,可以这样:

                                            vector ithRow = M[i];

 

                  注意,我们可用如下两种语法对HLSL的变量进行初始化。

 

                                             vector u = (0.0f,1.0f,2.0f,3.0f);

 

                 也可以与上述方法等价的构造函数的语法。

 

                                             vector u = vector(0.0f,1.0f,2.0f.3.0f);

 

                 再举一些例子:

 

                                          float2x2 f2x2 = float2x2(1.0f,2.0f,3.0f,4.0f);

                                          int2x2 m = {1,2,3,4};

                                          int n = int(5);
 
                                          float3 x =float3(0,0,0);

 

                 数组:

 

                 我们可用C++类似的语法声明一个特定类型的数组,例如:

 

                                            float M[4]M[4];

                                            half p[4];

                                            vector v[12];

 

                 结构体:

 

                 HLSL中的结构体定义方法和C++完全相同。但是,HLSL中的结构体不允许有成员函数。下面是一个HLSL结构体的例子:

                                            struct MyStruct
                                            {
                                                     Matrix T;
                                                     vector n;
                                                     float  f;
                                                     int    x;
                                                     bool   b;
                                            }


                                            MyStruct s;
                                            s.f = 5.0f;

                关键字typedef
       
                 HLSL的typedef关键与C++中的功能完全一样,例如,我们可用如下语法为类型vector<float 3> 赋于另一个名称point.

 

                                   typedef vector<float,3> point
 
                                              point myPoint;

 

                变量的前缀:

 

                static 如果全局变量在声明时使用了关键字static,就意味着这个变量在该着色器程序外不可见。这个全局变量是该着色器程序的局部变量。如果一个局部变量在声明时使用了关键字static,则该变量与C++中的局部变量具有完全相同的行为。即,包含该局部变量的函数,在首次调用时,该变量仅初始化一次,而且在该函数的所有调用过程中,该变量都对自身的当前值进行维护(每次该函数调用结束时,该变量仍然保留了调用过程中的状态,直至主程序的生命期结束).如果在函数中没有对该变量进行初始化,该变量将自动初始化为0.

 

                                       static int x = 5;

 

                uniform 如果变量声明时使用了关键字uniform,表明该变量在该着色器之外进行初始化。例如,在C++应用程序中对该变量进行初始化,然后再作为输入传给该着色器。

 

                extern 如果变量声明时使用了关键字extern,表明该变量可在该着色器程序外进行访问,例如可由C++程序对其访问。只有全局变量可以使用extern。非静态的全局变量默认状态下是extern类型的。

 

                shared 如果变量在声明时使用了关键字shared,则提示效果框架,该变量可在多个效果之间共享。只有全局变量方可使用该关键字进行声明。
 
                volatile 如果变量在声明时使用了关键字volatile,则提示效果框架该变量将经常修改。只有全局变量方可使用该关键字进行声明。

 

               const HLSL中的const关键字跟C++中的含义完全相同。即,如果一个变量在声明时使用了const关键字,该变量即为一常量,而且在程序运行时不可被修改。

 

                                         const float pi = 3.14f;

 

              关键字,语句及类型转换:

 

              关键字:

 

              下面列出HLSL所定义的全部关键字以供参考:

              asm bool complie const decl do double else extern false float for half if in inline inout int matrix out pass pixelShader return sampler shared static string struct  technique texture true typedef uniform vector vertexShader void volatile while

 

              下面标出的标识符都是保留字且未被使用,将来可能成为关键字:

              auto break case catch char class const_cast continue default delete dynamic_cast enum explicit friend goto long mutable namespace new operator private protected public register reinterpret_cast short signed sizeof static_cast switch template this throw try typename union unsigned using virtual

 

              基本程序流程:
 
              HLSL支持许多与C++类似的语句,如选择,循环,和一般的顺序流程。这些语句的语法与C++极为类似。
 
 类型转换:
 
             HLSL支持一种灵活的类型转换机制。HLSL中的类型转换语法和C语言的完全相同。例如,如果要将float类型转换为matrix类型,可以这样做:
 
                    
                  float f = 5.0f;
                                      matrix m = (matrix)f;
 
            对于本书的各例程中所出现的各种类型转换,从语法就可以推断器含义。但是,如果想对DirectX所支持的各种类型转换全面细致了解,需要参阅SDK.

 

            运算符:

 

            HLSL支持许多与C++类似的运算符,除了下面提到了几点外,这些运算符的使用方法与C++完全相同。下面列出HLSL所支持的运算符。
 
                    [] . > < <= >= != == ! && || ?: + += - -= * *= / /= % %= ++ -- = () ,

 

           虽然这些运算符的行为与C++中的非常相似,但仍有一些差别。首先,取模运算符%适用于整型和浮点型数据。使用取模运算符时,左操作数和右操作数必须同号。

 

          其次需要注意: 许多HLSL运算都是在变量的分量级上进行的。这是由于向量和矩阵都是HLSL的内置类型,而这些类型都由若干分量组成。由于有了能够在分量级上进行运算的运算符,如向量/矩阵加法,向量/矩阵减法,向量/矩阵的相等测试等运算都可使用与标量类型相同的运算符来进行。

           比如:
 
                           vector u = {1.0f,0.0f,-3.0f,1.0f};

                           vector v = {-4.0f,2.0f,1.0f,0.0f};

                           vector sum = u + v // {-3.0f,2.0f,-2.0f,1.0f};

 

             最后,我们来讨论双目运算中的变量类型提升。

            对于双目运算,如果左操作数与右操作数的维数不同,则维数较小的操作数得到提升(类型转换),使得其维数与原先维数较大的操作数相同。例如,如果x的类型为float,y的类型为float3,则在表达式(x+y)中,x将被提升为float3类型,所以该表达式的值也是float3类型的。这种提升是按照已定义的类型转换规则进行的。在这个例子中,我们是将标量转换为向量;所以,x被提升为float3类型后,x = (x,x,x),标量到向量的转换就是这样定义。注意,如果某种类型转换没有定义,则相应的类型提升也就找不到依据而无法进行。例如,由于float2类型到float3类型的转换没有定义,所以,我们无法将float2类型提升为float3类型。

 

           对于双目运算,如果左右操作数类型不同,则具有较低类型的操作数得到提升(类型转换),使得其类型精度与原先具有较高类型精度的操作数不同。例如,如果x是int类型变量,而y是half类型变量,则在表达式(x+y)中,变量x被提升为half类型,所以该表达式的结果也将是一个half类型的值。

 

           用户自定义函数:

 

          HLSL 中的函数具有下列性质:


 
 
          函数使用与C++类似的语法
 
           参数总是按值传递
 
           不支持递归

 

           函数总是内联的

 

           HLSL还额外增加了一些专门在函数中使用的关键字。例如,请观察如下用的HLSL编写的函数。

                                 bool foo(in const bool b,out int r1,inout float r2).

            内置函数:

 

             HLSL拥有一个丰富的内置函数集,非常有助于编写3D图形程序,下面的表格列出了部分常用函数,接下来的,我们将使用其中的某些函数,如果想更多的了解HLSL的内置函数可参考SDK中的对应目录。