一,概述
ES着色语言源自C语言,同时也有一些不同的优良特性,其易于被开发人员掌握。ES着色语言主要有以下特性:
是一种高级的过程语言;
对顶点着色器,片元着色器使用的是同样的语言;
基于C/C++的语法及流程控制;
完美支持向量与矩阵的各种操作;
通过类型限定符来管理输入与输入;
拥有大量的内置函数提供丰富的功能。
二,着色语言基础
1,基本数据类型:标量,向量,矩阵,采样器,结构体,空类型:
1标量:
整型int,保证最少支持16位,与c语言相似的是可以用8进制,10进制,16进制等表示;浮点型float;布尔型bool,在着色语言的流程控制中只能使用bool类型的值作为表达式。
2向量:
基本类型也分为整型(ivec2,ivec3,ivec4),浮点型(vec2,vec3,vec4),布尔型(bvec2,bvec3,bvec4),由两个,三个或四个相同类型的标量组成。
向量在着色器代码的开发中十分重要,可以很方便的存储以及操作颜色,位置,纹理坐标等不仅包含一个组成部分的量。开发中有时可能单独访问向量中的某个分量,基本语法是:<向量名>.<分量名>,根据目的不同,主要有如下用法:
将一个向量看作颜色时,可以使用r,g,b,a4个分量名,分别代表红,绿,蓝,透明度4个色彩通道
将一个向量看作位置时,可以使用x,y,z,w4个分量名,分别代表X轴,Y轴,Z轴,向量的模4个分量
将一个向量看作纹理坐标时,可以使用s,t,p,q,4个分量名,分别代表纹理坐标的不同分量。
若向量是4维的,则可以使用向量名s,t,p,q,;若向量是3维的,则可以使用向量名s,t,p,;若向量是2维的,则可以使用向量名s,t;上面两个同理。
访问向量中的各个分量还可以将向量看作一个数组,用下标进行访问。
3矩阵:
按尺寸分为2*2,3*3,4*4矩阵:mat2,mat3,mat4.
ES着色语言中,矩阵是按列顺序组织的,也就是说一个矩阵可以看作由几个列向量组成。对于矩阵的访问,可以将矩阵作为列向量的数组来访问,如matrix是一个mat4,可以使用matrix[2]取到该矩阵的第三列,其为一个vec4;也可以使用matrix[2][2]取到第三列的向量的第三个分量,其为一个flout;其他以此类推。
4采样器:采样器是专门用来进行纹理采样的相关操作,一般情况下,一个采样器向量代表一副或一组纹理贴图。与前面介绍的几类变量不同,采样器变量不能再着色器中初始化。一般情况下,采样器变量都用uniform限定符修饰,从宿主语言接收传递进着色器的值。基本类型有sampler2D,sampler3D,samplerCube.
5结构体:基本用法和C基本相似
6数组:可以声明任何类型的数组。声明数组的同时,可以指定数组的大小,也可以不指定数组的大小,但必须符合下列两种情况之一:引用数组之前,要再次使用第一种声明方式声明该数组;代码中访问数组的下标都是编译时常量(如:字面常量),这是编译器会自动创建适当大小的数组,使得数组尺寸足够存储编译器看到的最大索引值对应的元素
7空类型:使用void表示,仅用于声明不返回任何值的函数。
2,数据类型的基本用法
1声明,作用域,初始化
变量的声明及作用域与C++类似,可以在任何需要的位置声明变量,同时其作用域也与C++类似,分为局部变量和全局变量。
注意,着色语言特殊的地方在于,在一些着色语言的实现中不可以在if语句中声明新的变量,这是为了简化变量在else子句上作用域的实现,目前使用的Android平台的各种实现基本都支持,但也不排除特殊情况出现,所以这点要了解即可。
2变量初始化的规则
基本承袭C语言,但也有一点不同,规则如下:
常用初始化方式:变量可以在声明的时候进行初始化
用const限定符修饰的变量必须在声明的时候进行初始化
属性变量,一致变量以及一遍变量在声明的时候一定不能进行初始化
3,类型转换
ES着色语言没有提供类型的自动提升功能,并且对类型的匹配要求十分严格;也没有提供数据类型的强制转换功能,只能使用构造函数来完成类型转换
限定符 | 说明 |
attribute | 一般用于每个顶点都各不相同的量,如顶点位置,颜色等 |
uniform | 一般用于对同一组顶点组成的单个3D物体中所有顶点都相同的量,如当前的光源位置 |
varying | 用于从顶点着色器传递到片元着色器的量 |
const | 用于声明常量 |
4,函数的声明与使用
着色语言中也可以开发自定义函数,基本语法:<返回类型>函数名(参数序列){函数体}
参数序列中,除了可以指定类型外,还可以指定用处。具体方法为用参数用途修饰符进行修饰,常用的参数用途修饰符有:in修饰输入参数,若某个参数没有明确给出用途修饰符,则默认为in;out修饰输出参数,对于输出参数,在调用时不可以使用字面常量;inout修饰输入输出参数。
5,片元着色器中浮点变量精度的指定
定点着色器中直接声明使用即可,但在片元着色器中必须指定精度。精度有三种选择,lowp,mediump,highp分别代表低中高三种精度等级,在不同的硬件中实现可能会不同。一般情况下,使用mediump即可。包括标量,向量,矩阵里的浮点类型变量。如果在开发同一个片元着色器中浮点相关类型的变量都选同一种精度,则可以指定整个着色器中浮点相关类型的默认精度,语法如下:precision<精度><类型>;
6,程序的基本结构
着色器程序的基本结构一般由三大部分组成,主要包括:全局变量声明,自定义函数,main函数。与很多高级语言不同,着色器程序中要求被调用的函数必须在调用之前声明。着色器语言中没有switch语句,需要时可以使用if-else语句的嵌套来实现。
三,特殊的内建变量
着色器提供了一些用来满足特定功能需求的内建变量,这些内建变量不需要声明即可使用,一般实现渲染管线固定功能部分与自定义顶点或片元着色器之间的信息交互。根据信息传递的方向可以分为两类:输入变量,输出变量。
顶点着色器的内建变量主要为输出变量,包括gl_Position,gl_PointSite等;片元着色器的输出内建变量主要有gl_FragColor,gl_FragData,输入内建变量主要有gl_FragCoord,gl_FrontFacing
四,着色语言的内置函数
ES着色语言提供了很多内置函数,这些函数大都已经被重载,一般有4中变体,分别用来接收和返回flout,vec2,vec3,vec4类型的值。大部分内置函数同时适用于顶点着色器和片元着色器,也有部分只适用于顶点着色器或片元着色器。
按照设计目的可以分为3个类别:提供独特硬件功能的访问接口,如纹理采样系列的函数;简单的数学函数;一些复杂的函数。
包含有:角度转换与三角函数,指数函数,常见函数,几何函数,矩阵函数,向量关系函数,纹理采样函数,微分函数(函数详情解释请参考书籍《Android3D游戏开发技术宝典》)