《Unity Shader入门精要》读书笔记__渲染管线

2.1综述

渲染流水线(概念流水线):三维场景—>二期图像。

渲染流程:

《Unity Shader入门精要》读书笔记__渲染管线_第1张图片应用阶段:CPU负责实现。输出渲染图元(rendering primitives),即渲染所需的几何信息,可以是点、线、三角面等。

几何阶段:GPU上进行。处理所有和我们要绘制的几何相关的事情。

重要任务:将顶点坐标变换到屏幕空间中交给光栅器进行处理。

光栅化阶段:GPU上进行。使用上个阶段的数据产生屏幕上的像素并渲染出最终图像。

任务:决定每个渲染图元中的哪些像素应该被绘制。

2.2 CPU和GPU之间的通信

应用阶段可分为三个阶段:

2.2.1 把数据加载到显存中

渲染所需的数据:硬盘(HDD)->系统内存(RAM)->显存(VRAM)

2.2.2 设置渲染状态

渲染状态:定义场景中的网格如何被渲染。

2.2.3 调用Draw Call

Draw Call:一个由CPU到GPU的命令。指向需被渲染的图元(primitives) 列表。

给定Draw Call后,GPU根据渲染状态和输入的顶点数据进行计算,最终输出 像素。计算过程为如下的GPU流水线。

2.3GPU流水线(实际上的流水线)

2.3.1概述

《Unity Shader入门精要》读书笔记__渲染管线_第2张图片

 

光栅化阶段重要任务:计算每个图元覆盖了哪些像素,以及为这些像素计算它们的颜色。

顶点着色器(Vertex Shader):完全可编程,通常用于实现顶点空间变换、顶点着色等。

曲面细分着色器(Tessellation Shader):可选,用于细分图元。

几何着色器(Geometry Shader):可选,被用于执行逐图元(Per-Primitive)的着色操作或 被用于产生更多图元。

裁剪(Clipping):可配置,将摄像机视野外的顶点裁减掉,并剔除某些三角图元的面片。

屏幕映射(Screen Mapping):不可配置&编程,把每个图元的坐标转换到屏幕坐标系中。

三角形设置(Triangle Setup):固定函数。

三角形遍历(Triangle Traversal):固定函数。

片元着色器(Fragment Shader):完全可编程,实现逐片元的着色操作。

逐片元操作(Per-Fragment Operations):不可编程,高度可配置性,负责修改颜色,深度缓冲,进 行混合等。

2.3.2顶点着色器

主要任务:坐标变换,逐顶点光照。(以及输出后续阶段所需数据)

坐标变换:可以在这一步改变顶点的位置。Eg:用来模拟水面、布料等。

把顶点坐标从模型空间转换到齐次裁剪空间(必须完成)。

代码中如o.posWS =mul(unity_ObjectToWorld, v.vertex);

《Unity Shader入门精要》读书笔记__渲染管线_第3张图片

 

图2.8,坐标范围是OpenGL(同时也是Unity使用的NDC),z分量范围[-1,1]

而在DirectX中,NDC的z分量[0,1]。

2.3.3裁剪

将部分在视野内的图元的图元进行处理。

Eg:一个线段的一个顶点在视野内,另一个不在,那么视野外部的顶点应该使用一个新的顶点来代替,这个新的顶点位于这条线段和视野边界的交点处。

2.3.4屏幕映射

输入三维坐标系下的坐标(范围在单位立方体内),把每个图元的x和y坐标转换到屏幕坐标系(Screen Coordinates)(二维,与分辨率有关)下。

Ps:z坐标不会被处理,屏幕坐标系和z坐标一起构成了窗口坐标系(Window Coordinates)。

《Unity Shader入门精要》读书笔记__渲染管线_第4张图片 

Ps:屏幕坐标系在OpenGL 与 DirectX 之间存在差异

2.3.5三角形设置

主要任务:计算边界的像素信息,获得三角形边界
辅助理解:计算几何阶段传入的信息,查找三角网格的像素为止

