---
title: "SRP"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/unity-srp-scriptable-render-pipeline/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/05-游戏图形与运行时/渲染基础/SRP.md"
content_hash: 883b8ccb842d1e7cfc6e69c7bbcfd4512b726e37e2cb4115fca438203c5672dd
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
# SRP
## 1 渲染基础知识

![assets/0001 - SRP__5bc3eddacd591.png](/media/7e078ef72b0cffd9066c.png)


### 1.1 图形渲染管线

《Render-Time Rendering Third Edition》一书中将计算机图形渲染的流程划分为3个阶段


#### 应用阶段（Application Stage）

准备好要渲染的场景数据，如相机，模型，灯光等信息，为提高性能对不可见的物体进行剔除（Culling），最后设置好每个即将渲染的模型所对应的渲染状态。渲染状态包括但不限于材质，纹理，Shader等。


#### 几何阶段 （Geometry Stage）

该阶段运行在GPU上


1. 模型和视图变换 Model and View Transform
2. 顶点着色 Vertex Shading 顶点着色阶段的目的即确认顶点处材质的光照效果。像顶点位置，法线等数据都会通过该阶段发送到光栅化阶段。
3. 投影 Projection 该阶段就是将模型从三维空间投射到二维空间的过程 常见的投影方式有两种：**正交投影**，**透视投影**
4. 裁剪 Clipping

![assets/0001 - SRP__5bc3ee3de2ed6.png](/media/568fe7483e536b6763ea.png)

当图元完全处于视体内部，直接进入下个阶段

当图元完全处于视体外部，直接丢弃

当图元部分处于视体内部，对图元进行裁剪并产生新的图元

裁剪阶段即对部分处于视体内部的图元进行裁剪操作。


1. 屏幕映射 Screen Mapping

![assets/0001 - SRP__5bc3ee08bff1f.png](/media/c94b2d6c07ae53d2b19a.png)

进入该阶段顶点坐标仍然是三维的，但x,y在经过上面的投影阶段已经是二维的状态。此时x,y与z坐标组成了窗口坐标系。

假设在一个窗口里对场景进行绘制，窗口最小坐标(x1, y1)，最大坐标(x2, y2)。屏幕映射首先进行平移，随后进行缩放，在映射过程中z坐标不受影响。新的x和y坐标称为屏幕坐标系，并和z坐标进入光栅化阶段。


屏幕映射阶段即是将得到的坐标映射到对应的屏幕坐标系上。


#### 光栅化阶段（Rasterizer Stage）

1. 三角形设置 Triangle Setup 计算三角形表面的差异和三角形表面的其他相关数据
2. 三角形遍历 Triangle Traversal 扫描三角形覆盖的像素区域，并将重合的像素生产片段（fragment）。
3. 像素着色 Pixel Shading 逐像素处理着色运算
4. 合并 Merging

图形系统一般都是使用**双缓冲机制**，也就是最终生产的图像会输出到**后台缓冲区**(backbuffer)，然后交换至屏幕。合并阶段就是将前面所有片段操作（如：颜色缓冲区，alpha通道，模板缓冲区，深度测试结果等）所产生的片段颜色合并至后台缓冲区(backbuffer)。


### 1.2 GPU渲染管线

![assets/0001 - SRP__5bc3ee61dd019.png](/media/fb243f1b04071ff14194.png)


> 绿色阶段完全可以编程
>
> 蓝色阶段可配置，不可编程
>
> 灰色阶段完全固定，不可配置，不可编程
>
>
> 后续知识路径：
>
>
> Unity中的固定管线
>
>
> - Deferred Rendering
> - Forward Rendering
>
> Unity中的可编程管线
>
>
> - High Definition Render Pipeline
> - LightWeight Render Pipeline
> - 自定义渲染管线


## 2 SRP概述

可编程渲染管线是一个可以通过代码控制渲染的方式的管线。


### 2.1 解决了什么问题

#### 问题

传统Unity提供了一系列的内置管线供我们使用。包括**前向渲染**和**延迟渲染**。这些渲染方式是传统渲染黑盒子的缺点：


