基础篇
字符集
The OpenGL ES Shading Language(以后简称 GLSL)中的代码字符集是ASCII的子集。包含以下:
- 英文字母:a-z,A-Z,以及下划线(_)
- 数字:0-9
- 符号:. + - / * % < > [ ] ( ) { } ^ | & ~ = ! : ; , ?
- 井号:#(用于预处理)
- 空白符:空格,水平制表符,垂直制表符,换页符,回车符,换行符
行数与编译器诊断消息和预处理器有关,以回车或换行符结束。如果两者一起使用,也只被统计为是单行的结束。
不包含行连续符( \ )。
通常,GLSL是大小写敏感的。
没有字符或字符串数据类型,因此不包括引号字符。
没有文件结束符,源码字符串的结尾通过长度而不是一个字符告诉编译器。
源码字符串
单个编译单元的源码是字符集中的字符串数组。一个单个编译单元由这些字符串连接组成。每个字符串可以包含多行,由换行符分隔。字符串中不需要换行符,多个字符串可以形成单行。当字符串连接时,不会插入换行或其他字符。顶点和片元着色器每个都包含一个编译单元。单个顶点着色器和单个片段着色器链接在一起以形成单个程序。从编译返回的诊断消息必须标识字符串中的行号以及哪个源码字符串。源码字符串按顺序计数,第一个字符串是string 0。行号比已处理的换行符数多一个。
编译的逻辑阶段
编译过程基于c++标准的一个子集。顶点和片元处理器的编译单元在各自编译之后,在最后阶段链接在一起。编译的步骤如下:
- 连接源码字符串。
- 源码字符串被转换成一系列的预处理标记,这些标记包括预处理行号、预处理标识、预处理操作。注释被替换成空格。保留换行符。
- 预处理器执行。执行命令,执行宏扩展。
- 预处理标记被转换成Token。
- 空白符、换行符被丢弃。
- 进行语法分析。
- 进行语义检查。
- 定点着色器和片元着色器链接到一起,丢弃没有被二者同时使用的varying变量。
- 生成二进制文件。
预处理器
作为编译的其中一个步骤,预处理器会处理源码字符串。
预处理指令以#开头,#号之前不能有除了空白字符之外的任何字符。每一个指令独占一行。
预处理指令只能使用下面列出的指令,使用其他未定义指令会报错。
完整的预处理器指令如下:
#
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
#error
#pragma
#extension
#version
#line
下面的这个操作符也是合法的:
defined
#define 和 #undef
这两个和C++中的用法完全一样,不做过多说明。
#if, #ifdef, #ifndef, #else, #elif, #endif
这几个也基本和C++的用法一样,不过有下面几点差别。
#if 和 #elif 只能判断int类型,0为false,非0为true
不支持string类型
#pragma
编译指示。用来控制编译器的一些行为。
#pragma optimize(on)
#pragma optimize(off)
在开发和调试时可以设置为off,默认设为on。
#pragma debug(on)
#pragma debug(off)
在开发和调试时可以打开debug选项,以便获取更多的调试信息。默认设为off。
#extension
如果想使用GLGL默认不支持的操作,则必须启用对应的扩展,启用一个扩展可以使用下面的命令:
#extension : behavior
#extension all : behavior
其中,extension_name是扩展的名称,all是指所有的编译器支持的扩展。
behavior是指对该扩展的具体操作。比如启用、禁用等等。详情如下:
behavior | 作用 |
---|---|
require | 启用该扩展。如果不支持,则报错。 |
enable | 启用该扩展。如果不支持,则会警告。extension_name是all的时候会报错。 |
warn | 启用该扩展。但是会检测到所有使用该扩展的地方,提出警告。 |
disable | 禁用该扩展。如果该扩展不被支持,则提出警告。 |
默认是不会启用任何扩展,就像是执行了下面的命令:
#extension all : disable
对于每一个被支持的扩展,都有一个对应的宏定义,我们可以用它来判断编译器是否支持该扩展。
#ifdef OES_extension_name
#extension OES_extension_name : enable
// code that requires the extension
#else
// alternative code
#endif
#version
每一个编译单元都要指定GLSL的版本,如下:
#version number
一般默认即可。这个命令必须放到编译单元的最前面,其前面只能有注释或空白,不能有其他字符。
#line
在宏替换后,#line必须具有以下两种形式之一:
#line line
#line line source-string-number
预定义宏
- LINE :int类型,当前的行号,也就是在Source String中是第一行
- FILE :int类型,当前Source String的唯一ID标识
- VERSION :int类型,GLGL的版本
- GL_ES :对于嵌入式系统(Embed System,简称 ES),它的值为1,否则为0
所有的以两个下划线__开头的变量都是系统保留的,不允许私自定义和篡改。
操作符
优先级 | 类型 | 操作符 | 结合性 |
---|---|---|---|
1(最高) | 括号 | () | 无 |
2 | 一元运算符 | defined + - ~ ! | 从右到左 |
3 | 乘除法 | * / % | 从左往右 |
4 | 加减法 | * / % | 从左往右 |
5 | 位运算-移位 | << >> | 从左往右 |
6 | 大小关系 | < > <= >= | 从左往右 |
7 | 相等性判断 | == != | 从左往右 |
8 | 位运算-与 | & | 从左往右 |
9 | 位运算-非 | ^ | 从左往右 |
10 | 位运算-或 | | | 从左往右 |
11 | 逻辑与 | && | 从左往右 |
12(最低) | 逻辑或 | 从左往右 |
defined操作符一般有下面两种使用方式:
defined identifier
defined ( identifier )
注释
- 单行注释:
//注释内容
- 多行注释:
/*注释内容*/
Tokens
源码字符串会被转成一系列的Tokens。可以这么理解,代码中的每一个单词都属于某一种Token。比如关键词、数字、变量等等。GLSL中,Token主要有下面几种:
- keyword:关键字(如attribute、const、void)
- identifier:标识符(如变量名、函数名)
- integer-constant:整型常量(如6、66、666)
- float-constant:浮点型常量(如6.0、6.6)
- operator:操作符(如+、-、*、%)
关键字
已使用的关键字如下表:
attribute | const | uniform | varying | break | continue |
---|---|---|---|---|---|
do | for | while | if | else | in |
out | inout | float | int | void | bool |
true | false | lowp | mediump | highp | precision |
invariant | discard | return | mat2 | mat3 | mat4 |
vec2 | vec3 | vec4 | ivec2 | ivec3 | ivec4 |
bvec2 | bvec3 | bvec4 | sampler2D | samplerCube | struct |
预留关键字如下表:
asm | class | union | enum | typedef | template | this |
---|---|---|---|---|---|---|
packed | goto | switch | default | inline | noinline | volatile |
public | static | extern | external | interface | flat | long |
short | double | half | fixed | unsigned | superp | input |
superp | hvec2 | hvec3 | hvec4 | dvec2 | dvec3 | dvec4 |
fvec2 | fvec3 | fvec4 | sampler1D | sampler3D | sampler1DShadow | sampler2DShadow |
sampler2DRect | sampler3DRect | sampler2DRectShadow | sizeof | cast | namespace | using |
标识符
标识符其实就是指用户自定义的变量名、函数名、结构体名等等。
变量名可以由下面的字符组成:
_ a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
0 1 2 3 4 5 6 7 8 9
用户可以随便定义标识符,但是不能以 "gl_" 开头,因为以 "gl_" 开头的都是系统预留的。
网友评论