GLSL用到的字符集是ASCII码的子集,主要包含下面的几部分:
该字符集不包含反斜杠**,也不包含任何字符或字符串。
一般来说,GLSL是大小写敏感的。
不管是Vertex Shader还是Fragment Shader,其实都有一段对应的代码,称为Source Strings,它包含多个string,每个string一行。
对于本版本的GLSL来说,每个Shader对应着一个可编程单元,一个Vertex Shader对应着一个Fragment Shader,二者连接起来组成一个program。
编译程序使用C++标准的一个子集。
Vertex Shader和Fragment Shader在各自编译之后连接到一起。
编译的步骤如下:
作为编译的其中一个步骤,预处理器会处理source strings。
预处理指令以*#开头,#*号之前不能有除了空白字符之外的任何字符。每一个指令独占一行。
预处理指令只能使用上面列出的指令,使用其他未定义指令会报错。
完整的预处理器指令如下:
#
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
#error
#pragma
#extension
#version
#line
下面的这个操作符也是合法的:
defined
这两个和C++中的用法完全一样,不做过多说明
这几个也基本和C++的用法一样,不过有下面几点差别。
1. #if和#elif只能判断int类型,0为false,非0为true
2. 不支持string类型
编译指示。用来控制编译器的一些行为。
#pragma optimize(on)
#pragma optimize(off)
在开发和调试时可以设置为off,默认设为on。
#pragma debug(on)
#pragma debug(off)
在开发和调试时可以打开debug选项,以便获取更多的调试信息。默认设为off。
每一个编译单元都要指定GLSL的版本,如下:
#version number
一般默认即可。这个命令必须放到编译单元的最前面,其前面只能有注释或空白,不能有其他字符。
如果想使用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
除此之外,还预定义了一些变量:
所有的以两个下划线*__*开头的变量都是系统保留的,不允许私自定义和篡改。
优先级 | 类型 | 操作符 | 结合性 |
---|---|---|---|
1 | 括号 | () | 无 |
2 | 一元运算符 |
| 从右往左 |
| 3 | 乘除法 | * / % | 从左往右 |
| 4 | 加减法 | + - | 从左往右 |
| 5 | 位运算 移位 | << >> | 从左往右 |
| 6 | 大小关系 | < > <= >= | 从左往右 |
| 7 | 相等性判断 | == != | 从左往右 |
| 8 | 位运算 与 | & | 从左往右 |
| 9 | 位或算 非 | ^ | 从左往右 |
| 10 | 位或算 或 | | | 从左往右 |
| 11 | 逻辑与 | && | 从左往右 |
| 12 | 逻辑或 | || | 从左往右 |
defined操作符一般有下面两种使用方式:
defined identifier
defined ( identifier )
和Java里的注释没啥区别。主要有下面两种注释方法。
// 我是注释
/* 我是注释 */
Source String会被转成一系列的Tokens。可以这么理解,代码中的每一个单词都属于某一种Token。比如关键词、数字、变量等等。GLSL中,Token主要有下面几种:
Token | 解释 | 举例 |
---|---|---|
keyword | 关键词 | if elif ... |
identifier | 标识符 | 自定义的函数名、变量名 ... |
integer-constant | int常量 | 1 2 3 ... |
float-constant | float常量 | 1.1 1.2 1.3 ... |
operator | 操作符 | + - * / ... |
列举一下GLSL中的关键词,这些全部是系统保留的,不可私自篡改。
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 output
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_*开头的都是系统预留的。