- 只能按照他们本身设计的程序执行
- 很一般，它们需要做每一件事，而不能掌控任何流程
- 不可配置。只能在预设的位置注入一些指令
- 拓展性和可修改性有限，内部较小的修改可能导致外部较大的变化 由于改变破坏项目的行为产生Unity无法修复的Bug


#### 解决

SRP Core API 解决了上面描述的问题。其将渲染流程从原来的黑盒转向可控制、预制件、可编程的方向。


### 2.2 概念与过程

#### SRP Asset

SRP Asset本身是一个ScriptableObject，我们可以对其进行保存和版本控制。在GraphicsSetting中进行设置，Unity会使用SRP提供的渲染设置。SRP Asset提供了配置渲染管线的接口，当Unity实现第一次渲染的时候，其会调用InternalCreatePipelineCreatePipeline，Asset会返回一个SRP Instance。


```
[ExecuteInEditMode]

public

class

BasicAssetPipe
 :
RenderPipelineAsset


{


public
 Color clearColor = Color.green;


#
if
 UNITY_EDITOR


// Call to create a simple pipeline


 [UnityEditor.MenuItem(
"SRP-Demo/01 - Create Basic Asset Pipeline"
)]


static

void

CreateBasicAssetPipeline
(
)


{


var
 instance = ScriptableObject.CreateInstance<BasicAssetPipe>();

 UnityEditor.AssetDatabase.CreateAsset(instance,
"Assets/BasicAssetPipe.asset"
);

 }


#
endif


protected

override
 RenderPipeline
CreatePipeline
(
)


{


return

new
 BasicPipeInstance(clearColor);

 }

}
```


#### SRP Instance

SRP Asset控制配置，但是SRP Instance是真正的渲染的切入点，渲染的逻辑都在SRP Instance中。SRP Instance中包括一个Render function，此方法包括两个变量：ScriptableRenderContext（Command Buffer用于排列渲染相关操作）、Camera（需要渲染的摄像机）。


```
public

class

BasicPipeInstance
 :
RenderPipeline


{


private
 Color m_ClearColor = Color.black;


public

BasicPipeInstance
(
Color clearColor
)


{

 m_ClearColor = clearColor;

 }


protected

override

void

Render
(
ScriptableRenderContext context, Camera[] cameras
)


{


// clear buffers to the configured color


var
 cmd =
new
 CommandBuffer();

 cmd.ClearRenderTarget(
true
,
true
, m_ClearColor);

 context.ExecuteCommandBuffer(cmd);

 cmd.Release();

 context.Submit();

 }

}
```


SRP使用Unity中的CommandBuffers提供相关操作，CommandBuffers中的顺序是根据context传入的数据排序。SRP渲染最后一步需要调用context.Submit()方法，这一步执行render context中相关指令。


#### SRP Context

SRP渲染使用了延迟执行的方法。如果我们创建了一系列指令并执行它们。用于创建指令的的对象叫ScriptableRenderContext作为一个参数传给Render方法。


#### SRP中的Culling

- 视锥剔除：只计算在摄像机近裁剪面和远裁剪面之间的游戏物体
- 遮挡剔除：计算那些物体被遮挡了，并将被遮挡的物体进行剔除。

Unity开始渲染第一步是计算哪些可以渲染。这包括选择一个摄像机和进行剔除操作。剔除操作返回一个**被摄象机渲染的游戏物体**和**光照的列表**。SRP将在之后的渲染管线中使用这些游戏物体。SRP提供了很多关于剔除的相关API。


```
//Parameters controlling culling process in CullingResults


ScriptableCullingParameters cullingParams;

Camera.main.TryGetCullingParameters(
out
 cullingParams);

//doing culling for each camera


CullingResults cullingResults =
new
 CullingResults();

cullingResults = context.Cull(
ref
 cullingParams);
```


#### SRP中的 Drawing

在SRP中draw需要在culling步骤完成之后进行。

在渲染管线中可配置的部分很多，有一些我们需要在工作之前进行确认：


- 渲染管线的目标硬件、
- 想实现的特殊视觉效果
- 项目的类型

