openGL着色语言(GLSL)简单的说就是openGL中定义的子语言,专门用来编写着色器的。GLSL作为opengL的组成部分是在openGL2.0这个版本中加进去的。大家也许对着色器也并不陌生了,(如果陌生的话,维基一下)那么我们为什么要自己编写着色器呢?opengL提供的传统渲染模型就能够被我们一般的程序所使用,而不需要自己去沾上GLSL。虽然GLSL并不是太难,但是要是学习一门新的小语言,还是要几天时间来熟悉的吧。实际上,GLSL提供了更为强大的功能,它可以自己定义渲染的方式,不会受到传统固定渲染方法的束缚。下面是openGL着色器所能做到的事(参考自橙宝书):
日益逼真的材质——金属、岩石、木头、和油漆等
日益逼真的光照效果——区域光和软阴影等
自然现象——火、烟、水和云等
非现实材质——美术效果、钢笔画、水墨画和对插画技术的模拟等
针对纹理内存的新用途——用纹理存储法线、光泽值和多项式系数,用来进行并行计算
更少的纹理访问——可以程序化地创建纹理而不是通过访问存储在纹理内存中的纹理贴图
图像处理——旋转、边缘钝化遮蔽和复杂混合等
动画效果——关键帧插值、粒子系统、程序化定义的动作
用户可编程的反走样方法。
这里面仅仅介绍了一些最基础的东西,更详细的内容还是参考《opengl着色语言》简称橙宝书。这本书第三版的英文版《opengl shading language》在百度文库上可以下到。中文版的图书只有第一版的,是人民邮电出版社出版的。大概这个太小众了吧,都没有最新版的翻译了。但是我粗略对比了一下,内容 变化不大!
GLSL变量修饰符
修饰符给出了变量的特殊含义,GLSL中有如下修饰符:
·const – 声明一个编译期常量。
·attribute– 随不同顶点变化的全局变量,由OpenGL应用程序传给顶点shader。这个修饰符只能用在顶点shader中,在shader中它是一个只读变量。
·uniform– 随不同图元变化的全局变量(即不能在glBegin/glEnd中设置),由OpenGL应用程序传给shader。这个修饰符能用在顶点和片断shader中,在shader中它是一个只读变量。一般用的最多的就是这个了,我们就是通过这个在应用程序中把变量传给着色器,让着色器进行处理。一般传进去的都是数组、纹理、变量等等。
·varying –用于顶点shader和片断shader间传递的插值数据,在顶点shader中可写,在片断shader中只读。这个变量的作用就是通过顶点着色器进行修改或者求得,然后传给片元着色器,varying是两种着色器沟通的唯一桥梁喔!需要注意的是:只能顶点着色器传给片元着色器,而片元着色器不能传给顶点着色器,如果了解opengL的渲染管线,也就大概知道其中缘由了。
(在GLSL1.40中”attribute”和”varying”都删除了,在使用GL_ARB_compatibility扩展的时候依然可以使用它们)
数据类型和变量
下面是GLSL中的基本数据类型:
·float
·bool
·int
浮点类型与C中类似,布尔类型可以为true或false。
矢量:
·vec2就是一个2维的矢量,后面的数字最大为4。见下面说明
·vec{2,3,4} avector of 2,3,or 4 floats
·bvec{2,3,4} bool vector
·ivec{2,3,4} vectorof integers
这种变量的声明有C++ 的构造函数的风格。比如
Vec4 a = vec4(1,2,3,4)这样我们就定义了一个四维的向量a;
我们可以使用下面的名称来选择矢量的各个部分:
x,y,z,w 将矢量看做位置或者方向
r,g,b,a 将矢量看做一种颜色
s,t,p,q 将矢量看做一个纹理坐标
例如a.xy可以看做一个四维的空间中我取x,y的坐标。
矩阵:
GLSL还包括2×2、3×3或4×4型矩阵,因为这些矩阵类型在图形处理中很常用:
·mat2
·mat3
·mat4
取样器:
此外,还有一组用来实现纹理访问的特殊类型,它们被称为采样器(sampler),在读取纹理值(也称为纹素texel)时用到。下面就是纹理采样用到的数据类型:
·sampler1D – for 1D textures
·sampler2D – for 2D textures
·sampler3D – for 3D textures
一般的使用方式是是在着色器中声明:
Uniform sampler2D textName
然后在着色器中vec4 tmp = texture2D(textName,gl_TexCoord[0].st);
这样tmp就读到了纹理的灰度值。具体可以看我其他博客上写的完整代码。
大家还有可能看到sampler*DRect这种形式,因为上面的读取的是归一化后的纹理坐标,就是在0~1之间的。加了Rect后,我们就可以按照正常的坐标进行读取,比如说(128,512)就是一个纹理的坐标。
混合:
这个就举个例子大家可以理解一二了,
vec pos = vec4(1.0,2.0,3.0,4.0);
pos.xw = vec2(5.0,6.0);
那么pos现在的值是pos=(5.0,2.0,3.0,6.0);
按部分操作:
对一个矢量应用操作符时,其行为方式就像是独立应用于矢量的各个部分那样
例如:
vec3 v,u;
float f;
v = u + f;
等价于:
v.x =u.x +f;
v.y = u.y +f;
v.z = u.z +f;
而
vec3 v,u,w;
w= v+u;
等价于:
w.x= v.x+u.x;
w.y=v.y+u.y;
w.z = v.z + u.z;
强制类型转换:
假如我们想要将一个int转化为float,必须显示转换。这里不像C那样给你自动的隐式转化的。
int a;
float b;
b = int(a); //这样就完成了转换,跟C很不一样吧
GLSL支持的运算符:
注意:这里没有求模运算符了,这么好用的东西居然没有!!