基础知识:如下所示:
1.HLSL中所有的函数都是内联函数。
2.HLSL中没有引用和指针的概念,所以需要借助结构体或多个输出参数才能够从函数中返回多个数值。
变量类型:如下所示:
1.标量类型如表所示:
名称 | 说明 |
---|---|
bool | 取值非真即假。HLSL为此而提供了类似于C++语言中的true与false关键字。 |
int | 32位有符号整数,平台不支持时就用float类型进行模拟。 |
half | 16位浮点数,平台不支持时就用float类型进行模拟。 |
float | 32位浮点数。 |
double | 64位浮点数,平台不支持时就用float类型进行模拟。 |
2.向量类型如表所示:
名称 | 说明 |
---|---|
float2 | 2D向量,其中的分量都是float类型。 |
float3 | 3D向量,其中的分量都是float类型。 |
float4 | 4D向量,其中的分量都是float类型。 |
具有以下特性:
1>.可以通过与数组或者构造函数相似的语法来初始化向量。参考代码如下所示:
// 数组方式初始化向量
float3 v = {1.0f, 2.0f, 3.0f};
// 构造函数方式初始化向量
float2 w = float2(1.0f, 2.0f);
float4 u = float4(w, 3.0f, 4.0f); // 等价于u = {w.x, w.y, 3.0f, 4.0f}
2>.可以通过数组下标语法来访问向量中的分量。参考代码如下所示:
// 设置向量vec中第i个分量值为2.0f
vec[i] = 2.0f;
3>.可以通过规定的分量名x,y,z,w,r,g,b,a像访问结构体成员那样访问向量的各分量。参考代码如下所示:
// x, y, z, w分量通常用来代表位置;r, g, b, a分量通常代表颜色;两者都表示向量中第1 ~ 4个分量。
vec.x = vec.r = 1.0f;
vec.y = vec.g = 2.0f;
vec.z = vec.b = 3.0f;
vec.w = vec.a = 4.0f;
4>.可以通过重组的方式来初始化和访问向量。参考代码如下所示:
float4 u = {1.0f, 2.0f, 3.0f, 4.0f};
float4 v = {0.0f, 0.0f, 5.0f, 6.0f};
// 等价于:v.x = u.w; v.y = u.y; v.z = u.y; v.w = u.x。
v = u.wyyx; // v = {4.0f, 2.0f, 2.0f, 1.0f};
// 等价于:v.x = u.x; v.y = u.y。
v.xy = u; // v = {1.0f, 2.0f, 2.0f, 1.0f};
3.矩阵类型具有以下特性:
1>.可以通过“标量类型+行数m+列数n”来定义mxn矩阵,如:float2x2,half2x2,int2x2等。
2>.可以通过vector与matrix来定义4x4矩阵。
3>.可以通过二维数组的双下标语法来访问矩阵中的项。参考代码如下所示:
// 对矩阵M对象中的第i行第j列赋值为value变量值。
M[i][j] = value;
4>.可以通过一维数组的单下标语法来访问矩阵中对应的行向量。参考代码如下所示:
// 获取矩阵中指定行i的行向量
float3 ithRow = M[i];
// 对矩阵中第1 ~ 3行向量进行赋值
float3 T = float3(1.0f, 2.0f, 3.0f);
float3 B = float3(4.0f, 5.0f, 6.0f);
float3 N = float3(7.0f, 8.0f, 9.0f);
M[0] = T;
M[1] = B;
M[2] = N;
5>.可以通过以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;
6>.可以通过以0作为基准值索引的方式来访问矩阵中的项。参考代码如下所示:
M._m00 = M._m01 = M._m02 = M._m03 = 0.0f;
M._m10 = M._m11 = M._12 = M._13 = 0.0f;
M._m20 = M._m21 = M._m22 = M._m23 = 0.0f;
M._m30 = M._m31 = M._m32 = M._m33 = 0.0f;
4.数组类型可以通过类似C++的语法来声明。参考代码如下所示:
float M[4][4];
half P[4];
float3 V[12];
5.结构体与C++中定义结构体的方式基本上完全一致,区别仅在于HLSL中的结构体不具有成员函数。参考代码如下所示:
struct SurfaceInfo
{
float3 pos;
float3 normal;
float4 diffuse;
float4 spec;
};
SurfaceInfo v;
litColor += v.diffuse;
dot(lightVec, v.normal);
float specPower = max(v.spec.a, 1.0f);
6.typedef关键字与C++中的功能完全相同,用来将一个类型定义成另外一个别名。参考代码如下所示:
// 将float3类型定义成point类型
typedef float3 point;
point myPoint; // 等价于float3 myPoint
7.变量的修饰符如下表所示:
名称 | 说明 |
---|---|
static | 着色器变量对于C++应用程序而言是不可见的。 |
extern | 着色器变量对于C++应用程序而言是可见的。 |
const | 着色器变量的值不可更改。 |
uniform | 着色器变量的值可以在C++应用层更改;在着色器执行的过程中始终保持不变。 |
8.强制类型转换语法与C编程语言中的相同。参考代码如下所示:
float f = 5.0f;
float4x4 m = (float4x4)f; // 将浮点数f复制到矩阵m中的每一个元素中
关键字:如下所示:
1.已使用的关键字有:asm,bool,compile,const,decl,do,double,else,extern,flase,float,for,half,if,in,inline,inout,int,matrix,namespace,out,pass,pixelshader,return,register,sampler,shared,static,string,struct,technique,texture,true,typedef,uniform,vector,vertexshader,void,volatile,while。
2.保留或未使用的关键字有:auto,case,catch,char,class,const_cast,default,delete,dynamic_cast,enum,explicit,friend,goto,long。mutable,new,operator,private,protected,public,reinterpret_cast,short,signed,sizeof,static_cast,unsigned,using,virtual。
运算符:如下所示:
1.已使用的运算符如下表所示:
[] | . | > | < | <= | >= | != | == | ! |
---|---|---|---|---|---|---|---|---|
&& | || | ?: | + | += | - | -= | * | *= |
/ | /= | % | %= | ++ | – | = | () | , |
2.取模运算符%既可以用于整数也能用于浮点数,且左右操作数都具有相同的符号。
3.向量和矩阵类型可以按照分量为基准进行运算。参考代码如下所示:
float4 u = {1.0f, 2.0f, 3.0f, 4.0f};
float4 v = {5.0f, 2.0f, 7.0f, 4.0f};
float4 sum = u + v; // 等价于{u.x + v.x, u.y + v.y, u.z + v.z, u.w + v.w}
float4 b = (u == v); // 等价于{u.x == v.x, u.y == v.y, u.z == v.z, u.w == v.w} = {false, true, false, true}
4.对于二元运算来说,如果运算符左右操作数的维度不同,那么维度较小的变量类型将会按照自动转换定义被提升为维度较大的变量类型。
5.对于二元运算来说,如果运算符左右操作数的类型不同,那么低精度变量的类型将被提升为高精度变量的类型。
控制流:如下所示:
1.return语句参考代码如下所示:
return (expression);
2.if与if…else语句参考代码如下所示:
if (condition) {
statement(s);
}
if (condition) {
statement(s);
} else {
statement(s);
}
3.for语句参考代码如下所示:
for (initial; condition; increment) {
statement(s);
}
4.while与do…while语句参考代码如下所示:
while (condition) {
statement(s);
}
do {
statement(s);
} while(condition);
函数:如下所示:
1.内置函数:具有以下特性:
1>.常用的内置函数如下表所示:
函数 | 描述 |
---|---|
abs(x) | 返回|x|。 |
ceil(x) | 返回>=x的最小整数。 |
floor(x) | 返回<=x的最大整数 |
cos(x) | 返回x的余弦值,x为单位弧度。 |
sin(x) | 返回x的正弦值,x的单位为弧度。 |
sincos(in x, out s, out c) | 返回x的正弦值和余弦值,x的单位为弧度。 |
tan(x) | 返回x的正切值,x的单位为弧度。 |
clamp(x, a, b) | 将x钳制在范围[a, b]内,并返回结果。 |
clip(x) | 此函数仅限于在像素着色器中调用,如果x<0,就将当前的像素从后续的处理流程中丢弃。 |
cross(u, v) | 返回u x v(二向量之叉积)。 |
dot(u, v) | 返回u · v(二向量之点积)。 |
ddx(a) | 估算屏幕空间中的偏导数σp / σx。这使我们可以确定在屏幕空间的x轴方向上,相邻像素间某属性值a的变化量。 |
ddy(a) | 估算屏幕空间中的偏导数σp / σy。这使我们可以确定在屏幕空间的y轴方向上,相邻像素间某属性值a的变化量。 |
degrees(x) | 将x从弧度转换为角度。 |
radians(x) | 将x从角度转换为弧度。 |
determinant(M) | 返回矩阵M的行列式。 |
distance(u, v) | 返回点u与点v之间的距离||v - u ||。 |
frac(x) | 此函数返回的是目标浮点数的小数部分(即尾数)。 |
length(v) | 返回||v||(向量的模)。 |
lerp(u, v, t) | 基于参数t ∈[0, 1],在u和v之间进行线性插值。 |
log(x) | 返回ln(x)。 |
log10(x) | |
log2(x) | |
max(x, y) | 如果x>=y返回x;否则返回y。 |
min(x, y) | 如果x<=y返回x;否则返回y。 |
mul(M, N) | 返回矩阵乘积MN。 |
normalize(v) | 返回v / ||v||。 |
pow(b, n) | 返回bⁿ。 |
saturate(x) | 返回clamp(x, 0.0, 1.0)。 |
sqrt(x) | 返回x开平方。 |
rsqrt(x) | 返回1除以x的开平方。 |
reflect(v, n) | 根据给出的表面法线n和入射向量v来计算反射向量。 |
refract(v, n, eta) | 根据给出的表面法线n,入射向量v以及两种材质的折射率之比eta来计算折射向量。 |
transpose(M) | 返回矩阵M的转置矩阵。 |
Texture2D::Sample(S, texC) | 根据SamplerState对象S与2D纹理坐标texC,返回2D纹理图中相应的颜色数据。 |
Texture2D::SampleLevel(S, texC, mipLevel) | 根据SamplerState对象S,2D纹理坐标texC以及mipmap层级mipLevel,从2D纹理图中返回相应的颜色数据。 |
TextureCube::Sample(S, v) | 根据SamplerState对象S以及3D查找向量v来返回立方体图中相应的颜色数据。 |
Texture2DArray::Sample(S, texC) | 根据SamplerState对象S与3D纹理坐标texC(前两个坐标为普通的2D纹理坐标,而第三个坐标则用于指定数组的索引),返回2D纹理数组中相应的颜色。 |
2>.大多数的内置函数能以重载的方式使所有内置类型的计算变得有意义。如:lerp函数可以使标量,2D,3D以及4D向量的计算均有意义。
3>.如果以标量函数来对非标量类型进行计算,那么该函数将对每个分量依次展开运算。参考代码如下所示:
float3 v = float3(0.0f, 0.0f, 0.0f);
v = cos(v); // 等价于v=(cos(x), cos(y), cos(z))