OpenGL 图形渲染管线

学习笔记,自用 ヾ(•ω•`)o
参考:《细说图形管线》、games101等等

大致流程

CPU
即应用阶段
(1) 把数据加载到显存中
(2) 设置渲染状态
(3) 调用 draw Call

GPU
● VS
  得到clip裁剪坐标 + 顶点着色
  模型空间 Model—M(model) —>世界空间 world—V (view) —>观察空间 view—P(project) —>裁剪空间 clip—透射除法—>标准设备空间 Normalized Device Coordinates,NDC —视口变换Viewport —屏幕空间 screen
TS 针对点
  gpu自动
  曲面细分(一个点变成多个点,针对顶点)➕ 图元装配(点装配成图元,同时进行裁剪,背面剔除
● GS 针对图元
  可选阶段,按照某个规律创建或销毁几何图元
  实现公告栏(BillBoards)
  pcre数据传输非常慢,cpu准备好数据,传输gpu,处理
光栅化
  三角形的组装三角形的遍历
  对顶点的输入数据(比如,颜色、法线、纹理坐标)进行插值得到片段的属性信息(片段是像素的候选者)
  采样离散化的过程,确定图元覆盖的片段
● FS
  光照着色纹理映射
● Tests & Blending
  alphaTest,透明度测试,透明度在某个范围内才渲染,做着色之后可能改,所以大部分
  zTest,深度测试(depth覆盖,color覆盖)
  stencilTest: 模板检测,只对某一个mask内的东西着色
  Alpha混合

【early-z】
  三个test正常是放在VS之后做,early-z在vs之前先比较,过了之后再着色,弊端:所有程序不能改变depth ,且只能用在非透明物体
解决:分片段,对非透引入early-z
【延迟渲染】:
  前向是基于fragment渲染,特殊的延迟渲染是基于像素

【隐藏面消除】
  视椎体剔除(应用程序阶段CPU端) 、裁剪+背面剔除(图元组装)、Z-Buffer(针对像素点)、入口剔除 (Portal Culling)、遮挡剔除 (Occlusion Culling)


管线的划分粒度不一样,但是每个阶段的具体功能其实是差不多的

《Real Time Rendering》一书将渲染管线划分为以下四个阶段:
应用程序阶段(Application):
  在CPU端进行处理,包括碰撞检测、动画物理模拟以及视椎体剔除等任务,这个阶段会将数据送到渲染管线中;
几何处理阶段(Geometry Processing):
  投影变换、裁剪和屏幕映射 + 顶点着色器的功能
光栅化(Rasterization):
  图元离散化片段的过程
像素处理阶段(Pixel Processing):
  像素着色和混合的功能

细说图形渲染管线

顶点数据:

  顶点数据用来为后面的顶点着色器等阶段提供处理的数据。送入到渲染管线的数据包括顶点坐标、纹理坐标、顶点法线和顶点颜色等顶点属性。
  用三角形网格来近似表示物体,用指定的3个顶点来定义三角形。由于相邻三角形会存在顶点共用的情况,尤其在物体网格非常复杂的情况下,冗余数据会非常多。我们可以通过使用索引(顶点缓存对象 vertex buffer object VBO)来避免共享顶点间数据的多余。
  顶点缓冲对象VBO是在显卡存储空间中开辟出的一块内存缓存区,而不是在内存中,不需要从CPU传输数据,处理效率更高。可以开辟很多个VBO,每个VBO在OpenGL中有它的唯一标识ID,这个ID对应着具体的VBO的显存地址,通过这个ID可以对特定的VBO内的数据进行存取操作。

VS (顶点着色器Vertex Shader):

【功能】得到裁剪坐标 + 顶点着色
【顶点坐标变换】
  模型空间 Model—M(model) —>世界空间 world—V (view) —>观察空间 view—P(project) —>裁剪空间 clip—透射除法—>标准设备空间 Normalized Device Coordinates,NDC —视口变换Viewport —屏幕空间 screen

裁剪空间:以原点为中心的立方体, -w~w范围内
NDC: [-1,1]
屏幕:适应屏幕大小,做视口变化
投影:正交+透视,透视视锥体由四个参数定义:近平面(Near)、远平面(Far)、垂直视场角(Vertical Field of View, FOV)和屏幕纵横比(Aspect Ratio,也叫作屏幕宽高比)

【MVP】
M–
做旋转、平移、缩放
绕ZXY旋转公式:
在这里插入图片描述
V–
在这里插入图片描述
P–
P = 缩放矩阵 . 位移矩阵 .“挤压”矩阵
“挤压”矩阵求解过程:
首先利用近似三角形得到“挤压”矩阵的124行
根据近平面不变(x, y, n, 1)-> (x, y, n, 1)(nx, ny, n^2, n)
根据远平面中心点不变 (0, 0, f, 1)-> (0, 0, f, 1)(0, 0, f^2, f)
在这里插入图片描述
在这里插入图片描述
1、光照计算一般都是在世界空间进行的
2、在变换法线时,如果存在非均匀缩放变换,需要使用矩阵的逆的转置来变换法线。
在这里插入图片描述
3、在view space, 虚拟摄像机的位置是坐标的原点,观察方向沿着Z轴的负方向
在这里插入图片描述
4、透视投影和正交投影
透视投影本质就是对xyz分量进行了不同程度的缩放(当然, z分量还做了个平移), 此时顶点的W分量不再1, 而是-z; 而正交投影变换并没有改变W分量的值(W分量的值仍是1)
5、屏幕映射(透射除法+视口变换)
主要是硬件实现,不同厂商会有不同的设计,顺序的话放在光栅化之前就行了
透射除法:除以w分量
  是为了实现透射投影中近大远小的视觉效果,经过了投影矩阵Projection的变换后,W分量保留了观察空间中物体Z坐标的信息,所以透视除法才能够根据距离摄像机的远近正确实现透视效果。
  对于正交投影,透视除法并没有实际的效果。
使用齐次坐标的意义,其实就是为了正确记录下投影变换前(观察空间)中物体的深度信息,也就是Z坐标的值。

拾取(Picking) :
与投影变换和视口变换相反的一种变换是, 根据屏幕坐标反算出对应的3D对象。


【顶点着色】
在这里插入图片描述
平面着色、高洛德着色和冯氏着色;在画面效果和性能开销之间进行取舍

平面着色:是使用一个顶点颜色来代表整个三角面的颜色
高洛德着色:计算三个顶点的光照信息,然后在光栅化阶段插值得到三角形内部各个片段的光照信息。
冯氏着色:就是在片段着色器中计算每个片段的光照信息。开销最大,同时效果也是最好的。 会根据输的顶点法线信息在光栅化阶段插值得到各个片段的法线信息,然后在片段着色器中利用法线、纹理坐标、位置等信息计算每个片段的光照信息。

TS(triangle shader)

【作用】曲面细分(一个点变成多个点,针对顶点)+ 图元装配/组装(产生一序列的三角形、线段和点,之后就是对超出屏幕外的三角形进行裁剪)

1、曲面细分着色器(Tessellation Shader)
曲面细分:是利用镶嵌化处理技术对三角面进行细分,在顶点与顶点之间自动嵌入新的顶点,从而提升模型精度,提高渲染效果,是DirectX 11的组成部分之一;
曲面简化:相反,为特定情形下提供使用(如LOD技术)
我们不创建高模网格的原因:
第一,基于GPU可以实现动态的LOD技术,可以根据物体距离摄像机的远近来调整多边形网格的细节; 第二,节省内存。我们可以在各种存储器中保存低模网格信息,再根据需求用GPU动态地增加物体表面的细节

2、图元组装 / 装配(Primitive Assembly)
【裁剪 (Clipping) 】
完全位于视椎体外部的图元会被裁剪掉,不会对它们进行渲染。对于部分位于视椎体的图元,我们需要对他们进行所谓的剪裁操作,位于外部的顶点将被裁剪掉,而且在视椎体与线段的交界处产生新的顶点
在这里插入图片描述
裁剪阶段使用的是4分量的齐次坐标,还是线性的

【背面剔除 (Back-Face Culling】
背面剔除指的是剔除那些背对摄像机的图元
  我们利用三角形顶点的环绕顺序来确定所谓的 正面和背面。通常情况下,三角形的3个顶点是逆时针顺序 (couter-clockwise,ccw)进行排列时,我们会认为是正面,而顺时针(clockwise,cw)排序时,我们会认为是背面。
  在渲染半透明时,不能使用该技术,因为半透明物体可以看到物体背后的东西。否则会出现穿帮的情况

GS (几何着色器Geometry Shader)

1、可选阶段
2、【作用】:顶点着色器以顶点数据作为输入数据,而几何着色器则以完整的图元(Primitive)作为输入数据。与顶点着色器不能销毁或创建顶点不同,几何着色器的主要亮点就是可以创建或销毁几何图元
3、几何着色器通常用来实现一种叫做公告栏(BillBoards)的视觉效果
根据观察方向来确定多边形(模型) 面朝方向的技术叫公告板 ( 把3D的物体用2D来表示,然后让该物体始终朝向镜头)。 可以用公告板技术表示树木, 烟, 雾, 火, 爆炸, 以及云朵等
比如场景中的一棵树,对于整个场景来说不是主要物体,因此无需花费大量的时间去计算树的每一部分的细节。通常的做法是首先准备好一张树的照片,然后镜头运动的时候使得树始终正对着镜头,我们看到的始终是树的正面。
在这里插入图片描述
【功能】:将变换到屏幕空间的图元离散化为片段的过程
【步骤】:三角形的组装和三角形的遍历
【如何定义图元覆盖(Overlap)一个片段】最简单的点采样 (Point Sampling),而且采样点位于片段的中央位置,当采样点位于图元的内部时,我们认为图元覆盖了该片段

【三角形组装 (Triangle Setup)】
在这里插入图片描述
三角形组装会对顶点的输入数据(比如,颜色、法线、纹理坐标)进行插值,为后面的片段着色提供片段数据。很少去插值颜色值,通常都是用片段着色器对片段进行着色。
【三角形遍历 (Triangle Traversal) 】
绘制线段的方法:
在这里插入图片描述
  Δy = mΔx
  假定x的增量为1,那么y的增量为m, 需要对y的值进行取整操作。对于斜率大于1的线段,我们需要交换x和y,
多边形填充算法:
  用水平扫描线从上到下(或从下到上)扫描由多条首尾相连的线段构成的多边形,每根扫描线与多边形的某些边产生一系列交点。将这些交点按照x坐标排序,将排序后的点两两成对,作为线段的两个端点,以所填的颜色画水平直线。多边形被扫描完毕后,颜色填充也就完成了

锯齿和抗锯齿 (Aliasing and Anti-aliasing):
【原因】当我们使用离散的像素点来表示连续的物体时,丢失了物体连续的信息,导致锯齿的产生
【超级采样抗锯齿 (Super-Sampling Anti-aliasing)】
拿4xSSAA来说,假设屏幕分辨率为800x600,那么 4xSSAA会将屏幕渲染到1600x1200的缓冲区上
光栅化和片段着色器都是原来的4倍,渲染缓存的大小也是原来的4倍。
【多重采样抗锯齿 (Multi-Sampling Anti-aliasing)】
本质:在MSAA中我们会使用多个采样点来决定覆盖率的问题(Coverage)
在光栅化阶段计算三角面是否覆盖了片段的每个采样点,得到采样点覆盖率的数值,接下来在片段着色器计算这个片段的颜色值(只计算一次),然后最终的颜色会乘上这个覆盖率。
MSAA的主要问题在于它跟延迟渲染(Deferred Rendering)并不兼容 ,因为延迟渲染需要Geometry和Lighting两个pass,在光照阶段无法通过GBuferf获取片段的覆盖率信息。

片段着色器(Fragment Shader)

【Phong / Blinn-Phong 光照模型】
经验模型,并没有实际的物理意义
在这里插入图片描述
= 漫反射分量+镜面高光+环境光。
环境光分量是用来模拟全局光照效果的,是一个较小的光照常量,用来表示场景中其他物体反射的间接光照
在这里插入图片描述
Blinn-Phong光照模型是Phong模型的改进:
当观察方向和反射光线夹角大于90度时,Phong 模型会出现镜面反射分量被消除的情况,而半角向量和法线夹角都不会超过90度,不会出现上面说的高光不连续的问题,光照效果更佳真实。
在这里插入图片描述
在这里插入图片描述
【纹理贴图 (Textures)】
*将图像信息映射到三角形网格上的技术,以此来增加物体表面的细节,令物体更具有真实感
*最常见的是凹凸贴图(bump mapping)、法线贴图(normal mapping)、高度纹理(height mapping)、视差贴图 (parallax mapping)、位移贴图(displacement mapping)、立方体贴图(cubemap)、阴影贴图(shadowmap)
*texel: UV纹理坐标一般被归一化到[0,1]之间
*纹理过小(模糊,双线性插值)、过大(近处锯齿,远处摩尔纹,mipmap)

1、 凹凸映射(bumping mapping)
一般有两种方法:高度纹理(height map) + 法线贴图(normal map)
法线贴图直接存储的就是物体表面的法线,性能更高。高度贴图需要计算物体表面的法线扰动信息

法线贴图一般有物体空间(object space)和切线空间(tangent space)两种,区别在于法线存储的坐标空间不同
在这里插入图片描述
物体空间的法线贴图是相对于物体的坐标原点进行存储的;
而切线空间的法线贴图是相对于顶点坐标进行存储计算的
物体空间发现贴图偏向于五颜六色,因为发现相对于物体的朝向是随机的
切线空间的法线贴图是淡蓝色的,因为Z轴总是朝向(0, 0, 1),经过映射后得到的RGB为 浅蓝色。我们会根据顶点本身的法线(N)、切线(T)和副切线(B)三个信息来构建切线空间
切线空间下的法线纹理记录的是相对法线信息,可移植性强,可进行 UV 动画,一般用切线空间

在切线空间下计算光照,
  我们需要将光照方向和观察视角转换到切线空间;从效率上来说更高,因为我们在顶点着色器就可以完成光照方向和观察方向的转换
在世界空间下计算光照
  我们需要将采样到的法线方向转变到世界空间下。需要在片段着色器进行矩阵乘法。更通用,有时候需要在世界空间下进行一些计算,例如在使用环境贴图映射时,我们需要使用世界空间下的反射方法对Cubemap进行采样。

【阴影 (Shadows) 】
静态的物体,可以使用 Light map烘焙的方法来获取物体的影子,动态的物体,一般采用的是Shadow map 的技术。
Shadowmap:首先是从光源的位置渲染一遍场景,将得到的深度信息写入到贴图,然后再一次正常的渲染场景,利用我们得到的shadowmap来判断哪些片段落在了阴影中。
阴影粉刺(shadow acen):由于shadowmap精度的问题
  通过偏移量对阴影贴图中的深度值进行调整
我们发现调整前平面会有某些像素深度比深度贴图大,某些像素深度比深度贴图小,所以导致了某些地方有阴影某些没有的粉刺现象,经过了偏移后,所有像素点的深度值都比深度贴图大,没有了粉刺现象。如果偏移太大的话,会出现阴影偏离物体的失真现象。
偏移量的大小和平面的倾斜度有关, 平面越倾斜的话,需要的偏移量就越大

在这里插入图片描述
阴影走样(aliasing):锯齿状太明显了
  提升 shadowmap的分辨率
  百分比渐进过滤(Percentage Closer Filter, PCF)
    对得到的阴影因子(shadow factor, 不在阴影中为1,在阴影中为0)进行插值

PCSS(产生软阴影的方法)
软阴影:距离遮挡物越近,阴影越硬,距离遮挡物越远,阴影越软。我们需要计算一个相对的平均的遮挡物和阴影的投射物之间的距离

算法的核心:
第一步:记录一个shading point的遮挡物的平均深度(计算多大的区域内遮挡物?)
第二步:计算Filter的大小
第三步:PCF算法
在这里插入图片描述
计算平均深度:在着色点,连向光源,形成一个椎体,在这个椎体中去找blocker,再去找平均深度。

测试和混合(Tests & Blending)

裁切测试、Alpha测试、模板测试和深度测试后,Alpha混合技术
【裁切测试 (Scissor Test) 】
裁切测试可以避免当视口比屏幕窗口小时造成的渲染浪费问题。
这里没太懂????

【Alpha测试 (Alpha Test) 】
颜色:RGBA(alpha=1表示完全不透明,alpha=0表示完全透明)
消耗较大,性能较低:early-z不适用

【模板测试 (Stencil Test) 】
通过mask的值来控制那些片段的可见性,无法通过模板测试的片段将被丢弃
在这里插入图片描述
【深度测试 (Depth Test) 】
比较当前片段的深度值是否比深度缓冲中预设的值小,如果是则更新深度缓冲和颜色缓冲;否则丢弃片段不更新缓冲区的值。
与early-z区别:深度测试是在片段着色器之后进行的;early-z在片段着色器之前进行的

补充:
【Early-Z Culling】
背景:深度/模板测试是在片段着色器之后进行的,导致着色器计算资源的浪费(片段是最终显示在屏幕上像素的候选者)
作用:加速渲染
bug:不能在片段着色器去修改深度缓冲,不能有透明物体(即alpha测试会失效
【Z-Fighting】
1、当同一个位置的片段具有相似的深度值时,由于深度缓冲精度不够无法决定应该显示那个片段,导致片段之间抢占深度的至高点
2、经过透视除法后的z分量具有了非线性的关系,近平面处有较好的深度精度,而靠近远平面处深度精度较低。
3、解决:让物体之间有一些偏移,不要靠的太近;使用高精度的深度缓冲。

【Alpha混合 (Alpha Blending) 】
当场景中既有不透明物体,又有半透明物体时:我们需要先渲染不透明物体,渲染顺序为从前往后(Front-to-Back),;然后再渲染半透明物体,渲染顺序为从后往前(Back-to-Front)。
需要对不透明和半透明物体分开渲染:我们可以透过半透明物体看到半透明物体背后的东西,所以对半透明物体进行渲染时需要后面图层的信息,才能够正确进行混合。
对不透明物体按从近到远进行渲染是为了减少深度颜色缓冲器的写入操作,提升性能,避免overdraw;而半透明物体需要遵循画家算法由远及近进行渲染是为了渲染的正确性
在这里插入图片描述
在渲染半透明物体时, 需要开启深度测试而关闭深度写入功能
顺序无关半透明算法 (Order-independent transparency,OIT):
  简化对半透明物体的渲染过程,也被称作深度剥离(Depth Peeling)
  思想就是根据物体距离摄像机的远近进行深度信息的逐层剥离,首先记录离相机最近的一层,然后记录距离第二近的层,以此类推,层层递进

  

PLUS

一、【隐藏面消除 (Hidden Surface Removal, HSR)】

1、目的:减少到达片段着色器的片段的数量,提高渲染的性能
2、 种类:图元组装的裁剪(Clipping,针对的是图元)、背面剔除、Z-Buffer(针对像素点)、视椎体剔除 (Viewing-Frustum Culling) 、入口剔除 (Portal Culling)、遮挡剔除 (Occlusion Culling)

【视椎体剔除 (Viewing-Frustum Culling)】:
只需要渲染那些摄像机看得到的物体,也就是位于视椎体内的物体
视椎体剔除是在应用程序阶段完成的,在CPU端。
视椎体剔除利用的是射线检测的方法,根据视椎体的六个平面来检测物体。我们一般利用物体包围盒(Bounding Box)来做交差检测
由于场景中物体可能非常多,常见的用于3D场景碰撞检测的数据结构有:八叉树(OcTree)、二分空间划分(Binary Space Partitioning)、四叉树(Quad Tree)、场景图 (Scene Graphs)、kd树(K-Dimensional Tree)和层次包围(Bounding Volume Hierarchies)、PSV。这些空间数据结构也通常使用在场景管理、光线追踪和相交测试中。

【入口剔除 (Portal Culling) 】
可以将室内的门或者窗户看做视椎体来进行裁剪
局限性:一般只能在室内环境下使用,对于室外的大场景使用遮挡剔除技术

【遮挡剔除 (Occlusion Culling) 】
可见性问题可以通过 Z 缓冲器的硬件构造来实现,但密集度很高的场景下, Z 缓冲不是一个很“聪明”的机制。(例如,假设视点正沿着一条直线观察,其中,在这条直线上有 10 个球体,虽然这 10 个球体进行了扫描转换,同时与 Z 缓冲器进行了比较并写入了颜色缓冲器和 Z 缓冲器, 但是这个从这个视点渲染出的图像只会显示一个球体
在这里插入图片描述
深度复杂度指的是对每个像素重写的次数
从某种意义上来说,z缓冲器只选择并绘制那些可见的物体,从远到近,但是必须将这些物体都送入管线的大部分阶段。高效遮挡裁减算法背后的思想是,提前执行一些简单的测试,从而避免将所有的数据送入管线的大部分阶段。
有两种主要形式的遮挡裁剪算法,分别是基于点的遮挡裁剪和基于单元的遮挡裁剪。如下图所示
在这里插入图片描述
通过离线烘焙预先计算出潜在可视集合(Potentially Visible Set,PVS)。PVS记录了每个地形块(Tiles)可能看到的物体的集合,用于运行时查找计算。在计算PVS时我们会将场景划分为小的地形块,在每个块上随机选取N个采样点,以这些采样点为起点发出射线来获取场景中相交的物体,记录下物体的ID,求出每个块对应的ID的集合。在运行时根据摄像机的位置获取每 个块可见的物体进行渲染。

二、【颜色空间 (Color Spaces)】

RGB空间、CMY空间、HSV(B)空间和HSL(I)空间
其中RGB和CMY空间主要是用于设备的,而HSV和HSL空间是面向用户的

RGB,每个分量都是归一化到[0,1]之间的数字,三颜色混合得到的是白
在这里插入图片描述

CMY空间是一种减色系统,所以CMY三种颜色对应的是RGB三种颜色的补色
在这里插入图片描述
HSV是面向用户的,由色调Hue、饱和度Saturation和亮度Value或 Brightness三个分量构成。
在这里插入图片描述
HSL,H表示色调,S表示饱和度,L表示物体的亮度 (Lightness或者Intensity)。

Lab颜色空间,自然界中任何一种颜色都可以表示出来,它的颜色空间比RGB还要大
在这里插入图片描述
抖动处理 (Dithering)
  抖动可以用来增加可用的颜色数量

其他

  其他OpenGL知识点

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值