声明:本文章参考自《Real-Time Rendering》书籍加以汇总并引用了其中部分图片

一、渲染任务

渲染的任务其实就是从一个三维场景出发,将其进行渲染生成一个二维图像供人眼观察。详细点说,就是CPU和GPU配合,将3D场景中各个对象的坐标,纹理,材质等信息经一系列转换生成人眼可以看见的图像映射到屏幕上。

二、三个阶段

渲染的三个阶段一般分为,应用阶段,几何阶段和光栅化阶段,其大致的流程参考下方图1

图1 渲染管线流程图

三个阶段的操作对象的流程图大致可以参考一下 图2

图2 渲染管线操作对象流程图

1、应用阶段

这一阶段由CPU处理,主要任务是为接下来GPU的渲染操作提供所需要的几何信息,即输出渲染图元(rending primitives)以供后续阶段的使用。渲染图元就是由若干个顶点构成的几何形状,点,线,三角形,多边形面都可以是一个图元。

1-1:数据的准备

第一步 应先将不需要的数据剔除出去,如以包围盒为单位的视锥体(粗粒度)剔除,遮挡剔除,层级剔除等等。

第二步 根据UI对象在Herachy面板深度值的顺序(DFS深度优先搜索)设置渲染的顺序,其余物体大体可以按照离摄像机先近后远的规则为后续循环绘制所有对象制定排队顺序。

第三步 先将所有需要的渲染数据从硬盘读取到主存中,再把GPU渲染需要用到的数据打包发给显存(GPU一般没有对主存的访问权限,且与显存进行交换速度较快)。

打包的数据详细信息见图3

图3 打包的数据信息

1-2:设置渲染状态

渲染状态包括着色器(Shader),纹理,材质,灯光等等。

设置渲染状态实质上就是,告诉GPU该使用哪个Shader,纹理,材质等去渲染模型网格体,这个过程也就是SetPassCall。当使用不同的材质或者相同材质下不同的Pass时就需要设置切换多个渲染状态,就会增加SetPassCall 所以SetPassCall的次数也能反映性能的优劣。

1-3:发送DrawCall

当收到一个DrawCall时,GPU会按照命令,根据 渲染状态 和输入的顶点信息对 指定 的模(网格)进行计算渲染。

CPU通过调用图形API接口 glDrawElements (OpenGl中的图元渲染函数) 或者 DrawIndexedPrimitive (DirectX中的顶点绘制方法) 命令GPU对指定物体进行一次渲染的操作即为DrawCall。此过程实质上就是在告诉GPU该使用哪个模型的数据(图形API函数的功能就是将CPU计算出的顶点数据渲染出来)。

在应用阶段有三个衡量性能指标非常重要的名词 下面我将再次叙述一下

DrawCall CPU每次调用图形API接口命令GPU进行渲染的操作称为一次DrawCall。

SetPassCall :设置/切换一次渲染状态。

Batch :把数据加载到显存,设置渲染状态,CPU调用GPU渲染的过程称之为一个Batch。

注:一个Batch包含至少一个DrawCall

2、几何阶段

几何阶段由GPU进行处理,其几乎要处理所有和几何相关的绘制事情。如绘制的对象,位置,形状。几何阶段处理的对象时 渲染图元 ,进行逐顶点和逐多边形的操作。主要任务是把顶点坐标变换到屏幕空间中,以供给接下来的光栅器进行处理。具体输出的信息有,变换后的屏幕二位顶点坐标,顶点的深度值,着色,法线等等信息。

接下来对几何阶段的主要流水线阶段进行一下解释:

2-1:顶点着色器

流水线的第一个阶段, 其可以通过编程进行控制 。输入来自CPU发送的顶点信息,每个顶点都会调用一次顶点着色器。其主要工作为: 坐标转换和逐顶点光照(可选,计算输出顶 点的颜色值) 。坐标转换是必须完成的一个任务。其把顶点坐标从模型空间转换到齐次裁剪空间。(齐次裁剪空间不是屏幕空间,是xyz均放缩到-1到1的空间),具体过程可以参考图4