具体的选项：


- HDR vs LDR
- Linear vs Gamma
- MSAA vs Post Process anti-aliasing
- Physically-based Materials vs Simple Materials
- Lighting vs No Lighting
- Lighting technique
- Shadowing technique

实例1:过滤：Render Buckets and Layers

无光照，渲染一些不透明的物体

游戏物体有很多的类别，Unity使用队列的方式对其渲染。这些队列来自Unity存放GameObjects的buckets。当SRP渲染场景的时候，可以指定buckets的范围。

在buckets，可以使用标准的Unity Layers进行过滤。


```
var
 opaqueRange =
new
 FilteringSettings();

//FilteringSettings.renderQueueRange : Render objects whose material render queue in inside this range


//这里的渲染队列在[0,GeometryLast]之间是为不透明对象，在[GeometryLast,5000]之间被视为半透明对象。


opaqueRange.renderQueueRange =
new
 RenderQueueRange(
0
, (
int
)RenderQueue.GeometryLast);

//layerMask - Only render objects in the given layer mask


//Include all layers


opaqueRange.layerMask = ~
0
;
//??????不懂
```


实例2：绘制设置：物体如何被绘制出来的

通过前面的filtering和culling的过程，SRP决定了那些是需要渲染的对象，但是还需要进行如何绘制的设置.SRP提供了大量的可选择配置来渲染那些通过了过滤的游戏物体。用于配置的结构体叫做 DrawRenderSettings：允许我们进行配置：


Sorting - 渲染游戏物体的顺序，比如从前向后或从后向前

Per-Renderer flags - 那些内置的设置要Unity传给Shader，这包括像预置的光线探针(probe)、预置的光线贴图

Rendering flags - SRP batching的算法，像instancing 或者 non-instancing

Shader Pass - 当前渲染批次使用哪个Shader pass


```
//Setting for DrawRenderers.describes how to sort visible objects are sorted and which shader passes to use.


//SortingSettings - This struct describes the methods to sort objects during rendering.


var
 ds =
new
 DrawingSettings(
new
 ShaderTagId(
"Opaque"
),
new
 SortingSettings(Camera.main));

ds.enableInstancing =
true
;

//what kind of per-object data to setup during rendering. pass lightprobe and lightmap data to each renderer


ds.perObjectData = PerObjectData.LightProbe | PerObjectData.Lightmaps;
```


创建一个DrawingSettings对象，并设置这个对象的一些属性。


在完成上面的两个步骤后就可以进行绘制了


#### Free Camera

添加一个Free Camera组件，可以让摄像机通过键盘和鼠标进行简单的的移动，在Play Mode下进行移动和旋转。


#### Camera Switcher

Camera Switcher组件可以定义一系列相机，然后在Play Mode中通过Debug Window在这些相机之间进行切换。


### 2.3 Unity 渲染管线框架

Build-In Render 内置渲染器（默认）兼容太多，反而不能面面俱到，效果不好


Scriptable Render Pipline 可编程渲染管线技术，是Unity提供的新渲染系统，可用C#脚本定制Unity的渲染过程，但自己定制渲染管线对编程要求很高，难度大，所以Unity提供里2个预制的管线，基本上涵盖了我们所有的需求，使用时不需要太底层的技术要求！


High Definition Render Pipeline (HDRP): 高分辨率渲染管线，适用于PC或主机上的AAA级别游戏，同时支持Forward and Deferred 渲染。专注于高端图形渲染，针对高端硬件配置，像PC、XBox 和Playstation，其面向高逼真度的游戏、图形demo和建筑渲染、超写实效果，以及所需的最佳图形效果。同时针对高端图形处理时，它要比内置渲染器要快得多，但如果用来做low poly风格的作品就有点杀鸡用牛刀了，纯属浪费资源和时间；但要想得到完成利用HDRP的完美表现能力，需要大量的贴图，漫反射贴图、高光贴图、金属贴图、平滑贴图、AO贴图、法线贴图、凹凸贴图、高度贴图…So,要做HDRP流程需要非常长的时间和庞大的制作团队，还有充足的预算！建议5人以下的小团队慎入！


