GLSL语法及特点(转载)

OpenGL ES 1.x是针对固定硬件管线的而从OpenGL ES 2.0开始针对可编程硬件管线。而这其中最重要的就是顶点着色器和片元着色器,顶点着色器是针对每个顶点执行一次,用于确定顶点的位置,将颜色信息或者纹理信息传递给片元着色器,片元着色器是针对每个片元,片元我们可以理解为每个像素,用于确定每个片元(像素)的颜色。

本文只是介绍着色器语言本身,而固定管线和可编程管线这里不做详细介绍。

一 GLSL特点

OpenGLES的着色器语言GLSL是一种高级的图形化编程语言,其源自应用广泛的C语言。与传统的C语言不同的是,它提供了更加丰富的针对于图像处理的原生类型,诸如向量、矩阵之类。GLSL主要包含以下特性:

GLSL是一种面向过程的语言,和C相同。

GLSL的基本语法与C/C++基本相同。

它完美的支持向量和矩阵操作。

它是通过限定符操作来管理输入输出类型的。

GLSL提供了大量的内置函数来提供丰富的扩展功能。


二 GLSL 基础

GLSL虽然是基于C/C++的语言,也和他们有很多相似的地方,但是它和C/C++还是有很多的不同之处的,比如在GLSL中没有double、long等类型,没有union、enum、unsigned以及位运算等特性。

之前文中我们所使用的都是非常简单的着色器,没有使用过GLSL的内置函数,在后面要有比较复杂的功能实现,我们不可避免的要使用这些内置函数。

下面来看GLSL语言的基础。

2.1 基本数据类型

GLSL中的数据类型主要分为标量、向量、矩阵、采样器、结构体、数组、空类型七种类型。如下:

1. 标量:

标量表示的是只有大小没有方向的量,在GLSL中标量只有bool、int和float三种。对于int,和C一样,可以写为十进制(16)、八进制(020)或者十六进制(0x10)。对于标量的运算,我们最需要注意的是精度,防止溢出问题。

2. 向量:

向量我们可以看做是数组,在GLSL通常用于储存颜色、坐标等数据,针对维数,可分为二维、三维和四维向量。针对存储的标量类型,可以分为bool、int和float。共有vec2、vec3、vec4,ivec2、ivec3、ivec4、bvec2、bvec3和bvec4九种类型,数组代表维数、i表示int类型、b表示bool类型。需要注意的是,GLSL中的向量表示竖向量,所以与矩阵相乘进行变换时,矩阵在前,向量在后(与DirectX正好相反)。向量在GPU中由硬件支持运算,比CPU快的多。

作为颜色向量时,用rgba表示分量,就如同取数组的中具体数据的索引值。三维颜色向量就用rgb表示分量。比如对于颜色向量vec4 color,color[0]和color.r都表示color向量的第一个值,也就是红色的分量。其他相同。

作为位置向量时,用xyzw表示分量,xyz分别表示xyz坐标,w表示向量的模。三维坐标向量为xyz表示分量,二维向量为xy表示分量。

作为纹理向量时,用stpq表示分量,三维用stp表示分量,二维用st表示分量。

3. 矩阵:

在GLSL中矩阵拥有22、33、4*4三种类型的矩阵,分别用mat2、mat3、mat4表示。我们可以把矩阵看做是一个二维数组,也可以用二维数组下表的方式取里面具体位置的值。

4.采样器:

采样器是专门用来对纹理进行采样工作的,在GLSL中一般来说,一个采样器变量表示一副或者一套纹理贴图。所谓的纹理贴图可以理解为我们看到的物体上的皮肤。

5.结构体:

和C语言中的结构体相同,用struct来定义结构体,关于结构体参考C语言中的结构体。

6.数组:

数组知识也和C中相同,不同的是数组声明时可以不指定大小,但是建议在不必要的情况下,还是指定大小的好。

7.空类型:

空类型用void表示,仅用来声明不返回任何值得函数。

float a=1.0;

int b=1;

bool c=true;

vec2 d=vec2(1.0,2.0);

vec3 e=vec3(1.0,2.0,3.0)

vec4 f=vec4(vec3,1.2);

vec4 g=vec4(0.2);  //相当于vec(0.2,0.2,0.2,0.2)

vec4 h=vec4(a,a,1.3,a);

mat2 i=mat2(0.1,0.5,1.2,2.4);

mat2 j=mat2(0.8);  //相当于mat2(0.8,0.8,0.8,0.8)

mat3 k=mat3(e,e,1.2,1.6,1.8);


2.2 运算符

GLSL中的运算符有(越靠前,运算优先级越高):

索引:[]

前缀自加和自减:++,–

一元非和逻辑非:~,!

加法和减法:+,-

等于和不等于:==,!=

逻辑异或:^^

三元运算符号,选择:?:

成员选择与混合:.

后缀自加和自减:++,–

乘法和除法:*,/

关系运算符:>,<,=,>=,<=,<>

逻辑与:&&

逻辑或:||

赋值预算:=,+=,-=,*=,/=

2.3 类型转换

GLSL的类型转换与C不同。在GLSL中类型不可以自动提升,比如float a=1;就是一种错误的写法,必须严格的写成float a=1.0,也不可以强制转换,即float a=(float)1;也是错误的写法,但是可以用内置函数来进行转换,如float a=float(1);还有float a=float(true);(true为1.0,false为0.0)等,值得注意的是,低精度的int不能转换为低精度的float。

2.4 限定符

在之前的博客中也提到了,GLSL中的限定符号主要有:

