ShaderLab开发实战——Cg语言简介

上文中介绍了Shader相关基础概念,想了解的读者可通过ShaderLab开发实战——Shader基本概念查看。

文章最后还剩一个问题没有介绍,就是Shader编程语言Cg(C for graphics),本文将介绍Cg的相关知识点。

本文主要介绍两个问题,第一,为什么要使用Cg开发Shader,第二,Cg语言入门知识和学习资料。

1. 为什么要使用Cg开发Shader

    在Shader基本概念文章中已经介绍了,目前Shader的实现语言一共有三种,微软提供的HLSL(High Level Shading Language),OpenGL提供的GLSL(OpenGL Shading Language)以及NIVIDIA联合提供的Cg(C for graphics)。在Cg出现之前,HLSL和GLSL占据了整个Shader开发市场。随着NIVIDIA的GeForce系列显卡的崛起,其推出的Cg语言取得了巨大的成功。Cg语言是可以被OpenGL和DirectX广泛支持的图形处理器编程语言,属于OpenGL和DirectX的上层语言。可以说使用Cg编程的Shader可以在OpenGL和DirectX环境上运行,良好的跨平台性给开发者提供较大便利。另外Cg语言的易学性也是其一大优势,设计者的初衷也是想将Shader编程想C语言一样方便,当然还有一个重要原因是Unity3D中ShaderLab的编写使用了Cg语言。基于以上原因,Cg语言不断受到Shader开发者的青睐,学好Cg语言也是Shader编写的关键。

