赞
踩
渲染管线通常被分为四个阶段:应用阶段,几何阶段,光栅化阶段,像素处理.阶段。接下来将介绍每个阶段的大概任务:
(1) 应用阶段:应用阶段是指在CPU端进行处理的阶段,包括物理碰撞检测、物理模拟、动画计算等任务,对于3D游戏来说,游戏中包含大量的模型,3D模型中保存着模型的顶点坐标,法线,切线,颜色等数据,这些数据一般通过向量进行存储,CPU从模型中获取这些顶点信息数据,并将这些数据传送给GPU作为最开始的输入数据。然后将数据送到渲染管线中。
(2) 几何阶段:几何阶段主要执行顶点.坐标变换、顶点处理、坐标裁剪等操作,计算对象为顶点数据,即模型的顶点数据,在这个阶段,做的最多的操作就是顶点坐标变换,从模型空间变换到世界空间,然后再从世界空间变换至相机空间。这样在相机坐标系下就能方便地进行裁剪,裁剪的作用是判断顶点是否可见。
(3) 光栅化阶段:相比于屏幕上的像素点,顶点数据要少很多,这就有一个问题:无法实现从顶点数据到屏幕像素上的映射。而为了达到这一目的,就出现了顶点插值运算,即将两个顶点之间的空缺部分通过插值的形式进行填充,以达到能实现从顶点数据到像素上的一一映射,最后将渲染的结果显示到屏幕上。
(4) 像素处理阶段:像素处理阶段包括像素颜色计算、像素变换,透明度混合等操作,处理物体渲染顺序及深度测试等。这个阶段要处理的内容比较多,可以在此阶段中利用一些算法实现非常多的屏幕特效,比如高斯模糊,景深等,此阶段是游戏渲染中应用非常广泛的阶段,但因为计算对象是像素点,因此实现相关特效时比较耗费性能。
渲染管线几个阶段:
(1) 顶点数据:一个模型或者图形是由点线面构成的,为了让计算机绘制出这个图形,就必须告诉计算机这些数据的值,顶点数据包括顶点坐标,坐标的切线,法线,颜色等信息,对于OpenGL,这些数据一般都是向量(Vector)结构体,对于游戏引擎,这些数据来自导入的模型当中,在开始渲染之前,CPU会获取这些数据,然后将其传递给GPU,作为最原始数据,做好计算准备。
(2) 顶点着色器:顶点着色器(Vertex Shader)在渲染管线中的作用非常大,是渲染管线的第一个可编.程着色器,处理单元是顶点数据。顶点着色器的主要功能是对坐.标进行.变换。将输入的局部坐标变换到世界坐标、观察坐标和裁剪坐标。除此之外当然也可以进行光照着色,但是着色效果远不如在片元着色器中进行光照着色,因为计算量较小。
(3) 图元装配:图元装配(Primitive Assembly)是对传入的顶点数据进行重新组装,将顶点着色器的输出作为输入,这一点正验证了渲染的过程是以流水线的形式进行的,图元装配会将顶点装配成指定的图形,与此同时,会进行裁剪、被面剔除等操作,以减少不必要的计算,加速渲染过程。
(4) 几何着色器:几何着色器(Geometry Shader)会将图元装配阶段输出的数据作为输入数据。几何着色器不属于可编程阶段,由硬件设备自动完成,其主要作用是对顶点数据进行重构,可以在此阶段产生新的顶点数据,来弥补之前存在的一些问题。以便为接下来要进行的操作做好充分的准备工作。
(5) 光栅化:光栅化阶段(Rasterization Stage)的输入数据来自几何着色器的输出数据,光.栅化的意思很容易理解,到目前为止,渲染所处理的数据对象为顶点,无法通过一一对应的方式映射到屏幕上,而为了实现顶点到屏幕像素的一一映射,就出现了光栅化。换而言之,光栅.化的作用就是将两个顶点直接缺少的像素点通过插值的形式进行补充,生成片元着.色器可以处理的片段。此阶段.人为不可干涉,由硬件完成插值计算。在插值的过程中,会将不可见的顶点进行剔除。
(6) 片元着色器:片元着色器处理的对象将是像素点的颜色信息,也是最终显示在屏幕上的像素点,在这个过程中,可以处理光照和阴影计算,将处理完的值保存至缓冲区当中。
(7) 混合处理阶段:混合处理阶段属于屏幕后期处理范围,这意味着此阶段主要做的任务为屏幕优化操作,通过片元着色器得到的像素,有些不能被显示出来,比如透明度为0的像素点,对于这类像素点,我们需要进行测试,测试的范围包括Alpha测试、模板测试和深度测试等。不能通过测试的像素点将会被丢弃,就不会参与接下来的操作;通过测试的像素点会进入混合阶段。混合阶段主要是要处理透明物体,物体的透明度通过Alpha值来表示,范围是从0.至.1, alpha=1表示完全不透明,alpha=0表示完全透明。测试混合阶段基本不需要进行编程,但是常见的渲染管线接口会开放出一些参数给开发者.做调整。
我的相关博客链接:
这意味着透明物体要关闭深度写入,要是要开启深度测试,同时开启混合算法
为了能看到透明物体后面的内容,需要进行混合
深度测试在之前有介绍
渲染顺序在做优化上非常重要,比如不透明物体应该从前向后的顺序渲染,因为深度值越大,越容易不被遮挡,这里涉及Early-Z技术,透明物体则从后向前渲染,因为透明物体需要和后面的物体进行叠加,同时不写入深度值,暂且简单介绍一下,之后会有相关文章详细介绍。
要想让混合在多个物体上工作,我们需要最先绘制最远的物体,最后绘制最近的物体。普通不需要混合的物体仍然可以使用深度缓冲正常绘制,所以它们不需要排序。但我们仍要保证它们在绘制(排序的)透明物体之前已经绘制完毕了。当绘制一个有不透明和透明物体的场景的时候,大体的原则如下:
关于性能优化,我曾单独写过一篇博文介绍,有兴趣的可以看一下:
CPU端常见优化点:
1 减少tick的使用,大部分逻辑都是事件驱动的,能不在tick/update里刷就不要在里面刷
2 尽量减少使用get all class方法,性能较低
3 不要频繁创建销毁物体,对象池了解一下
数据传输优化(DrawCall)
1 尽量使用共享材质
2 减少渲染的物体数量,可以减少模型顶点数量,或者尽量使用LOD以及遮挡剔除
3 尽量使用图集
4 动态/静态批处理
关于批处理,我曾写过相关博文做简单介绍:
GPU端优化:
1 注意渲染顺序,尤其是透明物体
2 减少光照,尽量使用烘焙光
3 使用mipmap
4 尽量简化shader计算量
颜色缓冲区、深度缓冲区、模板缓冲区和累积缓冲区https://blog.csdn.net/linjf520/article/details/52183859
我们先来看模板测试(Stencil Test)。与之相关的是模板缓冲(Stencil Buffer)。实际上,模板缓冲和我们经常听到的颜色缓冲、深度缓冲几乎是一类东西。如果开启了模板测试,GPU会首先读取(使用读取掩码)模板缓冲区中该片元位置的模板值,然后将该值和读取(使用读取掩码)到的参考值(reference value)进行比较,这个比较函数可以是由开发者指定的,例如小于时舍弃该片元,或者大于等于时舍弃该片元。如果这个片元没有通过这个测试,该片元就会被舍弃。不管一个片元有没有通过模板测试,我们都可以根据模板测试和下面的深度测试结果来修改模板缓冲区,这个修改操作也是由开发者指定的。开发者可以设置不同结果下的修改操作,例如,在失败时模板缓冲区保持不变,通过时将模板缓冲区中对应位置的值加1等。模板测试通常用于限制渲染的区域。另外,模板测试还有一些更高级的用法,如渲染阴影、轮廓渲染等。
如果一个片元幸运地通过了模板测试,那么它会进行下一个测试——深度测试(Depth Test)。相信很多读者都听到过这个测试。这个测试同样是可以高度配置的。如果开启了深度测试,GPU会把该片元的深度值和已经存在于深度缓冲区中的深度值进行比较。这个比较函数也是可由开发者设置的,例如小于时舍弃该片元,或者大于等于时舍弃该片元。通常这个比较函数是小于等于的关系,即如果这个片元的深度值大于等于当前深度缓冲区中的值,那么就会舍弃它。这是因为,我们总想只显示出离摄像机最近的物体,而那些被其他物体遮挡的就不需要出现在屏幕上。如果这个片元没有通过这个测试,该片元就会被舍弃。和模板测试有些不同的是,如果一个片元没有通过深度测试,它就没有权利更改深度缓冲区中的值。而如果它通过了测试,开发者还可以指定是否要用这个片元的深度值覆盖掉原有的深度值,这是通过开启/关闭深度写入来做到的。我们在后面的学习中会发现,透明效果和深度测试以及深度写入的关系非常密切。
GBuffer Float[ 720 * 1280 * 4] 中转区:合格通过测试的点 会把 RGBA值 模板值 深度值 等存入GBuffer。
关于GBuffer、FrontBuffer、FrameBuffer】
GBuffer选出来的像素,FrontBuffer只写入GBuffer的RGBA,推到显示器显示,之后退到后台变为FrameBuffer;
FrameBuffer同样也会只写入GBuffer的RGBA,推到显示器显示,之后退到后台变为FrontBuffer。如此交替显示,一帧一帧渲染显示,有了动画。
opengl渲染管线 http://mizhiyigame.lofter.com/post/1e5faf6e_12df39e7c
延迟渲染的不足之处
https://blog.csdn.net/qq_36696486/article/details/105206425
阴影绘制的实现基础是Shadow Map算法,Shadow Map的绘制过程如下:
将物体顶点数据通过矩阵运算转移到灯.光空间下。从局部空间转移到世界空间,在转移到灯光空间下,对于不同的灯光,有着不同的投影矩阵,这里涉及两种投影方式:正交投影和透视投影。两种投影方式分别对应着不同的投影矩阵及视觉效果:正交投影往往应用于2D.游戏中,透视投影应用于3D游戏.中,但并不绝对。在灯光坐标下渲染物体阴影:
在灯光空间下.创建一张深度纹理贴图,用于保存物体在灯光空间下的深度信息,此深度贴图则是摄像机的渲染目标。灯管空间下的物体深度信息将被保留在该深度贴图中。
渲染深度贴图的过程比较简单,首先在该视口下的顶点信息进行判断,如果某个顶点的深度值比深度贴图中的值小,就更新贴图数据,反之丢弃掉该数据,直到遍历一遍所有像素点为止。遍历完成后,便得到了深度信息图。
获取到深度贴图后,如果某个点在光源视角下的深度值大于深度贴图中对应位置的深度值,就说明它被某个物体遮挡,因此是在阴影中的;反之,深度值小于深度贴图中的值,则不在阴影之中。
判断完成该顶点是否需要接收阴影后,需要做的最后一步就是对该顶点乘上阴影的颜色,遍历完一遍该物体的所有顶点后,便可得到该物体接收阴影的效果。
Shadow Map 伪码表示:
算法3.1: Shadow Map。
输入:顶点位置坐标。
输出:在灯光空间下是否可见。
BEGIN
(1) 将顶点坐标转换到灯光空间下,需要乘变换矩阵
(2) 计算该顶点在灯光空间下的深度值
(3) IF 该顶点的深度值大于深度贴图中对应点的深度值
(4) 返回FALSE
(5) ELSE
(6) 返回TRUE
(7) END IF
END
在计算机渲染一个物体的时候,对于透视投影情况下,当该物体距离摄像机非常远时,映射到屏幕上的像素点非常少,这就导致采样命中率降低,这样纹理寻址速度会变慢,性能会降低。同时对于高分辨率的物体来说,也会造成不必要的内存浪费。
为了解决上述采样率过低的问题,出现了多级渐远纹理(mipmap)多级渐远纹理是以空间换时间的方案,通过保存原尺寸贴图的四分之一大小,直到最小尺寸为2*2为止。在纹理寻址的过程中,会选择与映射到屏幕时对应的像素点数最接近的一张纹理,然后使用该纹理做纹理寻址,如图所示:
使用mipmap会造成多用33%的空间,但是使用它的好处也非常明显,换句话说就是使用空间换时间,利大于弊。对于阴影贴图来说,使用mipmap在做纹理寻址时也是一项重要优化。通过mipmap加快阴影映射,在性能上还能有一定程度的提升,但是当场景中物体离摄像机极远时,最好不要使用mipmap,因为这样会导致阴影极度模糊,造成阴影不真实的现象。
OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题,它简单来说就是一系列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距观察者的距离超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最适合物体的距离的那个。由于距离远,解析度不高也不会被用户注意到。同时,多级渐远纹理另一加分之处是它的性能非常好。
顶点着色器:顶点着色器(Vertex Shader)在渲染管线中的作用非常大,是渲染管线的第一个可编.程着色器,处理单元是顶点数据。顶点着色器的主要功能是对坐.标进行.变换。将输入的局部坐标变换到世界坐标、观察坐标和裁剪坐标。除此之外当然也可以进行光照着色,但是着色效果远不如在片元着色器中进行光照着色,因为计算量较小。
片元着色器:片元着色器处理的对象将是像素点的颜色信息,也是最终显示在屏幕上的像素点,在这个过程中,可以处理光照和阴影计算,将处理完的值保存至缓冲区当中。
关于抗锯齿,我曾出过一篇博客做相关说明,有兴趣的可以看一下:
一、矩阵旋转:
优点:旋转轴可以是任意向量
缺点:旋转其实只需要知道一个向量+一个角度(共4个信息值),但矩阵却用了16个元素(矩阵法消耗时间和内存)
二、欧拉角旋转
优点:容易理解,形象直观;表示更方便,只需要三个值(分别对应x、y、z轴的旋转角度)
缺点:欧拉角这种方法是要按照一个固定的坐标轴的顺序旋转的,因此不同的顺序会造成不同结果;欧拉角旋转会造成万向锁现象,这种现象的发生就是由于上述固定的坐标轴旋转顺序造成的。理论上,欧拉角旋转可以靠这种顺序让一个物体旋转到任何一个想要的方向,但如果在旋转中不幸让某些坐标轴重合,就会发生万向锁现象,这时就会丢失一个方向上的旋转能力(两个旋转轴(环)重叠),也就是说在这种状态下,我们无论怎么旋转(还是按照原先的旋转顺序),都不可能得到某些想要的结果,除非打破原先的旋转顺序或者同时旋转三个轴。
由于万向锁的存在,欧拉旋转无法实现球面平滑插值。
万向锁的简单解决办法:构造一个不同的旋转层级顺序,但是万向锁总是会在某一个顺序发生,调整旋转顺序不是根本解决办法。(Unity使用的是Z-X-Y顺规,即旋转顺序为z轴、x轴、y轴,虽然某些情况下会出现万向锁,但是这种顺规出现万向锁的概率最小)
万向锁解决办法:将欧拉角转换为四元数,对四元数进行Slerp插值,再将这一系列四元数转换为对应的欧拉角,然后作用于需要进行旋转的对象。这种做法缺点在于消耗内存,但是可以使物体任意旋转,灵活度高。
使用欧拉旋转出现旋转路径偏移的根本原因:在万向锁情况下对欧拉角的插值不是线性的。(突变)
静态欧拉角:其旋转轴使用的是静止不同的参考系。
动态欧拉角:使用object本身的坐标系,因而会随着object旋转而旋转。(局部坐标系会随着对象的旋转而旋转)
三、四元数旋转
优点:可以避免万向锁;只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;而且四元数旋转可以提供平滑插值。
缺点:比欧拉旋转稍微复杂了一点,因为多了一个维度,理解更困难,不直观。
https://zhuanlan.zhihu.com/p/79894982
图元装配(Primitive Assembly)是对传入的顶点数据进行重新组装,将顶点着色器的输出作为输入,这一点正验证了渲染的过程是以流水线的形式进行的,图元装配会将顶点装配成指定的图形,与此同时,会进行裁剪、被面剔除等操作,以减少不必要的计算,加速渲染过程。
https://www.jianshu.com/p/ae32494123a9
参数 x,y: 指定裁剪框左下⻆的点位置 (x,y);
参数 width , height:指定裁剪的宽和高。
目标颜色: 已经存储在颜色缓冲区中的颜色值。
源颜色: 作为当前渲染命令的结果进入颜色缓冲区的颜色值,它可能与目标颜色进行交互,也可能不交互。 目标颜色和源颜色都包含了单独的红、绿、蓝成分和一个可选的 alpha 值。如果我们忽略 alpha 值,OpenGL 会将它设为1.0。 当混合功能被启用时,源颜色和目标颜色的组合方式是由混合方程式控制的。默认情况下方程式如下:Cf = (CS * S) + (Cd * D)
- Cf :最终计算产生的颜色
- Cs :源颜色
- Cd :是目标颜色
- S :源混合因子
- D :目标混合因子。
这些混合因子是用 glBlendFunc
函数进行设置的:glBlendFunc(GLenum s, GLenum D);
S 和 D 都是枚举值,不是可直接指定的实际值。
https://juejin.im/post/6844903956087308295
https://blog.csdn.net/qq_36696486/article/details/104314572
-shader中有哪些内置的api
https://blog.csdn.net/plaxbsga/article/details/52787860
常用的数学函数:https://zhuanlan.zhihu.com/p/95051582 fract(x);//返回x的小数部分
1:https://learnopengl-cn.readthedocs.io/zh/latest/04%20Advanced%20OpenGL/05%20Framebuffers/
https://juejin.im/post/6844903670014820360
https://www.shuzhiduo.com/A/Vx5M64qYdN/
https://blog.csdn.net/wang15061955806/article/details/48974157
我用#CSDN#这个app发现了有技术含量的博客,小伙伴们求同去《现代opengl 设计 glDrawArrays与glDrawElements的功能与区别》, 一起来围观吧 https://blog.csdn.net/leon_zeng0/article/details/89291860
https://blog.csdn.net/puppet_master/article/details/52783179
这两种方法在性能上的区别
https://blog.csdn.net/weixin_42682806/article/details/84313524
以及复习矩阵变换的相关知识,详情请看你自己的ipad笔记
https://www.coder.work/article/4427073
为什么要先缩放,旋转,再平移 ,可见ipad书籍unity shader的矩阵章节。
摄像机在渲染管线中作用非常大,在游戏世界里,摄像机担任的角色类似于人的眼睛,摄像机所看到的内容最终会被绘制到屏幕上。为了模拟人的视野,摄像机具有近远平面和视野等属性,通过这些属性,可以绘制出一个视锥体,所有在视锥体内的物体初步判定为视野可见。
摄像机具有的最重要的属性是投影方式:即正交投影和透视投影。正交投影和透视投影两种投影方式的本质区别是投影矩阵的差异以及视锥体的不同。正交投影一般应用于平面或者2D游戏当中,使用正交投影矩阵进行平面映射。而透视投影一般应用于空间或者3D游戏。使用透视投影可以模拟人的视野,物体之间将具备更加贴近现实的遮挡关系,透视投影进行投影的方式是通过透视投影矩阵。
正交投影矩阵应用于一个立方体视口下,不在这个立方体之内的顶点都会被剔.除掉。因为正交投影矩阵围成一个立方体,因此为了生成正交矩阵,就需要指定对应的长度、宽和高。当顶点坐标在这个立方体内,则视为视口可见,不会被剔除。正射投影相机原理如下图所示:
透视投影矩阵定义了一个锥体空间,其中最.重要的参数是FOV(Field of View),就是相机的视野角度。通过该角度和进平面远平面围成一个封闭的锥体,在该锥体范围内的物体将不会被裁剪掉。透视投影广泛应用于3D空间,因为它能模拟人的视角去观察物体。因此在透视矩阵下,物体能表现出深度信息与遮挡关系。
相关运算矩阵,在闫令琪老师的课里会有详细说明
https://blog.csdn.net/qq_36696486/article/details/104291630
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。