渲染管线

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Unity 是一款跨平台的 3D 引擎有着强大的渲染功能并主要用于游戏开发。

谈到 Unity 的渲染功能我们不得不提及到着色器Shader——3D 游戏引擎中最重要的一个因素­,它在游戏效果以及画面显示方面起到了决定性的作用。Shader 编程也属于计算机图形学中一个重要的部分。

接下来让我们从可编程渲染管线来了解 Shader 编程。

渲染管线模型

3D 游戏以及 3D 模型通过渲染管线来渲染到 2D 的屏幕上。渲染管线的流程是在 GPU 中进行的它主要占有计算机的显存部分。渲染管线在这个过程中进行了顶点处理、面处理、光栅化、像素处理。

1顶点处理

大多数接触过 3D 图形的人都知道3D 模型是通过众多点构成的面而展现出来的。

顶点处理是通过一系列坐标系的变换让各个顶点通过一定的规律在摄像机前位移最终在屏幕上对应这些顶点的过程。

首先物体的各个顶点从自身坐标系通过世界变换矩阵处理转换到世界坐标系再通过取景变换矩阵变换到观察者坐标系最后通过投影变换将顶点转移到屏幕坐标系。

有一点大家会经常忘记在观察者坐标系转换到投影坐标系的过程中GPU图形处理单元还对材质属性和光照属性进行了处理。

2面处理

三点成一面。面处理有三个部分面的组装、面的截取、面的剔除。

面的组装模型中的三个点会组成一个三角形的面非任意点因为每个点都有自己的编号。这些面面面相接组成了我们能看到的模型。

面的截取由于摄像机和人眼一样可视的区域是一个锥形模型在摄像机可视范围内可能并不是全覆盖也就是在摄像机外这些在摄像机之内的部分就会被截取。

面的剔除为了模拟肉眼摄像机前的物体会出现近大远小的现象那么物体和物体之间会有遮挡被遮挡的面会被剔除不处理每个面都有法向量所以只有在面的法向量和摄像机散射向量夹角大于90度的才会被摄像机捕捉到。

3光栅化

光栅化又称之合并阶段。它的主要功能是将面转换成一帧中的像素集合。

这一阶段是不可以编程的它负责执行多个片段测试包括深度测试、alpha 测试和模板测试程序员可以通过高度配置来实现想要的效果。如果通过了所有的测试这部分颜色就会与帧缓冲存储的颜色通过 alpha 混合函数进行合并。

4像素处理

这个阶段将像素区域着色然后赋予贴图。

左上为3D网格模型左下为赋予贴图后的3D模型右图为贴图

Shader 详解

介绍完GPU 渲染管线之后我们再来简单了解一下可编程着色器 Shader —— 图形渲染里最有趣的部分。Shader 能让渲染的图形展示出水面效果、火焰的热流效果、角色的虚化效果等视觉效果。

着色器可分为顶点着色器VertexShader、几何着色器Geometry Shader和像素着色器Pixel Shader。它们从输入的数据中取得一个元素通过程序计算变换为输出数据的一个或多个元素

顶点着色器输入源为顶点顶点包含其在自身坐标系或世界坐标系的位置和矢量信息而输出源为已通过变换和照明处理的顶点包含其投影坐标系的信息。

几何着色器的输入源为一个有 n 个顶点的几何图元以及最多 n 个作为控制点的额外顶点输出源则变成 0 或多个图元。根据效果需要这些图元的可能和输入的时候不同。

像素着色器输入为顶点间的片段这些片段所包含的信息来自于对三角形顶点信息的插值输出成将要写到帧缓冲里的颜色

渲染管线概述

Unity渲染管线流程

多相机渲染

CPU渲染管线

层级剔除

遮挡剔除

发送数据将所有数据打包发送给GPU

GPU渲染管线

图元装配及光栅化

执行裁剪

裁剪空间转换到NDC

计算NDC

背面剔除

图元装配

光栅化

片元着色器Shader

纹理寻址模式

纹理压缩格式

光照计算

光照模型

经验光照模型

环境光

输出合并

Alpha测试

模板测试

深度测试

混合Blending

后处理

Unity渲染管线流程

CPU打包数据材质法线

a. 剔除物体摄像机外的物体将被剔除

b. 渲染排序安装给定顺序和深度对物体进行排序

c. 发送数据将所有数据打包发送给GPU

d. 调用ShaderSetPassCallDrawCall

GPU渲染管线

a. 顶点着色器将逐顶点执行。将模型空间转换到裁剪空间。可以处理顶点偏移和顶点光照。

b. 顶点着色器后光栅化阶段

裁剪片元: 将裁剪空间外的模型裁剪掉

转换为NDC标准化设备坐标使用透视除法

剔除背面剔除正面剔除等将特定方向的顶点进行剔除

视口转换转换到屏幕坐标

图元装配

光栅化会产生锯齿

c. 片元着色器逐像素执行。

d. 片元着色器之后输出合并阶段

Alpha测试

模板测试

深度测试

颜色混合

e. 帧缓冲区

f. 后处理阶段CPU调用GPU渲染管线