(提一下:此时GPU处理的顶点并不清楚顶点之间的关系,只是无差别的对待每个顶点,能             很好的体现各个部件的分离,降低耦合性)

图4 坐标转换

2-2:裁剪

顾名思义,就是将不需要的数据对象剔除出去的过程。由于场景一般很大,摄像机的视野范围可能不会覆盖所有的场景物体,裁剪就是为了将那些在摄像机视野范围外的物体剔除出去而被提出来的。

一个图元和摄像机的关系有三种:完全在视野内、部分在视野内、完全在视野外。完全在视野内的就传递给下一个流水线阶段,完全在视野外的就不会向下传递,而部分在视野内的就需要进行一次处理,就是裁剪。

下图(图5)展示了一个裁剪的过程:

图5 裁剪过程

由图5可清楚的看出,除完全在空间内外的图元被保留和舍弃以外,部分在空间内的图元(黄色三角形)会被裁剪,新的顶点将在空间的边界处生成,原来在外部的顶点会被舍弃 。

2-3:屏幕映射

通过计算将实际场景的对象映射到屏幕上,实质上就是对坐标的放缩,参考图6

图6 屏幕映射

3、光栅化阶段

此阶段仍然由GPU进行处理。这一阶段将会使用上个阶段传递的数据(屏幕坐标系下的顶点位置以及和它们相关的额外信息,如深度值(z坐标)、法线方向、视角方向等。)来产生屏幕上的像素,并渲染出最终的图像。光栅化的主要任务是 决定渲染图元中的哪些像素应该被绘制在屏幕上,然后对其颜色进行合并混合。

3-1:三角形设置

其主要任务是为后续光栅化提供所需要计算的信息。 例如,后续阶段需要判断像素点是否被三角形网格覆盖,只靠上个阶段得到的顶点信息无法确定边界的覆盖情况,还需要三角形网格边的信息,所以在这个阶段需要计算出边的表达式以供后续判断的使用。其输出都是为了给下一阶段做相应的准备。

3-2:三角形遍历

三角形遍历阶段会根据上一个阶段的计算结果判断一个三角形网格覆盖了哪些像素,并使用三角网格三个顶点的顶点信息对整个覆盖区域进行插值。详细过程见下方介绍:

此阶段会遍历所有的像素点,判断其是否被三角网格所覆盖 (用3-1计算的结果) ,如果被覆盖,则在此像素点上生成一个片元。片元不是单纯的像素点,其还包含很多状态的集合,这些状态用来最终计算检测筛选每个像素点最终的颜色。(部分状态包括:屏幕坐标,深度值,从几何阶段继承来的法线,纹理等等)。

片元状态的信息是由其所在三角形网格的三个顶点的信息的插值得到的,例如计算三角形网格重心位置片元的深度 如下图(图7)

图7 片元状态信息插值

最终输出的是包含多个片元的片元序列

3-3:片元着色器

非常重要的可编程着色器阶段。片元着色器的输入是上一个阶段对顶点信息插值得到的结果,输出为每个片元的颜色值。这一阶段可以按需完成很多重要的渲染技术,最重要的技术之一就是 纹理采样

为了在片元着色器中进行纹理采样,先在 顶点着色器 阶段输出每个顶点对应的纹理坐标,然后经过光栅化阶段对三角形网格的三个顶点对应的纹理坐标进行插值后,就可以得到其覆盖的片元的纹理坐标了。其局限在于仅可以影响单个片元。即执行片元着色器时,不能将结果直接发给旁边的邻居。片段着色器输出颜色的具体过程如下图(图8)

图8 计算输出颜色

3-4:逐片元操作

这是OpenGL中的说法,在DirectX中,这阶段被称为输出合并阶段(Output-Merger)。

该阶段是对每一片 片元 进行操作,主要任务有:

①决定每个片元的可见性,如深度测试、模板测试。

②如果一个片元通过了所有测试,就把这个片元的颜色值和已经存储在颜色缓冲区的颜色进             行合并,混合。

该阶段是高度可配置的,我们可以设置每一步的操作细节。该阶段首先解决的是,每个         片元的可见性问题。这需要进行一系列测试,只有通过了才能和颜色缓冲区进行合并。没通            过任何一 个测试,片元都会被丢弃。见图(9)