2. Cg语言入门知识和学习资料

    这里首先介绍一下Cg语言的编译过程。任何的汇编语言或高级语言程序都需要经过编译程序翻译成计算机能够理解0、1序列,整个编译过程分为静态编译和动态编译,两者的却别在于编译成可执行文件后是否需要源码信息。静态编译是指一旦语言编译成可执行文件,可执行文件运行中就不再需要源码信息,动态编译则相反。Cg语言的编译通常使用的是动态编译,当然也支持静态编译,NIVIDIA提供的Cg语言编译程序为cgc.exe。

    cgc首先会将Cg程序翻译成可被图形API(OpenGL和Direct3D)支持的形式,然后应用程序使用适当的OpenGL和Direct3D命令将翻译后的Cg程序传递给图形处理器,OpenGL和Direct3D的驱动程序最终会把它翻译成图形处理器所需要的硬件可执行格式。

   之后本文将从Cg语言数据类型开始讲起,介绍Cg语言相关入门知识。

    1. Cg数据类型

        Cg中支持六种基本数据类型,分别为float、int、half、fixed、sampler*、bool

        其中float和half分别为32位和16位的浮点数,int和fixed分别为32位整形和12定点数,sampler*为纹理对象,包括sampler2D、sampler3D、samplerRECT以及sampler CUBE等。

        除了基本数据类型,Cg还提供了内置的向量数据类型以及矩阵数据类型

        向量数据类型如float4表示float类型的4元向量,fixed4表示fixed类型的4元向量,这里注意的是向量长度不能超过4元。

        矩阵数据类型如float4x4表示4*4阶矩阵,4*4是矩阵的最大维度。

        在Cg语言中,向量和矩阵为内置的数据类型,而下面要说的数组则是一种数据结构。

        这里顺便提一下数据结构和数据类型的区别,数据类型是指数据的一种分类,比如说变量为Int或者float类型等。而数据结构是相互之间存在一种或者多种关系的数据的集合,比如数组结构将同一数据类型的变量储存在一起,那么数组就叫做数据结构。

        Cg中通过float a[10]声明一个包含10个float数据类型元素的数组,可以通过a.length获得数组长度

        Cg支持结构体类型,一个结构体相当于一种数据类型,可以定义该类型的变量。结构体生命一strcut开始,紧跟着结构体变量名以及大括号和分号等。

        Cg语言支持强制类型转换和隐式转换。当有类型变量和无类型常量进行运算时,无类型常量不进行类型转换。例如float a=1.0;float b = a+2.0此时2.0不换类型转换,编译时作为float类型。

        可在常量后面加上类型后缀,此时运算需要类型转换,后缀f表示float,h表示half,x表示fixed。

    2.Cg语言表达式与控制语句

        Cg中的操作符和c语言相似,这里就不进行过多说明了,附图:

           此外Cg中还支持了数学操作符、位移操作符、wizzle操作符(".")以及条件操作符。操作符的优先顺序如图:

    

        在控制流语句中,支持条件语句包括if、if-else,循环语句包括while、for、break以及return。

    3.输入\输出和语义绑定

        Cg中不存在指针的概念,所有数据通常都是暂存在寄存器中。

        Cg中s的关键字很多都是照搬C\C++中的关键字。

        in、out、inout用来表示函数输入参数的传递方式。这里先提一下形参和实参的区别,形参是指定义函数名和函数体时使用的参数,目的是接收调入参数时传入的参数;实参是指调用函数时,传入的参数。参数的传递分为值传递和引用传递,值传递时,函数处理的是传入实参的拷贝,不会影响实参的原值;引用传递时,函数处理的是实参的地址(C\C++使用指针,CG中使用in、out、inout关键字),会影响原有实参的值。in修饰形参,表示形参只用于输入,典型的值传递。out修饰形参,表示形参只用于函数的输出,也可以用return代替out修饰符使用。inout修饰形参,表示形参即用于输入也用于输出,典型的引用传递。

         const和uniform是独立的,可同时使用也可单独使用。

        uniform用来修饰只能由外部应用程序传入的变量。在Cg中输入的数据流分为两类:第一类Varying inputs表示输入数据流中图元信息的各种组成要素,包括顶点位置、法向量以及纹理坐标数据等。第二类Uniform数据由外部应用程序初始化并传入,不会随着图元信息的变化而变化。

        const用来修饰变量为常量变量。表示const修饰的变量初始化之后,其值不会改变。     

        语义词是数据和寄存器做一个映射关系,是两个处理阶段(顶点程序、片段程序)之间的输入\输出数据和寄存器之间的桥梁,同时语义通常也表示数据的含义,如 POSITION一般表示参数种存放的数据是顶点位置。   语义分为输入语句和输出语句:

        顶点着色程序的输入语义:

        POSITION:四元向量,最后一元数据为1,表示模型空间内的顶点位置坐标,在OpenGL中对应接收应用程序传递顶点数据的寄存器上。

        NORMAL:四元向量,最后一元数据为0,表示模型空间中顶点法向量坐标,在OpenGL中对应接收应用程序传递顶点法向量的寄存器上。

        顶点着色程序的输出语义及片段着色程序的输入语句:

        顶点着色程序的输出语义会被传入到片段着色程序中。

        语义包括POSITION、PSIZE、FOG、COLOR0-COLOR1,TEXCOORD0-TEXCOORD7。

        顶点着色程序中必须绑定一个输出语义POSITION,作为裁剪空间中的顶点坐标,该数据只被用于光栅化。

        为了保持顶点着色程序输出语义和片段着色程序输入语义的一致性,推荐使用struct类型数据作为两者之间的传递。例如:

        这里值得注意的地方是,在顶点着色程序中,输入语义和输出语义中都包括一个POSITION语义。两者是不同的,前者是应用程序中模型空间中的顶点坐标,是用来顶点着色程序对顶点坐标进行处理的。后者是顶点着色程序输出的裁剪空间顶点坐标,是用来给片段程序做光栅化处理的。两者都为POSITION语义,但作用是不一样的。

        片段着色程序的输出语义

        片段着色程序的输出语义通常只有一个,COLOR作为该片段的最终颜色值。

        绑定语义方法

        常见的绑定语义方法有三种:

        1. 声明在函数形参列表后面。

        2. 声明在结构体成员变量后面。

   

        3. 声明在函数声明后面。

    4.函数与程序设计

        Cg中函数的定义同C\C++中函数的定义方式一致,并且支持函数重载,即通过形参个数和类型进行函数区分。

        Cg中使用数组形参时传递的是数组的完整拷贝,C\C++中实际传入的是指向首元素的指针。数组作为函数形参时,可不必声明数组长度。如制定长度,调用函数传入实参数组时需要与函数形参数组长度一致。

        Cg中顶点处理程序和片段处理程序各提供了一个入口函数,同C\C++中的main()方法相似。通过判断函数输入、输出语义来判断入口函数。

        Cg中提供了一系列的内建的标准函数库,分为5个部分:数学函数、几何函数、纹理映射函数、偏导数函数以及调试函数。具体函数有哪些,读者可自行搜索。

    至此,Cg相关的基础知识已介绍完毕,可以看出Cg中的无论数据结构,函数语法都与C\C++很相似,建议学习中充分结合OpenGL渲染流程的实现原理。     

猜你喜欢

转载自my.oschina.net/u/3227483/blog/1810747