Universal Render Pipleline 通用管线流程（URP前身为Lightweight Render Pipeline — LWRP轻量级渲染管线），专注于性能，适用于移动端，URP是选了不会错的渲染管线，它被设计为能够在任何平台上都能提供最好的性能，所以除非有特殊需求只能在HDRP或者SRP解决的，其他都应该选择URP，不管是移动端、主机、PC等，URP都能提供高性能的渲染，目前URP能做的也非常多，它拥有很多HDRP相同的功能，但为了在所有平台达到更好的性能，其做了一定的缩减，但这并不意味着URP做不出漂亮的游戏；

LWRP使用Forward渲染。LWRP使用LWRP和LWRP-VR两种模板。LWRP同样使用自己的Shader，与Unity内置shader不兼容。


这两个内置管线都以package包的形式发布，都包含了Shader Graph编辑器和Post Processing后处理器。


> 总之
>
>
> - Build-In Render Pipeline内置渲染管线是Unity提供的固定的、不可编程控制的原始的渲染管线；
> - SRP是Unity提供的，一种渲染管线的实现方案——用户可以用C#编程控制渲染过程
> - HDRP和URP是Unity基于SRP的方式，提供的两种渲染管线的框架，是SRP实现的两种方案


#### URP HDRP区别

这两种管线流程都利用里Unity新的可编程渲染管线技术，Unity正在把他们变成新的标准，shader graph，visual effect graph这些新功能都是他们的专属，这两个都是创作shader和粒子特效很棒的工具，也支持VR，不过HDRP做逼真风格的VR性能要求非常高！因为Unity实际上把所有东西渲染2次（因为有两个镜头），所以延迟渲染现在只有HDRP支持，不过对URP的支持官方已经在路上。


两者最大的区别是对光照的支持，HDRP提供高级和丰富的光照功能，比如实时全局光照（RealTime GI），能够模拟光线反射、体积光、能模拟光穿过空气中的粒子，还有重头戏的光线跟踪，一种新的光线反射和阴影渲染技术，其原理是跟踪光线在场景中放射的路径，模拟光线在真实世界里与物体交互的效果，这技术对硬件性能非常高，但能产生非常逼真的效果，可以直接用来做电影级别的预渲染作品。


> **Global Illumination**（全局光照，缩写GI），是3D计算机图形中使用的一组算法通用名称，旨在为3D场景添加更逼真的照明效果。


另外一个区别是Shader，HDRP提供一系列高端的shader特效，例如高度、细节和parallax Maps，分别用于纹理的位移、细节和深度模拟，它还支持子面散射，用于模拟光线穿过很薄的物体，比如皮肤和衣物，它提供了高级的shader，像是stacklit，能够让你同时使用多个材质的属性，比如子面散射、彩虹色、各向异性和模糊参数化。


对于后处理效果，两者不相伯仲，HDRP独占的最重要效果，包括AO（环境光遮蔽）、自动曝光（模拟人眼适应不同光线条件的能力）、屏幕空间反射（模拟基于屏幕上可见物体的反射）；URP的AO支持已经在做了，但好东西不是都在HDRP，2D光照和阴影就是URP独占的，所以如果你在做2D游戏，就选URP！


另外两个管线都支持一个很Cool的特效—相机堆叠，让你能够同时用多个相机渲染。


## 3 总结

![assets/0001 - SRP__68747470733a2f2f692e696d6775722e636f6d2f55426b643353582e706e67.png](/media/58afbcc04b2641ae802b.png)


## 4 Ref

<https://blog.csdn.net/Game_Builder/article/details/102805829>

<https://blog.csdn.net/u013477973/article/details/83312809>

<https://gameinstitute.qq.com/community/detail/127854>

<https://www.jianshu.com/p/177927be1a62>

<https://blog.csdn.net/weixin_41622043/article/details/107623694>


<https://blog.csdn.net/u013477973/article/details/83312809>

<https://zhuanlan.zhihu.com/p/99142987>

<https://zhuanlan.zhihu.com/p/93203710> （SRP翻译系列汇总）
