【OPENGL】第三篇 着色器基础(一)
在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互。
首先我们先来看看什么叫着色器。
Shader(着色器)是用来实现图像渲染的,用来替代固定渲染管线的可编程程序。
着色器替代了传统的固定渲染管线,可以实现3D图形学计算中的相关计算,由于其可编程性,可以实现各种各样的图像效果而不用受显卡的固定渲染管线限制。这极大的提高了图像的画质。
在上一篇文章( http://www.cnblogs.com/MyGameAndYOU/p/4681710.html )
关于OpenGL的第一个例子中,我们已经接触过顶点着色器(Vertex Shader)以及片段着色器(Fragment Shader)的相关代码。另外,有些书籍或者文章也将片段着色器称为像素着色器(Pixel Shader)。
话说回来,在我们了解着色器之前,让我们先了解固定渲染管线(fixed-function pipeline)究竟是什么。
渲染管线,也称之为渲染流水线,可以理解为工厂的流水线工作,而在这里它的工作是让计算机把模型通过一系列的处理最终生成图像的过程,
网上也有人这么描述它:渲染管线是显示芯片内部处理图形信号相互独立的的并行处理单元。顶点管线在GPU中的作用就是处理几何数据,并将3D数据投射到二维的屏幕上。借用一个网友说的简单例子来通俗的说明一下顶点管线和像素渲染管线的作用。一个画家在做画的时候,都需要先把所画人或物的轮廓,框架画出来,这里我们称之为“构图”;然后再根据光照进行着色,这里我们称之为“渲染”。顶点管线和像素渲染管线所起的就是这两个作用,顶点管线和引擎负责把“轮廓、框架”画出来,而像素渲染管线和引擎则负责对画好的“轮廓、框架”根据光照等因素进行着色,构成一幅完整的图形。渲染管线直接关系到显卡对画面的渲染性能。
那为何称之为固定呢?这是说芯片上一组电路已经固定实现了特定的运算功能,程序能做的只是提供场景数据以及微调运算功能的参数。我们只能通过调用不同的API组合实现特定效果,但是比较死板。
那么问题又来了,流水线的处理过程分哪些步骤呢?
关于OpenGL的流水线,大家可以看这里的图形流水线教程,非常详细。CSDN博客地址:http://blog.csdn.net/racehorse/article/details/6593719
在这里,我借助前人的经验,把相关的知识再进一步分享给大家。
一个固定渲染管线包括如下功能:
1、顶点变换(Vertex Transformation)
这里的顶点是信息的集合,包含空间中的位置、颜色、法线、纹理坐标等等。主要用于顶点位置变换、对每个顶点计算光照、纹理坐标的生成以及变换。
2、图元组合和光栅化(Primitive Assembly and Rasterization)
该阶段处理的是上一个阶段输出的变换后的顶点以及它们的连接信息。连接信息用来描述顶点如何组成图元(三角形、四边形等等)。利用在顶点变换阶段计算出的数据,结合连接信息计算出片段的数据。(例如,每个顶点包含一个变换后的位置,当它们组成图元时,就可以用来计算图元的片断位置。另一个例子是使用颜色,如果多边形的每个顶点都有自己的颜色值,那么多边形内部片断的颜色值就是各个顶点颜色插值得到的。)另外此阶段还负责视锥体(view frustum)的剪裁和背面剔除。
光栅化决定了片断(fragment),以及图元的像素位置。这里的片断是指一块数据,用来更新帧缓存(frame buffer)中特定位置的一个像素。一个片断除了包含颜色,还有法线和纹理坐标等属性,这些信息用来计算新的像素颜色值。本阶段的输出包括帧缓存中片段的位置,以及经过插值后的片段信息。
3、片断纹理化和色彩化(Fragment Texturing and Coloring)
此阶段的输入是经过插值的片段信息。在前一阶段已经通过插值计算了纹理坐标和一个颜色值,这个颜色在本阶段可以用来和纹理元素进行组合。此外,这一阶段还可以进行雾化处理。通常最后的输出是片断的颜色值以及深度信息。
4、光栅操作(Raster Operations)
此阶段的输入包括像素位置、片断深度和颜色值。这个阶段对片段进行一系列的测试,包括:剪切测试(scissor test)、Alpha测试、模版测试、深度测试。
如果测试成功,则根据当前的混合模式(blend mode)用片段信息来更新像素值。注意混合只能在此阶段进行,因为片断纹理化和颜色化阶段不能访问帧缓存。帧缓存只能在此阶段访问。
一幅图总结固定功能流水线(Visual Summary of the Fixed Functionality)
下图直观地总结了上述流水线的各个阶段:
该图的出处http://blog.csdn.net/racehorse/article/details/6593719
而在我们即将进行的着色器编程中,上述的流程,有两个阶段被编程替代
1、顶点变换(Vertex Transformation) 这个阶段使用顶点着色器实现。
2、片断纹理化和色彩化(Fragment Texturing and Coloring) 这个阶段使用片段着色器实现。
在OpenGL 3.0版本之前(包含3.0),或者使用了兼容模式(compatibility profile)的OpenGL环境下,我们还可以使用之前的固定渲染管线,在不使用着色器的情况下处理几何与像素数据。
但从3.1版本开始,固定渲染管线从核心模式(core profile)去除,所以如果使用该版本之后的核心模式来编程的话,我们必须使用着色器。
GLSL在OpenGL 2.0版本左右发布的(在之前是属于扩展功能)。与OpenGL与时俱进,它是一种专门为图形开发设计的编程语言,但我们可以从其身上找到C/C++的影子。
每一个着色器代码看起来像是一个完整的C程序,同样有一个main入口函数。但是与C不同的是,着色器的main函数没有任何参数,在某个着色阶段中的输入和输出的所有数据都是通过着色器中的特殊全局变量来传递的。最重要一点是,不要把它们与应用程序中的全局变量混淆,它们两者没有任何关系。
#version 430 core in vec4 vPosition in vec4 vColor; out vec4 color; uniform mat4 ModelViewProjectionMatrix; void main(){ color = vColor; gl_Position = ModelViewProjectionMatrix * vPosition; }
正如上面的代码,OpenGL会使用输入和输出变量来传递着色器所需要的数据,变量的值会在OpenGL每次执行着色器的时候更新。
还有一种是变量是直接从OpenGL应用程序中接收数据的,称为uniform变量。uniform表示唯一,对所有几何图元的值都是一致的,除非应用程序对它执行了更新,否则着色器是并不会影响它的值的变化的。
在这一小节中,我们主要了解什么是着色器,为什么会出现着色器,它和固定管线有什么区别。另外,还有图形流水线知识,下一小节,我们会继续学习GLSL的基本变量以及相关操作。
2015.08.12
广州
posted on 2015-08-12 00:11 alwaystiys 阅读(2809) 评论(0) 编辑 收藏 举报