一、渲染
定义:将数学和图形数据转换成3D空间图像的操作;
简而言之,渲染就是将公式或者一堆数据,转换成一个立体的3D图形,例如:
- 函数:f(x) = sin(x) x∈[0,π],我们可以将其图形绘制出来,是一个正弦图像,绘制的过程就是渲染;
- 数据:(-1, 0)、(1, 0)、(0 ,1),这个是三个点,我们可以将点连起来闭环,是一个三角形,绘制的过程就是渲染;
1.1、渲染管线
OpenGL中常说的**“渲染管线”**,是指一系列数据处理的过程,并且将应用程序的数据转换到最终渲染的图像
图形渲染管线的整个处理流程可以被划分为几个阶段,上一个阶段的输出数据作为下一个阶段的输入数据,是一个串行的,面向过程的执行过程;
每一个阶段分别在GPU上运行各自的数据处理程序,这个程序就是着色器(shader)。部分着色器允许我们使用着色语言GLSL(OpenGL Shading Language)编写自定义的着色器,这样就可以更为细致的控制图像渲染流程中的特定处理过程了;
下图是一个图形渲染管线每一个阶段的抽象表示,蓝色部分代表允许自定义着色器。
1.1.1、顶点数据(Vertex Data)
- 顶点数据用来为后面的顶点着色器等阶段提供处理的数据,是渲染管线的数据主要来源;
- 送入到渲染管线的数据包括顶点坐标、纹理坐标、顶点法线和顶点颜色等顶点属性;
- 为了让OpenGL明白顶点数据构成的是什么图元,我们需要在绘制指令中传递相对应的图元信息;
- 常见的图元包括:点(GL_POINTS)、线(GL_LINES)、线条(GL_LINE_STRIP)、三角面(GL_TRIANGLES)等;
1.1.2、顶点着色器(Vertex Shader)
- 顶点着色器主要功能是进行坐标变换:将输入的局部坐标变换到世界坐标、观察坐标和裁剪坐标;
- 虽然我们也会在顶点着色器进行光照计算(称作高洛德着色),然后经过光栅化插值得到各个片段的颜色;
- 但是由于这种方法得到的光照比较不自然,所以一般在片段着色器进行光照计算;
1.1.2.1、世界坐标
- 世界坐标是不会变的,一直以世界坐标轴的XYZ为标准;
- 即X轴正半轴水平向右,Y轴正半轴垂直向上,Z轴正半轴为垂直屏幕向外;
1.1.2.2、局部坐标
- 所谓局部坐标系(Local Coordinate),也就是坐标系以物体的中心为坐标原点,物体的旋转或平移等操作都是围绕局部坐标系进行的;
- 这时,当物体模型进行旋转或平移等操作时,局部坐标系也执行相应的旋转或平移操作;
1.1.2.3、观察坐标
- 观察坐标系又称目坐标系( Eye Coordinates),简称EC,该坐标系是一个可定义在用户坐标系中任何方向、任何地方的三维直角辅助坐标系;
- 在观察坐标系中通常要定义一个垂直于该坐标系Z轴的平面,称观察平面;
- 该坐标系主要用于指定裁剪空间,确定三维几何形体哪一部分需要在屏幕上输出;
- 此外,通过观察平面可以把世界坐标系中三维几何形体需输岀部分的坐标值转换为规格化坐标系中的坐标值。
1.1.2.4、裁剪坐标
- 在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped);
- 被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段,这也就是裁剪空间(Clip Space)名字的由来;
1.1.3、图元装配(Shape Assembly)
- 图元组装将输入的顶点组装成指定的图元,包括点,线段,三角形等,是构成实体模型的基本单位;
- 图元组装阶段会进行裁剪和背面剔除相关的优化,以减少进入光栅化的图元的数量,加速渲染过程;
- 在光栅化之前,还会进行屏幕映射的操作:透视除法和视口变换;
1.1.4、几何着色器(Geometry Shader)
- 几何着色器也是渲染管线一个可选的阶段;
- 顶点着色器的输入是单个顶点(以及属性), 输出的是经过变换后的顶点;
- 与顶点着色器不同,几何着色器的输入是完整的图元(比如,点),输出可以是一个或多个其他的图元(比如,三角面),或者不输出任何的图元;
- 几何着色器的拿手好戏就是将输入的点或线扩展成多边形;
1.1.5、细分着色器(Tesselation Shader(s))
- 曲面细分是利用镶嵌化处理技术对三角面进行细分,以此来增加物体表面的三角面的数量,是渲染管线一个可选的阶段;
- 它由外壳着色器(Hull Shader)、镶嵌器(Tessellator)和域着色器(Domain Shader)构成;
- 其中外壳着色器和域着色器是可编程的,而镶嵌器是有硬件管理的;
- 我们可以借助曲面细分的技术实现细节层次(Level-of-Detail)的机制,使得离摄像机越近的物体具有更加丰富的细节,而远离摄像机的物体具有较少的细节;
1.1.6、光栅化(Rasterization)
- 光栅化是将几何数据经过一系列变换后最终转换为像素,从而呈现在显示设备上的过程;
- 这是一个将模拟信号转化为离散信号的过程;
- 光栅化过程产生的是片元,片元中的每一个元素对应于帧缓冲区中的一个像素;
- 光栅化会确定图元所覆盖的片段,利用顶点属性插值得到片段的属性信息;
- 然后送到片段着色器进行颜色计算,我们这里需要注意到片段是像素的候选者,只有通过后续的测试,片段才会成为最终显示的像素点;
光栅化其实是一种将几何图元变为二维图像的过程。该过程包含了两部分的工作:
- 决定窗口坐标中的哪些整型栅格区域被基本图元占用;
- 分配一个颜色值和一个深度值到各个区域;
光栅化的本质是坐标变换、几何离散化,如下图:
1.1.7、片段着色器(Fragment Shader)
- 片段着色器用来决定屏幕上像素的最终颜色;
- 在这个阶段会进行光照计算以及阴影处理,是渲染管线高级效果产生的地方;
- 在计算机图形中,颜色被表示为有4个元素的数据,RGBA(RGBA是代表Red(红色)Green(绿色)Blue(蓝色)和Alpha的色彩空间);
- 当在OpenGL或者GLSL中定义一个颜色,我们把颜色每个分量的强度设置在0.0到1.0之间;
1.1.7、测试与混合(Tests And Blending)
- 管线的最后一个阶段是测试混合阶段;
- 测试包括裁切测试、Alpha测试、模板测试和深度测试;
- 没有经过测试的片段会被丢弃,不需要进行混合阶段,经过测试的片段会进入混合阶段;
- Alpha混合可以根据片段的alpha值进行混合,用来产生半透明的效果,这些测试与混合操作决定了屏幕视窗上每个像素点最终的颜色以及透明度;
- Alpha表示的是物体的不透明度,因此alpha=1表示完全不透明,alpha=0表示完全透明;
- 测试混合阶段虽然不是可编程阶段,但是我们可以通过OpenGL或DirectX提供的接口进行配置,定制混合和测试的方式;
二、变换和投影
变换定义:顶点可以通过变换矩形
就行旋转,并在点之间绘制线段,就可以在2D屏幕上创造出一个3D世界的错觉;
投影定义:顶点可以通过投影矩形
将3D坐标转换成二维屏幕坐标;
-
正投影(平行投影):所有实际大小相同的物体在屏幕上都具有相同的大小,不管它们是远是近;它的视景体是一个正方形或者长方形
-
透视投影:远处的物体看上去比近处的物体更小一些;它的视景体看上去像是一个顶部被削平的金字塔,剩下来的这个形状称为平截头体;
三、光栅化
定义:绘制或填充每个定点之间的像素形成的线段就叫做光栅化;
我们上学的时候在纸面上绘制立方体,通常会将背面看不到的线段画为虚线,这在图形学上称为线框渲染,虽然可以展现3D效果,但是效果并不是特别好,所以我们通常用实心三角形进行渲染,三角形会被光栅化或者填充,这样就和我们现实世界中看到的效果差不多;
四、着色
定义:沿着顶点对表面进行上色;
着色器(Shader)是在图形硬件上执行的单独程序,用来处理顶点和执行光栅化的任务;
在实时计算机图形中,最前沿的技术是可编程着色器。今天的图像卡不再是低能的渲染芯片,而是功能强大的高度可编程的渲染计算机。当今图形卡上的可编程芯片:GPU(图形处理单元),和CPU高度并行,并且具有非常快的速度,程序员可以进行重新配置图形卡的工作方式,几乎可以实现任何可以想到的特殊效果;
五、纹理贴图
定义:一个纹理不过是一副用来贴到多边形上的图片,所以纹理贴图就是给立方体贴一张图片;
纹理将渲染提高到了一个崭新的层次,当需要在物体表面展示复杂的效果时,如果纯靠自己用三角形进行绘制,可能需要成千上万个三角形进行组合,工作量飙升,如果采用贴图,准备好图片之后,直接贴上去就行了;
六、混合
定义:将不同的颜色混在一起,也可以应用混合使物理看起来透明
例如:我们要展示一个带倒影的立方体
- 我们首先上下颠倒地绘制这个立方体,即先绘制倒影部分;
- 然后在这个立方体上面绘制地板,并与其混合;
- 最后再地板上面绘制正常方向的立方体;