OpenGL图形渲染管线(Pipeline)学习
学习参考:
https://blog.csdn.net/dcrmg/article/details/53556664
https://zhuanlan.zhihu.com/p/79183044
https://blog.csdn.net/u010356727/article/details/50594401
https://www.cnblogs.com/tandier/p/8110977.html
1.0 图形渲染管线概述
图形渲染管线被认为是实时图形学中的核心部分。渲染管线的功能是通过给定虚拟相机、3D场景物体以及光源等场景要素来渲染一副2D的图像。如下图所示,场景中的3D物体通过管线转变为屏幕上的2D图像。渲染管线因此是实时渲染的底层工具。画面中对象物体的位置和形状是由它们的几何形状,环境的特性以及在环境中摄像机的位置所共同决定的。对象物体的外观表现则是由材质的属性,光源,纹理贴图,以及着色模型所影响。
左图中,一虚拟摄像机放置在棱椎的顶部(即四条线交汇处)。只有可视体内部的图元会被渲染。因为图像是以透视投影被渲染的(像这里的情况)。可视体是一个视锥体,一个有着矩形底座的截头型金字塔。右图展示了摄像机所能看见的一切。注意在左图中红色的甜甜圈形状的物体在右图中没有被渲染,因为它位于是视椎体的外面。左图中那个扭曲的蓝色棱镜状物体被视椎体顶部的平面所截断。
图形渲染管线主要包括两个功能:
- 将物体3D坐标转变为屏幕空间2D坐标
- 给屏幕每个像素点进行着色
2.0 图形渲染管线处理流程
图形渲染管线的整个处理流程可以被划分为几个阶段,上一个阶段的输出数据作为下一个阶段的输入数据,是一个串行的,面向过程的执行过程。每一个阶段分别在GPU上运行各自的数据处理程序,这个程序就是着色器(shader)。部分着色器允许我们使用着色语言(OpenGL Shading Language)编写自定义的着色器,这样就可以更为细致的控制图像渲染流程中的特定处理过程了,下图是一个图形渲染管线每一个阶段的抽象表示,蓝色部分代表允许自定义着色器。
2.1 顶点数据(Vertex Data)
顶点数据用来为后面的顶点着色器等阶段提供处理的数据。是渲染管线的数据主要来源。送入到渲染管线的数据包括顶点坐标、纹理坐标、顶点法线和顶点颜色等顶点属性。为了让OpenGL明白顶点数据构成的是什么图元,我们需要在绘制指令中传递相对应的图元信息。常见的图元包括:点(GL_POINTS)、线(GL_LINES)、线条(GL_LINE_STRIP)、三角面(GL_TRIANGLES)。
2.2 顶点着色器(Vertex Shader)
顶点着色器主要功能是进行坐标变换。将输入的局部坐标变换到世界坐标、观察坐标和裁剪坐标。虽然我们也会在顶点着色器进行光照计算(称作高洛德着色),然后经过光栅化插值得到各个片段的颜色,但由于这种方法得到的光照比较不自然,所以一般在片段着色器进行光照计算。
2.2.1 世界坐标
世界坐标是不会变的,一直以世界坐标轴的XYZ为标准。
2.2.2 局部坐标
所谓局部坐标系(Local Coordinate),也就是坐标系以物体的中心为坐标原点,物体的旋转或平移等操作都是围绕局部坐标系进行的,这时,当物体模型进行旋转或平移等操作时,局部坐标系也执行相应的旋转或平移操作。
2.2.3 观察坐标
观察坐标系又称目坐标系( Eye Coordinates),简称EC,该坐标系是一个可定义在用户坐标系中任何方向、任何地方的三维直角辅助坐标系。在观察坐标系中通常要定义一个垂直于该坐标系Z轴的平面,称观察平面。该坐标系主要用于指定裁剪空间,确定三维几何形体哪一部分需要在屏幕上输出;此外,通过观察平面可以把世界坐标系中三维几何形体需输岀部分的坐标值转换为规格化坐标系中的坐标值。
2.2.4 裁剪坐标:
在一个顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个特定的范围内,且任何在这个范围之外的点都应该被裁剪掉(Clipped)。被裁剪掉的坐标就会被忽略,所以剩下的坐标就将变为屏幕上可见的片段。这也就是裁剪空间(Clip Space)名字的由来。
2.3 图元装配(Shape Assembly)
图元组装将输入的顶点组装成指定的图元,包括点,线段,三角形等,是构成实体模型的基本单位。图元组装阶段会进行裁剪和背面剔除相关的优化,以减少进入光栅化的图元的数量,加速渲染过程。在光栅化之前,还会进行屏幕映射的操作:透视除法和视口变换。
2.4 几何着色器(Geometry Shader)
几何着色器也是渲染管线一个可选的阶段。我们知道,顶点着色器的输入是单个顶点(以及属性), 输出的是经过变换后的顶点。与顶点着色器不同,几何着色器的输入是完整的图元(比如,点),输出可以是一个或多个其他的图元(比如,三角面),或者不输出任何的图元。几何着色器的拿手好戏就是将输入的点或线扩展成多边形。下图展示了几何着色器如何将点扩展成多边形。
2.5 细分着色器(Tesselation shader(s))
曲面细分是利用镶嵌化处理技术对三角面进行细分,以此来增加物体表面的三角面的数量,是渲染管线一个可选的阶段。它由外壳着色器(Hull Shader)、镶嵌器(Tessellator)和域着色器(Domain Shader)构成,其中外壳着色器和域着色器是可编程的,而镶嵌器是有硬件管理的。我们可以借助曲面细分的技术实现细节层次(Level-of-Detail)的机制,使得离摄像机越近的物体具有更加丰富的细节,而远离摄像机的物体具有较少的细节。
2.6 光栅化(Rasterization)
光栅化是将几何数据经过一系列变换后最终转换为像素,从而呈现在显示设备上的过程。这是一个将模拟信号转化为离散信号的过程。
光栅化过程产生的是片元,片元中的每一个元素对应于帧缓冲区中的一个像素。光栅化会确定图元所覆盖的片段,利用顶点属性插值得到片段的属性信息,然后送到片段着色器进行颜色计算,我们这里需要注意到片段是像素的候选者,只有通过后续的测试,片段才会成为最终显示的像素点。
光栅化其实是一种将几何图元变为二维图像的过程。该过程包含了两部分的工作。
第一部分工作:决定窗口坐标中的哪些整型栅格区域被基本图元占用;
第二部分工作:分配一个颜色值和一个深度值到各个区域。
光栅化的本质是坐标变换、几何离散化,如下图:
2.7 片段着色器(Fragment Shader)
片段着色器用来决定屏幕上像素的最终颜色。在这个阶段会进行光照计算以及阴影处理,是渲染管线高级效果产生的地方。在计算机图形中,颜色被表示为有4个元素的数据,RGBA(RGBA是代表Red(红色)Green(绿色)Blue(蓝色)和Alpha的色彩空间),当在OpenGL或者GLSL中定义一个颜色,我们把颜色每个分量的强度设置在0.0到1.0之间。
2.7 测试与混合(Tests And Blending)
管线的最后一个阶段是测试混合阶段。测试包括裁切测试、Alpha测试、模板测试和深度测试。没有经过测试的片段会被丢弃,不需要进行混合阶段;经过测试的片段会进入混合阶段。Alpha混合可以根据片段的alpha值进行混合,用来产生半透明的效果,这些测试与混合操作决定了屏幕视窗上每个像素点最终的颜色以及透明度。
Alpha表示的是物体的不透明度,因此alpha=1表示完全不透明,alpha=0表示完全透明。测试混合阶段虽然不是可编程阶段,但是我们可以通过OpenGL或DirectX提供的接口进行配置,定制混合和测试的方式。