unity shaderlab学前准备(4)
##Unity shader学前准备之CG语言(4) Cg中的操作符与C语言中的类似(操作符的功能和写法与C相同,但用法不 尽相同),按照操作符的功能可以划分为:关系操作符、逻辑操作符、条件操作符。Cg中有一类较为独特的操作符,称为Swizzle操作符, 这个操作符用于取出 向量类型变量中的分量。
###1.关系操作符(Comparison Operators)
关系操作符,用于比较同类型数据(不同类型的基础数据需要进行类型转换,不同长度的向量,不能用于进行比较)之间的大小关系或者等价关系。Cg中有6种关系操作符,如下表所示,关系操作符的返回值类型均为bool类型。
###2.逻辑操作符(Logical Operators) Cg语言中有3种逻辑操作符,如下表所示,逻辑操作符运算后返回值类型均为bool类型。
有一点需要注意:Cg中的逻辑与&&
和逻辑或||
不存在C中的短路现 象(short-circuiting,即只用计算一个操作数的bool值即可),而是参与运算的操作数据都进行bool分析。
在Cg中,由于关系操作符以及逻辑操作符,都返回bool类型结果,所以这两种操作符有时也被统一称为boolean operator。
Cg语言表达式允许对向量使用所有的boolean operator,如果是二元操作符,则被操作的两个向量的长度必须一致。表达式中向量的每个分量都进一对一的 运算,最后返回的结果是一个bool类型的向量,长度和操作数向量一致。例如:
float3 a = float4(0.5,0.0,1.0);
float3 b = float4(0.6,-0.1,0.9);
bool3 c = a<b;
运算后向量c的结果为float3(true,false,true)
;
###3.逻辑操作符(Math Operators) Cg语言对向量的数学操作提供了内置的支持,Cg中的数学操作符有:
*; //乘法
/; //除法
~; //取反
+; //加法
-: //减法
%; //球余
++; //后继
--; //前驱
*=; //乘后赋值
/=; //除后赋值
+=; //加后赋值
-=; //减后赋值
一般情况下,人们觉得“好像只有加减乘除等运算可以对向量进行”,实际上,++、——等数学 运算符同样可以使用在向量上。所以“Cg语言对向量的数学操作提供内置支持”这句话是非常准确的。
注意:求余操作符%
只能在int
数据类型之间进行,否则编译器会提示错误信息:
error C1021: operands to “%” must be integral.
菊长PS:你没看错,就是error C1021,其实NVIDIA的Cg编译器还有Cuda编译器都是基于GCC编译器。
当使用这些数学操作符对一个标量和一个向量进行运算时,标量首先被复制到一个长度相同的向量中,然后进行运算,比如如下形式是正确的:
void function() {
float2 a = float2(1.0, 1.0);
float b = 2.0;
f *= d;
f *= 2.0;
}
###4.位移操作符
Cg语言中的移位操作符,功能和C语言中的一样,也可以作用在向量上,但 是向量类型必须是int类型。例如:
int2 a = int2(0.0,0.0);
int2 b = a>>1;
但如果不是整形,比如下例代码:
float2 a = int2(0.0,0.0);
float2 b = a>>1;
就会报如下错误:
error C1021:operands to “shr” must be integral.
###5.Swizzle 操作符
Cg语言中可以使用swizzlw操作符.
将一个向量成员取出组成一个新的向量。swizzle操作符被GPU硬件高效支持。swizzle操作符后接x、y、z、w,分别表示原始向量的第一个、第二个、第三个、第四个元素;siwzzle操作符后接r、g、b和a的含义与前者等同。不过为了程序的可读性,建议只将表示颜色值的向量,使用swizzle操作符后接r、g、b和a的方式。
举例如下
float4(a, b, c, d).xyz; //等价于 float3(a, b, c)
float4(a, b, c, d).xyy; //等价于 float3(a, b, b)
float4(a, b, c, d).wzyx; //等价于 float4(d, c, b, a)
float4(a, b, c, d).w; //等价于 float d
值得注意的是,Cg语言中float a 和float1 a是基本等价的(菊长PS:不一样),两者可以进行类型转换;float、bool、half等基本类型声明的变量也可以使用swizzle操作符。例如:
float a = 1.0;
float4 b = a.xxxx;
注意:swizzle操作符只能对结构体和向量使用,不能对数组使用,如果对数 组使用swizzle操作符则会出现错误信息:
error C1010: expression left of .”x” is not a struct or array (提示的错误信息中array换成vector更加合适)。
要从数组中取值必须使用[]符号,例如:
float a[3] = {1.0,1.0,0.0};
float b = a[0]; //正确
float c = a.x; //编译会提示错误信息
###6.条件操作符(Conditional Operators)
三目运算符:
expr1 ? expr2 : expr3;
expr1的计算结果为true或者flase,如果是true,则expr2执行运算,否则expr3 被计算。
三目运算符为简单的if-else语句提供了一种便利的替代方式,例如我们可以 不必写:
if(a < 0){
b = a;
}else{
c = a;
}
而改写为
(a < 0)?(b = a) :( c = a);
Cg中的条件操作符一个特征是:支持向量运算。即,expr1的计算结 果可以是bool型向量,expr2和expr3必须是与expr1长度相同的向量。举例如下:
float3 h = float3(-1.0,1.0,1.0);
float3 i = float3(1.0,0.0,0.0);
float3 g = float3(1.0,1.0,0.0);
float3 k;
k = (h < float3(0.0,0.0,0.0))?(i):(g);
三元向量h
与float3(0.0, 0.0, 0.0)
做比较运算后结果为(true, false, false)
,所 以i的第一个数据赋值给k的第一个数据,g的第二个和第三个数据赋值给k的第二 个和第三个数据,k的值为(1.0, 1.0, 0.0)
。
###7.操作符优先顺序
Cg语言中操作符的优先顺序如下表所示,从上到下表示从高级到低级的优 先级;同一行的操作符具有同等优先级。
###8.控制流语句(Control Flow Statement)
程序最小的独立单元是语句(statement),语句一般由分号结尾,缺省情况 下,语句是顺序执行的,但是当涉及逻辑判断控制时,就要求有控制流程序语句。控制流程序语句分为条件语句和循环语句,在C语言中,条件语句有if、if-else、 switch等,而循环过程则由while、do-while和for语句支持。Cg中的控制流语句和循环语句与C语言类似:条件语句有:if、if-else;循环语句有:while、for。break 语句可以和在for语句中使用。
Cg语言中的控制流语句要求其中的条件表达式返回值都是bool类型,这一点 是与C语言不同之处(C语言中,条件表达式返回值可以是实数,0为假,非0为真)
同样,return只能作为最后一条语句出现。函数的递归调用(recursion)在 Cg语言中是被禁止的。Switch 、case和default在Cg中作为保留关键字存在,但 是它们目前不被任何profile所支持(菊长PS:写作本文的时候还没被支持,而且已经停止开发了,so,switch语言应该是彻底不会在Cg里的,去期待shader model 6吧,SPIR-V也完成了,寄希望这个openCL,GLSL和vulkan的整合框架可以和微软的directx一战吧)。