《GPU编程与CG语言之阳春白雪下里巴人》- 第六章(CG 表达式与控制语句)

第06章 CG 表达式与控制语句

读书之法,在循序而渐进,熟读而精思。
          ------ 朱熹

在上一章中,我们已经介绍了 Cg 语言的基础数据类型(7种)、内置数据类型,以及数组、结构、接口等类型,本章将在此基础上讨论 Cg 中的表达式,表达式由操作符(operator)关联一个或多个操作数(operand)构成,我们首先阐述各种类型的操作符,并结合数据类型讲解操作符的具体使用方法。
  Cg 中的操作符与 C 语言中的类似(操作符的功能和写法与 C 相同,但用法不尽相同),按照操作符的功能可以划分为:关系操作符、逻辑操作符、条件操作符。Cg 中有一类较为独特的操作符,称为 Swizzle 操作符,这个操作用于取出向量类型变量中的分量。此外,与 C 语言不同的是,Cg 允许在向量类型变量上使用操作符,例如 > 操作符可以用来比较两个向量各个分量的大小关系。Cg 中的表达式还有狠多与 C 语言不通的细节之处,将在本章中一一分说。

6.1 关系操作符(Comparison Operators)

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

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

在 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);
  float3 c = a < b;

运算后向量 c 的结果为 float3(true, false, true);

6.2 逻辑操作符(Logical Operators)

Cg 语言中有 3 种逻辑操作符(也被称为 boolean Operators),如下表所示,逻辑操作符运算后的返回类型均为 bool 类型。

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

正如上节所说,逻辑操作符也可以对向量使用,返回的变量类型是同样长度的内置 bool 向量。
  有一点需要注意:Cg 中的逻辑与(&&)和逻辑或(||)不存在 C 中的短路现象(short-circuiting,即只用计算一个操作数的 bool 值即可),而是参与运算的操作数据都进行 bool 分析。

6.3 数学操作符(Math Operators)

Cg 语言对向量的数学操作提供了内置的支持,Cg 中的数学操作符有:乘法;/除法;-取反;+加法;-减法;%求余;++;一一;=;/=;+=;-=;后面四中运算符有时被归纳入复制操作符,不过他们实际上进行数学计算,然后进行赋值,所以这里也放入数学操作符中进行说明。
  在文献【2】第 3.3 节 Math Expressions 中,其行文意思容易让人觉得“好像只有加减法除等运算可以对向量进行操作”,实际上经过我的测试,++、一一等数学运算发符同样可以使用在向量上。所以“Cg 语言对向量的数学操作提供内置支持”这句话是非常准确的。
  需要注意的是:求余操作符%。只能在 int 类型数据间进行,否则编译器会提示错误信息:

  error C1021:operands to “%” must be integral.

当使用这些数学操作符对一个标量和一个向量进行运算时,标量首先被复制到一个长度相同的向量中,然后进行运算,例如下面的代码形式是正确的:

  void function()
  {
    float2 a = float2(1.0, 1.0);
    float b = 2.0;
    f* = d;
    f* = 2.0;
  }

6.4 移位操作符

Cg 语言中的移位操作符,功能和 C 语言中的一样,也可以作用在向量上,但是向量类型必须是 int 类型。例如:

  int2 a = int2(0.0, 0.0);
  int2 b = a >> 1;

如果使用如下代码,会出现错误提示信息:

  error C1021:operands to "shr" must be integral.
  float2 a = int2(0.0, 0.0);
  float2 b = a >> 1;

6.5 Swizzle 操作符

可以使用 Cg 语言中的 Swizzle 操作符(.)将一个向量的成员取出组成一个新的向量。 Swizzle 操作符被 GPU 硬件高效支持。Swizzle 操作符后接x、y、z、w,分别表示原始向量的第一个、第二个、第三个、第四个元素;Swizzle 操作符后接 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 是基本等价的,两者可以进行类型转换;float、bool、half 等基本类型声明的变量也可以使用 Swizzle 操作符。例如:

  float a = 1.0;
  float4 b = a.XXXX;

注意:Swizzle 操作符只能对结构体和向量使用,不能对数组使用,如果对数组使用 Swizzle 操作符则会出现错误信息:

  // 其实个人觉得,提示的错误信息中 array 换成 vector 更加合适
  error C1010:expression left of. "x" is not a struct or array.

要从数组中取值必须使用[]符号。例如:

  float a[3] = {1.0, 1.0, 0.0};
  float b = a[0]; // 正确
  float c = a.X; // 编译会提示错误信息

6.6 条件操作符(Conditional Operators)

条件操作符的语法格式为:

  expr1?expr2?expr3;

expr1 的计算结果为 true 或者 false,如果是 true,则 expr2 执行运算,否则 expr3 被计算。
  条件操作符为简单的 if-else 语句提供了一种便利的替代方式,例如我们可以不必写:

  if(a < 0) {b = a}
  else {c = a}

而改写为:

  (a < 0)?(a < 0):(a < 0);

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,1.0)。

6.7 操作符优先顺序

Cg 语言中操作符的优先顺序如下表所示,从上到下表示从高级到低级的优先级;同一行的操作符具有同等优先级。该表参考了 Cg 教程可编程实时图形权威指南第3.3.1节。

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

6.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、1)
  vs_2_x,vp30 和 vp40 这些 profile 支持分之指令(又称转移指令,branch instruction),for 和 while 循环指令在这些 profile 中被完全支持。在文献【3】中提到:
  “In other profiles,for and while loops may only be used if the compiler can fully unroll them (that is,if the compiler can determine the iteration count at compile time)”。
  这句话的意思是“在其他的 profiles 中,for 和 while 循环只有当确切的知道循环次数时此才能被使用”。但经过试验,如果使用“在 fp40 和 ps_3_0 之前的”片段 profiles 编译含义 for,while 语句时会出现错误提示信息:error c6003:instruction limit of exceeded .......。因此,如果没有确切的把握,不要在低级的 profiles 中使用循环控制语句。
  同样,return 只能作为最后一条语句出现。函数的递归调用(recursion)在 Cg 语言中是被机制的。Switch、case 和 default 在 Cg 中作为保留关键字存在,但是他们目前不被任何 profiles 所支持。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容