图9 片元测试及合并

测试过程是很复杂的,不同接口实现细节也不同,下面笔者将讲述一些常用的测试:

开启了模板测试,GPU就会使用读取掩码读取模板缓冲区中该 片元的模板值,将该值 和读取到的参考值进行比较。这个比较函数可以是开发者指定的,例如小于模板值时则舍弃 该片元或 者大于模板值时舍弃该片元 。片元无论有没有通过模板测试都可以根据模板测试和下面的深度测试结果来修改模板缓冲区。这个修改操作也是由开发者指定的。模板测试通常用于限制渲染的区域。

通过模板测试后,片元就会进行深度测试。其同样是高度可配置的。

开启后, GPU会把该片元深度值和已存在与深度缓冲区的深度值进行比较 ,这个比较函数也是开发者设置的。例如小于缓冲区深度值时舍弃该片元,或者大于缓冲区深度值等于时舍弃该片元。通常人们更希望显示离摄像机最近的物体,所以一般比较函数设置为当前片元深度值要小于缓冲区深度值,深度值大无法通过测试。如果片元没有通过测试,则会被丢弃掉。

与模板测试不同,只有通过之后开发者才能指定是否用该片元的深度值覆盖原有缓冲区的深度值。这是通过开启/关闭深度写入做到的。

通过了所有测试后,片元就来到了合并操作。

每个像素的信息被存储在一个名为颜色缓冲区的地方,因此执行此次渲染时,颜色缓冲区中往往已经有了上次渲染之后的结果。所以需要合并的方式使其达到一种均衡状态。

对于 不透明物体 ,开发者可以选择关闭混合操作。这样片元着色器计算得到的颜色值就会直接覆盖原来颜色缓冲区中的像素值。

对于 半透明物体 ,需要使用混合操作来让这个物体看起来是透明的。

混合操作也是可以高度配置的。开启了混合,GPU会取出源颜色和目标颜色将两者混合。

源颜色是片元着色器得到的颜色,目标颜色是已经存在于颜色缓冲区中的颜色值。

提前测试的目的主要是为了提高性能

虽然逻辑上这些测试是在片元着色器之后进行的,但对于大多数GPU来说,他们会尽可能在执行片元着色器之前进行这些测试。

尽可能早知道哪些片元会被舍弃可以提高性能 ,比如unity的渲染流水线中的深度测试就在片元着色器之前。这种将深度测试提前的技术被称为Early-Z技术。

但将这些测试提前其检验结果可能会与片元着色器中一些操作产生冲突。

至此Unity的渲染管线的大致过程就已经介绍完毕啦~,这是笔者第一次攥写博客部分绘制的流程图和解释还较为粗糙,后续还会继续编写有关Unity的内容,希望能对大家有所帮助( .^◡^ .)

