Shader
这篇文章我们将简单介绍一下Shader与对Shader编程,在此将讨论OpenGL的Shader语言GLSL。
首先推荐教程(毕竟我这里只是我自己学的经历,为防止错误的思想误导了别人,还是先摆出比较正确的教程再说)
1. 着色器
2. GLSL
着色器(英语:shader)应用于计算机图形学领域,指一组供计算机图形资源在执行渲染任务时使用的指令,用于计算图像的颜色或明暗。但近来,它也能用于处理一些特殊效果,或者视频后处理。通俗地说,着色器告诉电脑如何用特有的一种方法去绘制物体。
程序员将着色器应用于图形处理器(GPU)的可编程流水线,来实现三维应用程序。这样的图形处理器有别于传统的固定流水线处理器,为GPU编程带来更高的灵活性和适应性。以前固有的流水线只能进行一些几何变换和像素灰度计算。现在可编程流水线还能处理所有像素、顶点、纹理的位置、色调、饱和度、明度、对比度并实时地绘制图像。着色器还能产生如模糊、高光、有体积光源、失焦、卡通渲染、色调分离、畸变、凹凸贴图、边缘检测、运动检测等效果
Direct3D和OpenGL都使用了以下三种着色器:
- 顶点着色器处理每个顶点,将顶点的空间位置投影在屏幕上,即计算顶点的二维坐标。同时,它也负责顶点的深度缓冲(Z-Buffer)的计算。顶点着色器可以掌控顶点的位置、颜色和纹理坐标等属性,但无法生成新的顶点。顶点着色器的输出传递到流水线的下一步。如果有之后定义了几何着色器,则几何着色器会处理顶点着色器的输出数据,否则,光栅化器继续流水线任务。
- 几何着色器可以从多边形网格中增删顶点。它能够执行对CPU来说过于繁重的生成几何结构和增加模型细节的工作。Direct3D版本10增加了支持几何着色器的API, 成为Shader Model 4.0的组成部分。OpenGL只可通过它的一个插件来使用几何着色器,但极有可能在3.1版本中该功能将会归并。几何着色器的输出连接光栅化器的输入。
- 像素着色器(Direct3D),常常又称为片断着色器(OpenGL),处理来自光栅化器的数据。光栅化器已经将多边形填满并通过流水线传送至像素着色器,后者逐像素计算颜色。像素着色器常用来处理场景光照和与之相关的效果,如凸凹纹理映射和调色。名称片断着色器似乎更为准确,因为对于着色器的调用和屏幕上像素的显示并非一一对应。举个例子,对于一个像素,片断着色器可能会被调用若干次来决定它最终的颜色,那些被遮挡的物体也会被计算,直到最后的深度缓冲才将各物体前后排序。
统一着色器模型将上述三种着色器统一起来,发布于OpenGL和Direct3D 10里面。
这一大堆来自于维基百科的介绍,我们可以从中得到一堆的名词,暂时需要记住的就【顶点着色器】和【片段着色器】,我们也将使用这两个着色器让我们的三角形显示出来。
首先介绍一些Shader的基本构造:
1 |
|
GLSL是一种类C语言,in , out , uniform都是他的关键字 ,type则是float , int等等的基本类型。在GLSL中有int
,float
,double
,uint
,bool
这几种基本类型,还有高级一些的向量和矩阵(暂且不提)类型。
向量
GLSL中的向量是一个可以包含有1、2、3或者4个分量的容器,分量的类型可以是前面默认基础类型的任意一个。它们可以是下面的形式(n
代表分量的数量):
类型 | 含义 |
---|---|
vecn |
包含n 个float分量的默认向量 |
bvecn |
包含n 个bool分量的向量 |
ivecn |
包含n 个int分量的向量 |
uvecn |
包含n 个unsigned int分量的向量 |
dvecn |
包含n 个double分量的向量 |
当前我们的目标是给三角形着色,这需要用到顶点着色器和片段着色器。我们首先需要一个顶点着色器的代码:
1 |
|
还有一个片段着色器:
1 |
|
我们可以将这两个着色器程序写入文件,然后从文件里读出来编译,也可以像我这样直接写成语句。
1 | GLchar const* vertexShaderSource = |
写好了着色器程序,接下来是要编译链接他
1 | //创建缓冲器 |
这里我们注意的是检查着色器那里,我们用了glGetShaderiv
获得着色器编译信息GL_COMPILE_STATUS
和
GL_INFO_LOG_LENGTH
,当着色器出错,GL_INFO_LOG_LENGTH > 0
,就要查看着色器编译过程中的错误信息了,使用glGetShaderInfoLog
获得。
这些执行完成后,我们的代码基本已经成了,在main的循环里使用这个已经链接着色器的program就可以了。
1 | glUseProgram(program); |
在最后修改的时候我的完整代码经过了一些更改,如下:
1 |
|
这个代码中使用了uniform变量
uniform变量是外部application程序传递给(vertex和fragment)shader的变量。因此它是application通过函数glUniform()函数赋值的 。在(vertex和fragment)shader程序内部,uniform变量就像是C语言里面的常量(const),它不能被shader程序修改。也就是说shader只能用不能改uniform变量。