2.3.6三角形遍历(扫描变换(Scan Conversion))

主要任务:查找哪些像素被三角形网格覆盖。

若覆盖则生成一个片元(fragment),而片元中的状态是对3个顶点的信息进行插值得到的。

这一步输出就是得到一个片元序列。

2.3.7片元着色器(像素着色器(Pixel Shader))

输入:上一个阶段对顶点信息插值得到的结果。

输出:一个或者多个颜色值。

这一阶段可以完成很多重要的渲染技术,如纹理采样。

局限性:仅影响单个片元,即执行片元着色器时,不可将自身任何结果发送给其领周围片元。
例外:片元着色器可访问到导数信息

2.3.8逐片元操作/输出合并阶段(Output-Merger)

OpenGL中为逐片元操作,在DirectX中为输出合并阶段。

主要任务:

1决定各片元的可见性(例如:深度测试、模板测试)
2将通过所有测试的片元的颜色值与存储在颜色缓冲区的颜色进行合并(混合)

《Unity Shader入门精要》读书笔记__渲染管线_第5张图片

 

2.3.8.1 模板测试

  原理:GPU读取模板缓冲区该片元位置的模板值

  目的:限制渲染区域(指定比较函数,>、<、≤、≥指定值时舍弃该片元)

  用法:渲染阴影、轮廓渲染

2.3.8.2 深度测试

  前提:通过了模板测试

  原理:GPU将深度值与已存在于深度缓冲区的深度值比较(通过值可覆盖原有深度值)

  用法:透明效果

2.3.8.3 混合(Blend)

《Unity Shader入门精要》读书笔记__渲染管线_第6张图片

 

PS:

Early-Z技术:尽管逐片元操作位于片元着色器之后,但是为了避免造成性能浪费,深度测试可以提前在片元着色器之前进行。

PS:

双重缓冲(Double Buffering):对场景的渲染是在后置缓冲(Back Buffering)中进行,一旦场景渲染好,GPU就会交换后置缓冲区和前置缓冲(Front Buffer)中的内容。前置缓冲就是之前显示在屏幕上的图像。

2.4 Draw Call

2.4.1 什么是Draw Call?

  CPU调用图像编程接口。

2.4.2 造成性能问题的元凶是谁?

  CPU。

解释:CPU添加命令至 “命令缓冲区” ,GPU依次读取命令进行缓冲。值得注意的是当GPU完成一次渲染工作后,才会取出下一命令继续执行。

4.3 为什么Draw Call多了会影响帧率?

  CPU的完成需要很多准备工作,但GPU的渲染执行能力却快于CPU,造成CPU耗时长的提交渲染信息与命令。出现CPU过载,GPU闲置工作的情况。

4.4 如何减少Draw Call

批处理:将很多小的Draw Call合成一个大的

适用范围(更适合静态物体,因为只需要合并一次即可):

  - 不会移动的地面、岩石等(参照 Unity的静态批处理)

  - 飞行的禽兽,鱼等(对动态的批处理)。

注意:由于这些物体时刻运动,需每帧重新合并后发送至GPU,对空间和时间均有一定程度影响。

注意事项:

  - 避免使用大量很小的网格。(出现不可避免情况,需考虑是否可以合并)

  - 避免使用过多的材质。(不同网格之间尽可能公用同一材质)

名词解释:

图元:基本图形元素是任何一个图形表达都是由若干不同的点、线、面图案或相同 的图案循环组合而成的。这些点、线、面图案即为基本图形元素

NDC:

插值:在离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据 点。插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况, 估算出函数在其他点处的近似值。应用上,可用来填充图像变换时像素之间的空隙。

片元:片元并不是真正意义上的像素,它包含了很多状态(屏幕坐标、深度信息、顶点 信息等等),这些状态用于计算每个像素的最终颜色。

你可能感兴趣的:(计算机图形学,图形渲染,着色器,技术美术)