自底向上的SRP教程 I

Custom Render Pipeline

对 Catlike Coding 教程的解析与补充

点击传送——>CustomRenderPipeline

1.SRP入口

1
2
3
4
5
6
7
8
9
10
11
12
public class CustomRenderPipeline : RenderPipeline
{
CameraRender cameraRender = new CameraRender();
protected override void Render(ScriptableRenderContext context, Camera[] cameras)
{
foreach(Camera camera in cameras)
{
cameraRender.Render(context, camera);
}
}

}
  • 继承自 RenderPipeline 实现抽象函数 Render 驱动渲染
  • ScriptableRenderContext 是参与渲染的SRP上下文
  • Camera[] 存储所有参与渲染这一帧的所有摄像机对象
  • 一般创建相机管理类对每个相机进行渲染(CameraRender)

2.设置相机属性

1
context.SetupCameraProperties(camera);

SetupCameraProperties方法的作用是在相机渲染时,根据相机的参数设置相机的矩阵、近裁剪面、远裁剪面等属性,以便正确渲染场景。该方法在相机渲染前被调用,用于确定相机的位置、旋转、缩放等参数,并计算出相应的投影矩阵、视图矩阵等矩阵,以便正确渲染场景。这样,我们就能够以正确的角度、比例和距离观察场景,并能够从不同角度和距离观察场景,以满足不同的需求

3.CommandBuffer

SkyBox,Gizmos这些比较特殊的内容通过ScriptableRenderContext来发送渲染命令,其他更普遍的渲染命令需要通过CommandBuffer间接发出。它是一个容器,保存需要执行的渲染命令。通过它我们可以在渲染管线的不同阶段插入自定义的绘制命令,实现对渲染的控制。

1
2
3
4
5
6
7
8
private const string bufferName = "CAMERA BUFFER";
private CommandBuffer buffer = new CommandBuffer { name = bufferName };

private void ExecuteBuffer()
{
context.ExecuteCommandBuffer(buffer);
buffer.Clear();
}

执行命令和清空缓冲区一般是一起执行的,所以可以抽象成一个方法

4.清除渲染目标

1
2
CameraClearFlags flags = camera.clearFlags;
buffer.ClearRenderTarget(flags <= CameraClearFlags.Depth, flags == CameraClearFlags.Color, Color.clear);
  • CameraClearFlags是用于控制摄像机渲染前是否对上一帧的渲染结果进行清空的枚举类型,可以在Camera组件上进行设置
  • ClearRenderTarget()三个参数分别为
    • 是否清空深度缓冲(深度缓冲区应当在所有情况下清除,除非标志为Depth)
    • 是否清空颜色缓冲(当标志为Color时清空颜色缓冲区)
    • 清空后的颜色值Color.clear(线性空间的话用camera.background.linear)

5.剔除

1
2
3
4
5
6
7
8
9
10
11
private bool Cull()
{
ScriptableCullingParameters parameters;

if(camera.TryGetCullingParameters(out parameters))
{
cullingResults = context.Cull(ref parameters);
return true;
}
return false;
}
  • camera.TryGetCullingParameters()方法指示是否获取剔除参数(剔除掩码、LOD、阴影距离等)
  • context.Cull() 根据输入的参数判断哪些物体应该被剔除,返回一个剔除结果集合容器

6.绘制可见物体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void DrawVisibleGeometry()
{
// 1.绘制不透明物体
// 设置渲染顺序 指定渲染相机
var sortingSettings = new SortingSettings(camera)
{
criteria = SortingCriteria.CommonOpaque
};
// 设置渲染的Shader以及排序模式
var drawingSettings = new DrawingSettings(unlitShaderTagId, sortingSettings);
// 设置哪些类型的渲染队列可以被绘制
var filteringSettngs = new FilteringSettings(RenderQueueRange.all);

context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettngs);

// 2.绘制天空盒
context.DrawSkybox(camera);

// 3.绘制透明物体
sortingSettings.criteria = SortingCriteria.CommonTransparent;
drawingSettings.sortingSettings = sortingSettings;
// 只渲染RenderQueue为transparent的物体
filteringSettngs.renderQueueRange = RenderQueueRange.transparent;

context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettngs);
}
  • SortingCriteria枚举,控制Unity在绘制对象之前对对象进行排序的方式
    • SortingCriteria.CommonOpaque: 经典不透明对象排序
    • SortingCriteria.CommonTransparent: 经典透明对象排序
  • 一般情况下渲染顺序:不透明物体->天空盒->透明物体(如果不分开绘制天空盒最后绘制会遮挡透明物体)

7.局部类分离代码

CameraRender.cs:

1
2
3
4
public partial class CameraRender
{
...
}

CameraRender.Editor.cs

1
2
3
4
5
6
7
8
9
10
partial class CameraRender
{
partial void DrawGizmos();
#if UNITY_EDITOR
partial void DrawGizmos()
{
...
}
#endif
}

需要在宏外边声明方法

8.在场景中绘制UI

1
2
3
4
5
6
7
partial void PrepareForSceneWindow()
{
if(camera.cameraType == CameraType.SceneView)
{
ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
}
}
  • CameraType.SceneView用于编辑场景视图,Scene View摄像机可以自由移动、旋转和缩放,以查看和编辑场景中的各个部分。此外,它还可以显示辅助网格、灯光、碰撞器等编辑工具的信息,以帮助用户更好地进行场景编辑。不会渲染到游戏视图,而是渲染当前正在编辑的场景。Debug输出的名称是:SceneCamera
(下接 自底向上的SRP教程 II)

自底向上的SRP教程 I
https://baifabaiquan.cn/2023/04/13/自底向上的SRP教程I/
作者
白发败犬
发布于
2023年4月13日
许可协议