GLSL的简介(上)

最近开始研究NPR(非真实性)渲染,感觉还是用GLSL自己写着色器比较靠谱。于是找了NEHE的一篇对GLSL的简介翻译一下,当做入门。

什么是GLSL?

GLSL(GLslang)是官方的opengl着色语言的简称(OpenGL Shading Language)GLSL是类似于C/C++的高级语言,适用于一部分显卡。使用GLSL,你能够编写一些短小的程序,称为着色器(shader),这些着色器在GPU上运行。

为什么使用着色器?

DirectX 8的硬件之前(GeForce 2以及更久的显卡,Radoen 7000以及更旧的显卡),图形的渲染管线只能设置一些参数,不能被编程。举个例子,OpenGL的光照模型有环境光、漫射光、反射光和发射光。这个光照模型虽然被广泛使用,但其实还有许多其他的光照模型。在OpenGL的固定渲染管线中,只能使用这个内置的光照模型,不能使用其他的。而使用着色器,你就能编写自己的光照模型。但这也只是着色器的特点之一,还有许多其他的可能性:阴影(Shadows)、环境映射(Environment Mapping)、逐个像素的光照(Per-Pixel Lighting)、凹凸贴图(Bump Mapping)、平行凹凸贴图(Parallax Bump Mapping)、高动态范围(HDR)

为什么选择GLSL?

着色器直到2002年才通过ARB_vertex_program ARB_fragment_program这两个扩展加入到OpenGL。但是使用这些扩展你只能使用汇编着色器(assembly shaders)。因为光照和着色模型越来越复杂,汇编着色器使用起来非常困难。GLSL是是一种高级着色语言,这意味着你能用类似于C/C++的风格编写自己的着色器。这使得编写着色器简单很多。

OpenGL的固定管线和GLSL有何区别?

GLSL中有两种类型的着色器:顶点着色器(vertex shaders)和片段着色器(fragment shaders)

顶点着色器

顶点着色器在每个顶点上运行,因此如果你调用glVertex*(或者 glDrawArrays),顶点着色器会在每个顶点上执行。如果你使用自己编写的顶点着色器,你就几乎完全控制了关于顶点的运算。但是如果你使用了自己编写的着色器,固定管线中所有的关于顶点的运算就会被替换,比如顶点变换(模型视图变换、投影变换)、法线变换(归一化(Normalization)和重新调节(Rescaling))、光照、纹理坐标生成和变换。关于一个自定义的顶点着色器替换和没有替换的部分的具体情况,请参考[1]41页。所以如果你想使用顶点着色器,你必须自己编写上述的几个运算(如果你需要的话)。

片段着色器

片段着色器在每个由光栅化生成的片段上运行。使用片段着色器,你几乎能完全控制有关片段的运算。但是就像顶点着色器一样,自定义的片段着色器会替换固定管线中所有关于片段的运算,包括:纹理的访问和使用(纹理环境)、雾。关于自定义的片段着色器替换的功能的细节,参考[1]43页。正如使用顶点着色器,使用片段着色器的时候你要自己完成所有关于片段的运算(如果需要的话)

下面是OpenGL1.5的固定渲染管线:

GLSL长什么样的?

正如上面所述有两种着色器(其实现在有三种,另外一种是后来加入的),顶点着色器和片段着色器。每种着色器有不同的输入和输出。

GLSL中的数据类型

GLSL中主要有4种数据类型:floatintboolsampler。对于前面的3种类型,都有相应的vector类型:

2D,3D4Dfloat类型的vector:vec2,vec3,vec4

2D,3D4Dint类型的vector:ivec2,ivec3,ivec4

2D,3D4Dbool类型的vector:bvec2,bvec3,bvec4

对于float类型还有matrix类型,分别对应2*2矩阵、3*3矩阵、4*4矩阵:mat2,mat3,mat4

sampler类型代表纹理,由于纹理采样。sampler类型必须归一化,不允许被声明为不归一的类型,下面是几种不同的sampler类型:

1D,2D3D纹理:sampler1D,sampler2D,sampler3D

立方体映射纹理:samplerCube

1D2D深度组件纹理(depth-component texture):sampler1Dshadow,sampler2Dshadow

关于属性(Attributes),常量(Uniforms)和变量(Varyings)

在着色器中有三种输入和输出:uniforms, attributes varyings

Uniforms是在一次渲染中不会改变的值,比如光源的位置或者光的颜色。Uniforms在顶点和片段着色器中都可以用。Uniforms是只读的。Attributes只在顶点着色器中可用,它们是输入值,随着每个顶点变化,比如顶点位置和法线。Attributes是只读的。Varyings 被用于将数据从顶点着色器传送到片段着色器。Varyings在图元上进行插值(与透视相关)Varyings 在片段着色器中是只读的,但是在顶点着色器中是可读写的(但是注意,在写一个Varying类型的值之前读取会得到一个未定义的值)。 如果你想使用varyings ,你必须在顶点着色器和片段着色器中声明相同的varying 。所有的uniform, attribute and varying 类型都是全局的。你不能在一个函数中定义uniform/attribute/varying。

