Cg(c for graphic)语言的数据类(转)
抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人”
本章将着重介绍Cg语言中预定义的内置(built in)的、或称为基本(primitive)的数据类型。然后介绍可以用来声明对象的各类类型,主要是数组和结构类型。学习本章时,需要体会内置向量类型和数组类型的区别。
5.1 基本数据类型
Cg支持7种基本的数据类型:
1. float,32位浮点数据,一个符号位。浮点数据类型被所有的profile支持(但是DirectX8 pixel profiles在一些操作中降低了浮点数的精度和范围);
2. half,16为浮点数据;
3. int,32位整形数据,有些profile会将int类型作为float类型使用;
4. fixed,12位定点数,被所有的fragment profiles所支持;
5. bool,布尔数据,通常用于if和条件操作符(?:),布尔数据类型被所有的profiles支持;
6. sampler*,纹理对象的句柄(the handle to a texture object),分为6类:sampler, sampler1D, sampler2D, sampler3D, samplerCUBE,和samplerRECT。DirectX profiles不支持samplerRECT类型,除此之外这些类型被所有的pixel profiles和 NV40 vertex program profile所支持(CgUsersManual 30页)。由此可见,在不远的未来,顶点程序也将广泛支持纹理操作;
7. string,字符类型,该类型不被当前存在的profile所支持,实际上也没有必要在Cg程序中用到字符类型,但是你可以通过Cg runtime API声明该类型变量,并赋值;因此,该类型变量可以保存Cg文件的信息。
前6种类型会经常用到,事实上在Wikipedia有关Cg语言的阐述中只列举了前6种类型,而并没有提到string数据类型。除了上面的基本数据类型外,Cg还提供了内置的向量数据类型(built-in vector data types),内置的向量数据类型基于基础数据类型。例如:float4,表示float类型的4元向量;bool4,表示bool类型4元向量。
注意:向量最长不能超过4元,即在Cg程序中可以声明float1、float2、float3、float4类型的数组变量,但是不能声明超过4元的向量,例如:
float5 array ;// 编译报错
向量初始化方式一般为:
float4 array = float4(1.0, 2.0, 3.0, 4.0);
较长的向量还可以通过较短的向量进行构建:
float2 a = float2(1.0, 1.0);
float4 b = float4(a, 0.0, 0.0);
此外,Cg还提供矩阵数据类型,不过最大的维数不能超过4*4阶。例如:
float1x1 matrix1; // 等价于 float matirx1; x 是字符,并不是乘号!
float2x3 matrix2; // 表示2*3 阶矩阵,包含6 个 float 类型数据
float4x2 matrix3;// 表示 4*2 阶矩阵,包含 8 个 float 类型数据
float4x4 matrix4 ;// 表示4*4 阶矩阵,这是最大的维数
矩阵的初始化方式为:
float2x3 matrix5 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
注意:Cg中向量、矩阵与数组是完全不同,向量和矩阵是内置的数据类型(矩阵基于向量),而数组则是一种数据结构,不是内置数据类型!这一点和C\C++ 中不太一样,在C\C++中,这三者同属于数据结构,数组可以构建向量和矩阵。下一节中将详细阐述Cg中的数组类型。
5.2 数组类型
“General-purpose arrays can only be used as uniform parameters to a vertex program. The intent is to allow an application to pass arrays of skinning matrices and arrays of light parameters to a vertex program”(文献【3】的Array章节)。
在着色程序中,数组通常的使用目的是:作为从外部应用程序传入大量参数到Cg的顶点程序中的形参接口,例如与皮肤形变相关的矩阵数组,或者光照参数数组等。
简而言之,数组数据类型在Cg程序中的作用是:作为函数的形参,用于大量数据的转递。
Cg中声明数组变量的方式和C语言类似:例如:
float a[10]; // 声明了一个数组,包含10 个 float 类型数据
float4 b[10]; // 声明了一个数组,包含10 个 float4 类型向量数据
对数组进行初始化的方式为:
float a[4] = {1.0, 2.0, 3.0, 4.0}; // 初始化一个数组
要获取数组长度,可以调用“.length”,例如:
float a[10]; // 声明一个数组
int length = a.length; // 获取数组长度
声明多维数组以及初始化的方式如下所示:
float b[2][3] = {{0.0, 0.0, 0.0},{1.0, 1.0, 1.0}};
对多维数组取长度的方式为:
int length1 = b.length; // length1 值为2
int length2 = b[0].length; // length2 值为3
数组和矩阵有些类似,但是并不是相同。例如4*4阶数组的的声明方式为:float M[4][4];4阶矩阵的声明方式为:float4x4 M。前者是一个数据结构,包含16个float类型数据,后者是一个4阶矩阵数据。float4x4 M[4],表示一个数组,包含4个4阶矩阵数据。
进行数组变量声明时,一定要指定数组长度,除非是作为函数参数而声明的形参数组。并且在当前的profiles中,数组的长度和所引用的数组元素的地址必须在编译时就知道。
“Unsized arrays may only be declared as function parameters-they may not be declared as variables. Furthermore, in all current profiles, the actual array length and address calculations implied by array indexing must be known at compile time”(文献【3】)。
由于形参数组的概念与函数的概念紧密结合,所以将在第8章的8.1函数章节中进行统一阐述。
5.3 结构类型
Cg语言支持结构体(structure),实际上Cg中的结构体的声明、使用和C++非常类似(只是类似,不是相同)。一个结构体相当于一种数据类型,可以定义该类型的变量。引入结构体机制,赋予了Cg语言一丝面向对象的色彩。还记得C++中,结构体与类的区别吗?没有区别,除了默认访问属性在结构体中为public,类中为private,所以结构体与类是非常近似的,由此可以看出shader 语言的发展趋势还是向着具有面向对象特性的高级语言。不过目前的Cg语言中的结构体以展现“封装”功能为主,并不支持继承机制。
结构体的声明以关键字struct开始,然后紧跟结构体的名字,接下来是一个大括号,并以分号结尾(不要忘了分号)。大括号中是结构体的定义,分为两大类:成员变量和成员函数。例如,定义一个名为myAdd的结构体,包含一个成员变量,和一个执行相加功能的成员函数,然后声明一个该结构体类型的变量,代码为:
struct myAdd
{
float val;
float add(float x)
{
return val + x;
}
};
myAdd s;
使用符号“ ”引用结构体中的成员变量和成员函数。例如:
float a = s.value;
float b = s.add(a);
注意:在当前的所有的profile版本下,如果结构体的一个成员函数使用了成员变量,则该成员变量要声明在前。此外,成员函数是否可以重载依赖于使用的profile版本。(文献[3] 的structures and Member functions章节)
一般来说,Cg的源代码都会在文件首部定义二个结构体,分别用于定义输人和输出的类型,这二个结构体定义与普通的C结构定义不同,除了定义结构体成员的数据类型外,还定义了该成员的绑定语义类型( Binding Semantics),所谓绑定语义类型是为了与宿主环境进行数据交换的时候识别不同数据类型的。目前Cg支持的绑定语义类型包括POSTION位置), COLOR(颜色),NORMAL(法向量),Texcoord(纹理坐标)等类型。
当顶点着色程序向片段着色程序传递的数据类型较多的情况下,使用结构体可以大大的方便代码的编写和维护。总而言之,使用结构体是一个好习惯,高智商的孩子都使用。
5.4 接口(Interfaces)类型
Cg语言提供接口类型,实际上,我本人很少见到使用接口类型的着色程序,原因在于,Cg语言中的接口类型还不完善,不能被扩展和包含。此外,目前的GPU 编程大多只是针对独立的算法进行编码,规模较小,使用接口类型没有太大的优势。所以这里对该类型并不多做说明。有兴趣的读者可以参阅文献【3】的 Interfaces章节。
5.5 类型转换
Cg中的类型转换和C语言中的类型转换很类似。C语言中类型转换可以是强制类型转换,也可以是隐式转换,如果是后者,则数据类型从低精度向高精度转换。在Cg语言中也是如此。例如:
float a = 1.0;
half b = 2.0 ;
float c = a+b ; // 等价于 float c = a + (float)b;
当有类型变量和无类型常量数据进行运算时,该常量数据不做类型转换,举例如下:
float a = 1.0;
float b = a + 2.0; //2.0 为无类型常量数据,编译时作为 float 类型
Cg语言中对于常量数据可以加上类型后缀,表示该数据的类型,例如:
float a = 1.0;
float b = a + 2.0h; //2.0h 为 half 类型常量数据,运算是需要做类型转换
常量的类型后缀(type suffix)有3种:
? f :表示float;
? h: 表示 half;
? x: 表示fixed