g. GPU渲染到屏幕

多相机渲染

每个摄像机都会渲染一遍该相机内的物体的顶点。

每个相机都会跑一次完整的渲染管线流程

默认会清除除天空盒之外的其他物体通过ClearFlags和Depth设置清楚条件和渲染顺序。

如果不清楚其他相机的物体将会出现渲染叠加。

通过一个相机清除一个相机保留好像可以实现3D视频的左右眼效果。虽然需要两倍的渲染时间

CPU渲染管线

剔除物体摄像机外的物体将被剔除

视锥体剔除

即使用摄像机可视范围的视锥体构成的区域与物体进行碰撞检测。

优化但是复杂的物体碰撞检测很耗性能因此会使用一个简单的碰撞体Box Colider进行包裹称为AABB包围盒。

层级剔除

通过摄像机进行特定物体的剔除。剔除特定层级的物体未被勾选即被剔除物体。

感觉这个可以实现物体的快速隐藏。(通过将物体设置到隐藏层来减少渲染而又无需摧毁。

遮挡剔除

通过判断物体位置和遮挡关系对被不透明物体完全遮挡的物体进行剔除。

渲染排序安装给定顺序和深度对物体进行排序

通过Render Queue数值进行排序相等时使用深度进行排序。

不透明物体默认2000

透明物体默认3000

大于2500理解为半透明队列将按深度进行从后向前排序

小于2500理解为不透明物体按深度从前向后排序

不透明物体从前向后排序有助于优化被遮挡物体将不会被渲染。

半透明物体从后向前渲染才能保证渲染颜色正确半透明颜色混合顺序不同结果颜色不同。

半透明物体内部不能保证完全从后向前进行渲染。导致的显示效果1.向面片一样没有厚度

发送数据将所有数据打包发送给GPU

模型数据

格式obj格式fbx格式推荐

obj数据

顶点坐标三维

法线信息法线向量

UV坐标二维数据最后一位无用

索引列表一行数据表示一个三角面通过索引找到每个顶点的顶点、法线、UV。通过索引记录有助于压缩数据

调用ShaderSetPassCallDrawCall

GPU渲染管线

顶点着色器Shader

Unity中的顶点Shader

最重要的任务将顶点坐标从模型空间变换到裁剪空间

通过MVP矩阵对顶点的坐标进行变换。

模型空间变化到世界空间

参考系由物体自身变化到世界统一坐标

模型空间时建模软件的坐标空间就是模型生成的坐标。

世界空间变化到相机空间

参考系由世界坐标变化到以相机为中心

相机空间变化到裁剪空间

将相机的视锥体进行压扁标准化成2x2x1的CVV矩阵

图元装配及光栅化

执行裁剪

在裁剪坐标空间中裁剪多余的像素和图像。

超过CVV之外的形状将会被裁剪。

空间范围[w, w, 0] ~ [-w, w, w]

NDC - 标准化设备坐标

为转换到屏幕坐标做准备

空间范围[-1, -1, 1]~[1, 1, 0]

空间中的z值为深度值将会在下面几个操作中保留然后再深度剔除中排上用场。

裁剪空间转换到NDC

P.xyz / P.w = NDC

同时要注意不同的设备NDC不同

DX平台左上角[0, 0], 右下角[1, 1]

OpenGL左下角[0, 0]右上角[1, 1]

// 适应不同平台下的ndc坐标

o.screen_pos.y = o.screen_pos.y * _ProjectionParams.x;

计算NDC

我们能直接获得的最远只有裁剪空间下的坐标想要获取NDC坐标需要自己计算。但是很简单。

裁剪空间下坐标空间为[-w,-w,w] -> [w, w, 0]

NDC坐标为[-1, -1,1] -> [1, 1, 0]

裁剪空间坐标除以w可以得到=>[-1, -1, 0] -> [1, 1, 0]

方法一

// 顶点着色器

o.screen_pos = o.vertex;

// 适应不同平台下的ndc坐标

o.screen_pos.y = o.screen_pos.y * _ProjectionParams.x;

// 片段着色器

// 计算屏幕空间NDC坐标

// 透视除法 xyz范围 [-w,-w,w],[w,w,0] => [-1, -1,1]=>[1,1,0]

half2 screen_ndc = i.screen_pos.xy / (i.screen_pos.w + 0.000001);

half2 screen_uv = (screen_ndc + 1.) * .5; // [x, y]范围: [-1, 1] => [0, 1]

方法二

// 顶点着色器

o.screen_pos = ComputeScreenPos(o.vertex);

// 片段着色器

// 计算屏幕空间NDC坐标

// [x, y]范围: [-1, 1] => [0, 1]

half2 screen_uv = i.screen_pos.xy / (i.screen_pos.w + 0.000001);

背面剔除

将背对着摄像机的物体进行剔除。

通过三角面的索引列表进行排列如果排列顺序为顺时针则为正面为逆时针则为背面。

屏幕坐标空间- 视口转换

将xy坐标转换到屏幕空间的宽高。

将NDC空间下转换到屏幕空间下的坐标

图元装配

在平面中将顶点连线形成一个一个封闭的三角形。

光栅化

在平面中对每一个图元中每一个片元生成像素。

深度值Z

法线

顶点色

切线

位置

所有自定义数据

片元着色器Shader

纹理技术

纹理采样

在纹理坐标UV中进行采样[0, 0] ~ [1, 1]。通过UV映射到纹理的像素上取出那个点的像素。

纹理过滤机制

小图像映射到大块区域相当于图片放大显示。

四舍五入 - 会产生比较尖锐的边缘

双线性差值

大图像映射到小块区域引起的失真

Mipmap通过给定一组大小不同的图像进行映射。显示大区域时用大图像小区域小图像。

Mipamp只会增加1/3的存储占用。每个图像大小依次递减1/2。

纹理寻址模式

当索引超过UV时应该怎么取值。

Repeat重复模式 - 取小数将形成循环取UV的效果

Clamp截取 - 超过将会取最大、最小值。

纹理压缩格式

RGBA 32bit

ASTC 4x4 block ASTC 6x6 - 纹理细节保留较好压缩明显

ETC2 8bits

PVRTC 4bits

光照计算

光照组成

直接光照

间接光照

光照模型

BRDF基于物理的渲染模型过于复杂。

经验光照模型

光照模型基本框架 = 直接光漫反射 + 直接光镜面反射 + 间接光漫反射 + 间接光镜面反射 + …次表面散射PDR等

Lambert漫反射光照模型

Phong光照模型

通过入射光方向和法向量计算反射光方向。知道了反射光就可以对比视线和反射光的夹角来得出其看到的光线多少。

Blinn光照模型

通过入射光方向和法向量夹角计算出其半角向量。以半角方向对反射光方向进行近似半角计算更简单。

Ground光照模型

Flat光照模型

环境光

可以等同于间接光进行模拟。

间接光照实现

Lightmap

Reflection Probe

Light Probe

输出合并

最重要任务处理遮挡关系处理半透明混合。

帧缓冲区FrameBuffer

颜色缓冲区ColorBuffer

深度缓冲区DepthBufferZ-buffer

模板缓冲区StencilBuffer

Alpha测试

完全透明的或者不满足给定透明度的片元将被丢弃。

模板测试

选定一个区域进行对比不在区域中会被丢弃。

深度测试

使用深度进行测试不通过将被丢弃。

通过测试的片元的深度将被存在Z-buffer中。也可控制不写入。

在Shader中可以通过ZWrite和ZTest进行控制。

ZWrite是否写入Z-buffer

ZTest深度测试规则

提前深度测试技术

Early-Z发生在顶点Shader之后图元装配之前。

是一种提前优化技术通过提前测试避免不必要的图元装配和片元计算。

混合Blending

对半透明像素进行颜色混合。

从后到前

一般情况下会关闭ZWrite

写在Shader中如

Blend SrcAlpha OneMinusSrcAlpha

Blend SrcAlpha One

后处理

后处理可以在着色器工作完成后由CPU调用GPU对整体屏幕画面进行调整。

渲染管线可以看成3大步骤组成

CPU处理要渲染的数据将数据发送给GPU

GPU根据CPU发来的数据将画面渲染到帧缓冲区

一个画面在帧缓冲区渲染完了进行后处理后输出

一、CPU阶段

剔除

将不在视锥范围内的物体剔除掉

渲染顺序

将根据视锥范围内的物体位置决定渲染顺序

不透明队列RenderQueue<2500按照从前到后的顺序排序

透明队列RenderQueue>2500按照从后到前的顺序排序

先透明队列后不透明队列

打包发送数据

将要渲染的数据发送给GPU

一个模型的数据包含以下内容

顶点坐标Position

法线向量Normal

贴图采样位置UV

索引列表

每一行表示一个面的数据而一个面是由三个点构成

每个点的数据都包含上述abc三个数据

因此每一行的数据可以看成

点1.Position/点1.UV/点1.Normal

点2.Position/点2.UV/点2.Normal

点3.Position/点3.UV/点3.Normal

调用SetPass Call与Draw call

SetPass Call设置好各种渲染状态、背面剔除、要使用的Shader与混合模式

Draw Call通知GPU去渲染模型

二、GPU阶段

GPU阶段可以视为

点将拿到的顶点坐标转化为屏幕屏幕坐标

线将各个顶点连接起来形成一个个三角面即图元

面给三角面上色

最后输出合并。

顶点Shader将模型空间顶点转化为裁剪空间投影成像

裁剪操作将不在裁剪空间里的顶点给裁剪掉

NDC标准化设备坐标将裁剪空间转化为NDC标准化设备坐标

背面剔除将背面的三角面剔除掉

视口变换将裁剪空间转换为屏幕空间坐标

线

图元装配将顶点连接形成三角面称为图元

光栅化通过插值将图元内部形成一个个片元片元可以理解成一个像素点

片元Shader通过纹理着色、光照着色来给片元上色

输出合并

通过alpha测试、模板测试、深度测试、颜色混合

处理遮挡关系、处理半透明混合将结果绘制到帧缓冲区

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6