内置的类型

GLSL在顶点着色器中有一些内置的attributes 类型:

gl_Vertex :代表顶点位置的4D向量           

gl_Normal :代表顶点法线的3D向量             

gl_Color :代表顶点颜色的4D向量      

gl_MultiTexCoordX :代表纹理坐标的4D向量   

还有一些其他的内置attributes 类型,参考[2], 41页,里面有一个完整的清单。

GLSL 也有一些内置的uniforms类型:

gl_ModelViewMatrix :代表模型视图矩阵的4X4矩阵。      

gl_ModelViewProjectionMatrix :代表模型视图投影矩阵的 4X4矩阵。   

gl_NormalMatrix :代表模型视图矩阵的逆置换矩阵的3X3矩阵。这个矩阵用于法线变换。

还有一些其他的内置uniforms类型,比如光照状态,参考[2], 42页,里面有一个完整的清单。

GLSL 内置的变量

gl_FrontColor :代表图元正面的颜色的4D向量            

gl_BackColor :代表图元背面的颜色的4D向量

gl_TexCoord[X] :代表第X个纹理上的纹理坐标的4D向量

还有一些其他的内置变量,参考[2], 44页,里面有一个完整的清单。

另外有一些内置的类型用于着色器的输出:

gl_Position  :代表经过最后处理的顶点的位置的4D向量,只在顶点着色器中可用。

gl_FragColor  :代表帧缓存的最后的颜色的4D向量。只在片段着色器中可用。              

gl_FragDepth  :代表深度缓存的最后的深度的float类型的值,只在片段着色器中可用。内置类型的重要性在于它们对应与OpenGL的状态。比如你调用glLightfv(GL_LIGHT0, GL_POSITION, my_light_position),那么my_light_position这个值可以在顶点着色器或者片段着色器中使用gl_LightSource[0].position作为uniform被访问。

自定义的类型

你可以自定义attributes, uniforms 和varyings。比如如果你想从你的应用为每一个顶点传送一个正切向量到顶点着色器,你可以定义一个Tangent attribute类型:

attribute vec3 Tangent

这里有一些其他例子:

uniform sampler2D my_color_texture; 

uniform mat4 my_texture_matrix; 

varying vec3 vertex_to_light_vector; 

varying vec3 vertex_to_eye_vector; 

attribute vec3 tangent; 

attribute vec3 binormal; 

语言的细节

GLSL 与C/C++类似但是有一些细微的差别。参考[1],57页,ANSI C features which are not supported in GLSL。

另外GLSL 具有以下的特点/约束:

GLSL是100%类型安全的。你不能将一个整型不加转换直接传给一个浮点型:

float my_float = 1;         // Won’t Work! “1” Is An Integer! 

float my_new_float = 1.0;       // Will Work! 

Casts have to be done using constructors. For example this won’t work:

类型转换必须使用构造器。比如下面的代码:

vec2 my_vec; 

ivec2 my_int_vec; 

my_vec2 = (vec2)my_int_vec;     // Won’t Work Because No Constructor Is Used! 

my_vec2 = vec2(my_int_vec);     // Will Work!

向量和矩阵只能使用构造器赋值:

vec3 my_vec = vec3(1.0, 1.0, 1.0); 

mat3 my_mat = mat3(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0); 

向量相乘是按分量逐个作出的乘积:

vec3 my_vec1 = vec3(5.0, 1.0, 0.0); 

vec3 my_vec2 = vec3(1.0, 3.0, 4.0); 

vec3 product = my_vec1 * my_vec2;   // Will Return This Vector: (5.0, 3.0, 0.0) 

也可以对向量和矩阵进行相乘。
矩阵* 向量将把向量当做列向量(OpenGL标准)。
向量* 矩阵将把向量当做行向量 (DirectX 标准)。

比如一个顶点以这种方式进行法线变换:

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex 

这将简单地将顶点的位置通过模型视图投影矩阵变换。也可以使用其他内置的运算子:

dot        :点乘

cross      :叉乘

texture2D   :用于对纹理采样

normalize   :对一个向量规格化

clamp   :将一个向量固定在一个最小值和最大值之间    

关于全部内置的运算子,参考[2],46页。

每个着色器必须有一个 main函数,这个main函数在着色器执行时被调用。

由于内容太多,剩下的内容下次继续翻译,敬请期待。

References:

[1] OpenGL Shading Language Master Class Notes, 3DLabs, March/April 2004
http://www.3dlabs.com/support/developer/ogl2/presentations/GLSLMasterClass2004.pdf
[2] The OpenGL Shading Language Specification Version 1.051, 3DLabs, February 2003
http://www.3dlabs.com/support/developer/ogl2/downloads/ShaderSpecV1.051.pdf
[3] The OpenGL extension registry
http://oss.sgi.com/projects/ogl-sample/registry/
[4] OpenGL shading language “The orange book”, Randi J. Rost, ISBN 0-321-19789-5
http://www.3dshaders.com/

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值