使用包组[包装组织]
笼统的讲,显示器上每一个像素点都至少会执行一次。这也是为什么GPU要设计高度优化的并行架构的原因。同样的在Cg语言的标准变量类型和操作符中,这种设计哲学也很明显。理解它们,不仅仅是为了正确的使用着色器,同时也是为了能够写出更高效的着色器。
操作步骤
在Cg语言中有两种类型的变量: 单精度值single 和 包组packed arrays 。后者很容易辨别因为这种类型通常会以数字结尾,比如 float4 , int4 等等。正如它们的名字所表示的一样,这些类型的变量跟我们编程语言中的 结构体structs 类似,这也意味着每一个这样的变量包含了多个单精度值。在Cg语言中我们称之为 包组packed arrays ,尽管它们并非真的是传统意义上的数组。
在包组中的元素能像常见的结构体那样访问。通常它们表示成 x ,y ,z 和 w 。然而Cg语言还有另一种表示,就是 r ,g ,b ,a 。尽管你使用 x 或者 r 去表示都是可以的,但是对于代码阅读者来说它们之间的区别就非常的大了。事实上,在着色器编程中,经常涉及到的就是位置和颜色的计算。你可能对下面的标准着色器代码中的代码片段还有印象吧:
o.Alpha = _Color.a;
在这里, o 是一个结构体而 _Color 就是一个包组。这也是为什么Cg要禁止上面提到的两种表示进行混用的原因:你不能使用 _Color.xgz 。
这里还有一个很重要的包组的特性,这种特性在C#中没有: swizzling [这个不知道怎么翻译]。Cg允许仅通过简单的一行代码就对包组内的元素进行寻址和重新排序。又是下面在标准着色器中熟悉的代码片段:
o.Albedo = _Color.rgb;
Albedo 是一个 fixed3 类型,也就是说它里面包含了三个 fixed 类型的值。 然而 _Color 是一个 fixed4 类型的定义。由于 _Color 定义包含的元素比 Albedo 定义包含的元素要多,直接赋值的话,由于不匹配,肯定会产生一个编译错误。如果用C#代码来进行同样的操作,代码如下所示:
o.Albedo.r = _Color.r; o.Albedo.g = _Color.g; o.Albedo.b = _Color.b;
相比于C#代码,在Cg语言中,我们可以用如下代码简写:
o.Albedo = _Color.rgb;
Cg语言也允许对元素进行重新排序。比如,通过 _Color.bgr 这个代码去交换红色和蓝色通道的颜色。
最后要讲一点,当一个单精度值赋值给包组时,这个值会被复制到包组的所有元素中去:
o.Albedo = 0; // Black =(0,0,0) o.Albedo = 1; // White =(1,1,1)
这个就是Cg语言中的 smearing 特性。
Swizzling 还可以被用作表达式的左值,不过仅当包组的具体元素能被这样使用:
o.Albedo.rg = _Color.rg;
上面这种特性,叫做 masking .
压缩矩阵
真正发挥 swizzling 特性潜力的是在它应用于压缩矩阵的时候。Cg语言允许像 float4x4 这种类型,这是一个四行四列的矩阵。你可以使用 _mRC 标记访问矩阵中的单个元素,R 表示元素所在的行而 C 表示元素所在的列:
float4x4 matrix; // ... float first = matrix._m00; float last = matrix._m33;
_mRC 标记还可以接连使用:
float4 diagonal = matrix._m00_m11_m22_m33;
如果要获取矩阵的整行,可以使用中括号:
float4 firstRow = matrix[0]; // Equivalent to float4 firstRow = matrix._m00_m01_m02_m03;
相关补充
包组是Cg语言中最棒的特性之一,你可以从下面的连接获得关于包组的更多信息:
http://http.developer.nvidia.com/CgTutorial/cg_tutorial_chapter02.html
希望它能帮到你或者帮你找到思路(^_^)选个表情,或者留个评论吧!