目录渲染管线(流水线,流程)一、渲染任务二、三个阶段1、应用阶段 1-1:数据的准备 1-2:设置渲染状态 1-3:发送DrawCall2、几何阶段 2-1:顶点着色器 2-2:裁剪 2-3:屏幕映射3、光栅化阶段 3-1:三角形设置 3-2:三角形遍历 3-3:片元着色器 3-4:逐片元操作 ...
游戏开发中经常需要平衡GPU和CPU的性能消耗 比如游戏加载时的 Loading 界面,往往伴随着资源请求(网络请求数据和本地请求资源),这些请求很消耗CPU的资源,如果Loading也放在CPU做的话会抢占CPU资源,就使得当前界面会变的非常卡顿,所以我们要在CPU忙的时候,通过GPU来分担一下工作。 Loading 做法:利用CPU 做若干图交替 ;利用GPU旋转 OpenGl 渲染 ...
URP 称为Universal Render Pipeline(通用 渲染管线 ),可以提供更加灵活的 渲染 方案,通过添加Render Feature实现各种 渲染 效果。并且可以针对移动平台进行专门的优化,同时还提供了SRPBatcher提高 渲染 效率。 Unity 的一些工具,比如ShaderGraph,也是必须在URP管线下才可以使用,可以说许多方面均优于内置 渲染管线 。 所以如果还在使用内置 渲染管线 的,建议尽早升级到URP。通过本文,可以了解到如何从内置管线升级到URP。并且记录了一些升级时可能遇到的问题和解决方法
渲染管线 就是经过一系列的操作,把 图形 渲染 到屏幕上的一个过程,这些操作总的来说就是:剔除、 渲染 、屏幕后处理。 不同的 渲染管线 ,执行的操作不一样,输出的结果也不一样,比如一个加工布娃娃的流水线,A流水线就是缝合、输出,B流水线是缝合、点缀、输出 unity 总体来说包含两种 渲染管线 ,一种是内置的 渲染管线 ,一种是可编程 渲染管线 可编程 渲染管线 又分为三种:1、urp 通用 渲染管线 2、hdrp 高清 渲染管线 3、完 自定义的 渲染管线 切换 渲染管线 : 一般一个工程只是用其中一种 渲染 ... 1、 渲染 路径 Unity 的内置 渲染管线 支持不同 渲染 路径。 渲染 路径是与光照和阴影相关的一系列操作。不同的 渲染 路径具有不同功能和性能特征。应根据项目类型以及目标硬件,选择 渲染 路径。 可在 Graphics 窗口中选择项目使用的 渲染 路径,并可为每个摄像机覆盖该路径。 如果运行项目的设备上的 GPU 不支持所选的 渲染 路径,则 Unity 将自动使用较低保真度的 渲染 路径。例如,在无法处理延迟着色的 ......
Easy Decal 为你提供一个易于使用的工作 流程 来将贴花贴在游戏世界中的所有类型的表面上。为你的虚拟世界丰富细节,并将你的游戏环境提升至更高一级。 Easy Decal 不仅支持衍射纹理和法线贴图,而且还支持各种着色器和材料。你可以轻松地将贴花贴到巨大的崎岖表面上 - 其动态几何形状生成器会在眨眼间自动调整所有所需参数(UV、切线、法线等)。仅使用一个工具,就能让你的贴花则随地可用。 • 适用于所有 Unity 版本 • 完整的编辑器集成 • 自定义材料以及着色器 • 包含即用的预制件 • 包含 80 多个不同的贴花 • 3D 投影(转化、旋转、缩放) • 动态几何 • 纹理图志编辑器 • 贴花动画 • 边缘融合 • 网格贴花 • 屏幕空间贴花 • 用于 LWRP/URP [测试版] 的屏幕空间贴花 • 延迟贴花 • 静态网格(需要框/网格碰撞器) • 经过 Oculus Rift 的广泛测试 SRP 支持 • 框形投影器(网格 贴花) • 平面投影器(网格贴花) • 无光照的屏幕空间(倍增) • 框形投影器(网格 贴花) • 平面投影器(网
对于 Unity URP(Universal Render Pipeline) 渲染管线 的烘焙,你可以通过以下步骤进行操作: 1. 打开 Unity 编辑器,确保已经安装并启用了URP 渲染管线 。 2. 创建一个新的空物体,或者选择现有的物体作为你要进行烘焙的对象。 3. 在Inspector面板中,选择该物体的Renderer组件。 4. 在Renderer组件的设置中,找到Lighting部分,并启用"Lightmap Static"选项。这将告诉 Unity 该物体需要参与光照烘焙。 5. 在场景中放置光源,例如Directional Light、Point Light或Spot Light。 6. 调整光源的参数,例如颜色、强度、阴影等,以满足你的需求。 7. 在菜单栏中选择"Window" > "Rendering" > "Lighting Settings",打开光照设置窗口。 8. 在光照设置窗口中,选择"Bake"选项卡。 9. 点击"Bake"按钮开始进行光照烘焙。 10. 等待烘焙完成后,你可以在场景中预览烘焙结果。 请注意,烘焙过程可能需要一定的时间,具体时间取决于场景复杂度和硬件性能。此外,在进行烘焙之前,请确保场景设置和材质设置正确,以获得最佳的烘焙效果。