attritude:一般用于各个顶点各不相同的量。如顶点颜色、坐标等。

uniform:一般用于对于3D物体中所有顶点都相同的量。比如光源位置,统一变换矩阵等。

varying:表示易变量,一般用于顶点着色器传递到片元着色器的量。

const:常量。

限定符与java限定符类似,放在变量类型之前,并且只能用于全局变量。在GLSL中,没有默认限定符一说。

2.5 流程控制

GLSL中的流程控制与C中基本相同,主要有:

if(){}、if(){}else{}、if(){}else if(){}else{}

while(){}和do{}while()

for(;;){}

break和continue


2.6 函数

GLSL中也可以定义函数,定义函数的方式也与C语言基本相同。函数的返回值可以是GLSL中的除了采样器的任意类型。对于GLSL中函数的参数,可以用参数用途修饰符来进行修饰,常用修饰符如下:

in:输入参数,无修饰符时默认为此修饰符。

out:输出参数。

inout:既可以作为输入参数,又可以作为输出参数。

2.7 浮点精度

与顶点着色器不同的是,在片元着色器中使用浮点型时,必须指定浮点类型的精度,否则编译会报错。精度有三种,分别为:

lowp:低精度。8位。

mediump:中精度。10位。

highp:高精度。16位。

不仅仅是float可以制定精度,其他(除了bool相关)类型也同样可以,但是int、采样器类型并不一定要求指定精度。加精度的定义如下:

uniform lowp float a=1.0;

varying mediump vec4 c;

当然,也可以在片元着色器中设置默认精度,只需要在片元着色器最上面加上precision <精度> <类型>即可制定某种类型的默认精度。其他情况相同的话,精度越高,画质越好,使用的资源也越多。

三 GLSL 内建变量

在着色器中我们一般都会声明变量来在程序中使用,但是着色器中还有一些特殊的变量,不声明也可以使用。这些变量叫做内建变量。內建变量,相当于着色器硬件的输入和输出点,使用者利用这些输入点输入之后,就会看到屏幕上的输出。通过输出点可以知道输出的某些数据内容。当然,实际上肯定不会这样简单,这么说只是为了帮助理解。在顶点着色器中的内建变量和片元着色器的内建变量是不相同的。着色器中的内建变量有很多,在此,我们只列出最常用的集中内建变量。

顶点着色器的内建变量

输入变量:

gl_Position:顶点坐标

gl_PointSize:点的大小,没有赋值则为默认值1,通常设置绘图为点绘制才有意义。

片元着色器的内建变量

输入变量:

gl_FragCoord:当前片元相对窗口位置所处的坐标。

gl_FragFacing:bool型,表示是否为属于光栅化生成此片元的对应图元的正面。

输出变量:

gl_FragColor:当前片元颜色

gl_FragData:vec4类型的数组。向其写入的信息,供渲染管线的后继过程使用。

四 常用内置函数

常见函数

radians(x):角度转弧度

degrees(x):弧度转角度

sin(x):正弦函数,传入值为弧度。相同的还有cos余弦函数、tan正切函数、asin反正弦、acos反余弦、atan反正切

pow(x,y):xy

exp(x):ex

exp2(x):2x

log(x):logex

log2(x):log2x

sqrt(x):x√

inversesqr(x):1x√

abs(x):取x的绝对值

sign(x):x>0返回1.0,x<0返回-1.0,否则返回0.0

ceil(x):返回大于或者等于x的整数

floor(x):返回小于或者等于x的整数

fract(x):返回x-floor(x)的值

mod(x,y):取模(求余)

min(x,y):获取xy中小的那个

max(x,y):获取xy中大的那个

mix(x,y,a):返回x∗(1−a)+y∗a

step(x,a):x< a返回0.0,否则返回1.0

smoothstep(x,y,a):a < x返回0.0,a>y返回1.0,否则返回0.0-1.0之间平滑的Hermite插值。

dFdx(p):p在x方向上的偏导数

dFdy(p):p在y方向上的偏导数

fwidth(p):p在x和y方向上的偏导数的绝对值之和


几何函数

length(x):计算向量x的长度

distance(x,y):返回向量xy之间的距离

dot(x,y):返回向量xy的点积

cross(x,y):返回向量xy的差积

normalize(x):返回与x向量方向相同,长度为1的向量

矩阵函数

matrixCompMult(x,y):将矩阵相乘

lessThan(x,y):返回向量xy的各个分量执行x< y的结果,类似的有greaterThan,equal,notEqual

lessThanEqual(x,y):返回向量xy的各个分量执行x<= y的结果,类似的有类似的有greaterThanEqual

any(bvec x):x有一个元素为true,则为true

all(bvec x):x所有元素为true,则返回true,否则返回false

not(bvec x):x所有分量执行逻辑非运算

纹理采样函数

纹理采样函数有texture2D、texture2DProj、texture2DLod、texture2DProjLod、textureCube、textureCubeLod及texture3D、texture3DProj、texture3DLod、texture3DProjLod等。

texture表示纹理采样,2D表示对2D纹理采样,3D表示对3D纹理采样

Lod后缀,只适用于顶点着色器采样

Proj表示纹理坐标st会除以q

纹理采样函数中,3D在OpenGLES2.0并不是绝对支持。我们再次暂时不管3D纹理采样函数。重点只对texture2D函数进行说明。texture2D拥有三个参数,第一个参数表示纹理采样器。第二个参数表示纹理坐标,可以是二维、三维、或者四维。第三个参数加入后只能在片元着色器中调用,且只对采样器为mipmap类型纹理时有效。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343