使用包组数组
使用包组[包装组织] 笼统的讲,显示器上每一个像素点都至少会执行一次。这也是为什么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 特性。 ...