##Unity shader学前准备之CG语言(4)        Cg中的操作符与C语言中的类似(操作符的功能和写法与C相同,但用法不 尽相同),按照操作符的功能可以划分为:关系操作符、逻辑操作符、条件操作符。Cg中有一类较为独特的操作符,称为Swizzle操作符, 这个操作符用于取出 向量类型变量中的分量。

###1.关系操作符(Comparison Operators)

       关系操作符,用于比较同类型数据(不同类型的基础数据需要进行类型转换,不同长度的向量,不能用于进行比较)之间的大小关系或者等价关系。Cg中有6种关系操作符,如下表所示,关系操作符的返回值类型均为bool类型。

关系操作符
功能
用法
<
小于
expr< expr
<=
小于或等于
expr<=expr
!=
不等于
expr!=expr
==
等于
expr==expr
>=
大于或等于
expr>=expr
>
大于
expr>expr
关系操作符

###2.逻辑操作符(Logical Operators)        Cg语言中有3种逻辑操作符,如下表所示,逻辑操作符运算后返回值类型均为bool类型。

逻辑操作符
功能
用法
&&
逻辑与
expr&&expr
||
逻辑或
expr||expr
!
逻辑非
!expr
逻辑操作符

       有一点需要注意: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);

三元向量hfloat3(0.0, 0.0, 0.0)做比较运算后结果为(true, false, false),所 以i的第一个数据赋值给k的第一个数据,g的第二个和第三个数据赋值给k的第二 个和第三个数据,k的值为(1.0, 1.0, 0.0)

###7.操作符优先顺序

       Cg语言中操作符的优先顺序如下表所示,从上到下表示从高级到低级的优 先级;同一行的操作符具有同等优先级。

操作符
结合律
功能
() [] -> .
从左到右
函数调用、数组引 用、结构引用、成员 选择
! ~ ++ - + - * & (type) sizeof
从右到左
一元操作符:取反、 增加、减少、正号、 负号、间接、地址、 转换
*/%
从左到右
乘法、除法、余数
+-
从左到右
加法、减法
<< >>
从左到右
移位操作符
< >= > >=
从左到右
关系操作符
== !=
从左到右
等于、不等
&
从左到右
位操作符与
^
从左到右
位操作符异或
&&
从左到右
逻辑与
||
从左到右
逻辑或
?:
从右到左
条件表达式
= += -= *= /= %= &= ^= != <<= >>=
从右到左
赋值、赋值表达式
,
从左到右
逗号操作符

###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一战吧)。