SRP学习笔记

SRP是什么

Unity2018添加了对可编辑渲染管线的支持,让从头搭建渲染管线成为可能,虽然在许多个别的步骤(如剔除 culling)仍然需要依赖Unity。Unity2018还介绍了用这种方法创建的两个渲染管线,轻量级渲染管线(lightweight pipeline)和高清渲染管线(highdefinition pipeline).目前这两个渲染管线仍处于预览状态,可编辑渲染管线的API也被标记为测试技术。但这已经足够让我们用于创建自己的渲染管线了。

  • 简而言之就是可以在unity里面用C#和SRP API写出C++里面用OpenGL类似的效果。
  • 所谓定义渲染管线,就是一系列的OpenGL API的调用过程,数据组织的过程。

SRP中一些比较重要的概念

RenderPipelineAsset

  • 保存了SPR的配置数据
  • 继承自Rendering.RenderPipelineAsset
  • 要想使用SRP需要在GraphicsSetting中设置

image

RenderPipeline

  • 渲染管线的编辑类,继承自RenderPipeline
  • 核心的函数是Render(),它是进入SRP的入口
  • 这对不同的camera类型,每一帧都会分别执行代码。runtime的时候主要是Game Camera。

ScriptableRenderContext

  • 它的角色是我们编写的SRP C#代码和unity底层图形代码之间的接口。
  • 执行渲染命令都是通过ScriptableRenderContext的API

CBUFFER

  • 这个是用来保存一些渲染时通用的数据的
  • 比如一帧里面VP矩阵一般是不变的,那么就不需要每渲染一个对象都用API给GPU传递一次矩阵。
  • 可以参考下面的代码的具体语法。
  • SRP Batch的实现原理也是依赖CBUFFER

SRP Batch

  • 在SRP中是用代码开启的GraphicsSettings.useScriptableRenderPipelineBatching,但是实际测试的时候只要正确设置了CBUFFER就能实现批处理。
  • 经过进一步测试GraphicsSettings.useScriptableRenderPipelineBatching是可以控制batch的
  • 对于URP和HDRP是有个inspector上的勾选项。
  • batch的原理

image

一个基础的SRP代码

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
using UnityEngine;
using UnityEngine.Rendering;

using Conditional = System.Diagnostics.ConditionalAttribute;

public class SRP1 : RenderPipeline
{
private RenderPipelineAsset _asset;
CommandBuffer commandbuffer = new CommandBuffer() { name = "SRP1Command" };

SortingSettings sortingSetting;
FilteringSettings filterSetting;
Material errorMaterial;
public SRP1(RenderPipelineAsset asset)
{
_asset = asset;
}
protected override void Render(ScriptableRenderContext context, Camera[] cameras)
{
GraphicsSettings.useScriptableRenderPipelineBatching = true;
for (int i = 0; i < cameras.Length; i++)
{
//Debug.Log("[" + cameras[i].name + "]:" + "[" + cameras[i].cameraType + "]");
Camera camera = cameras[i];

// glColorClear
CameraClearFlags flag = camera.clearFlags;
if (flag == CameraClearFlags.Skybox)
{
context.DrawSkybox(camera);
}
else
{
commandbuffer.ClearRenderTarget(
flag <= CameraClearFlags.Depth,
flag <= CameraClearFlags.Color,
new Color(0.1f, 0.4f, 0.6f)
);
context.ExecuteCommandBuffer(commandbuffer);
commandbuffer.Clear();
}

context.SetupCameraProperties(camera);
// get shader
ShaderTagId shaderTagId = new ShaderTagId("SRP1Shader");
// set draw setting
sortingSetting = new SortingSettings(camera)
{
criteria = SortingCriteria.CommonOpaque
};
// shaderTagId 和 filterSetting 都起到了过滤的作用
filterSetting = new FilteringSettings(RenderQueueRange.opaque);
var drawingSetting = new DrawingSettings(shaderTagId, sortingSetting);

// cull
CullingResults cullingResults = new CullingResults();
if (camera.TryGetCullingParameters(out ScriptableCullingParameters p))
{
cullingResults = context.Cull(ref p);
context.DrawRenderers(cullingResults, ref drawingSetting, ref filterSetting);
}
DrawDefaultPipeline(context, camera, cullingResults);
if (camera.clearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null)
{
context.DrawSkybox(camera);
}
context.Submit();
}
}
[Conditional("DEVELOPMENT_BUILD"), Conditional("UNITY_EDITOR")]
void DrawDefaultPipeline(ScriptableRenderContext context, Camera camera, CullingResults cullingResults)
{
if (errorMaterial == null)
{
Shader errorShader = Shader.Find("Hidden/InternalErrorShader");
errorMaterial = new Material(errorShader)
{
hideFlags = HideFlags.HideAndDontSave
};
}
ShaderTagId shaderTagId = new ShaderTagId("ForwardBase");

var drawSettings = new DrawingSettings(shaderTagId,sortingSetting);
drawSettings.SetShaderPassName(1, new ShaderTagId("PrepassBase"));
drawSettings.SetShaderPassName(2, new ShaderTagId("Always"));
drawSettings.SetShaderPassName(3, new ShaderTagId("Vertex"));
drawSettings.SetShaderPassName(4, new ShaderTagId("VertexLMRGBM"));
drawSettings.SetShaderPassName(5, new ShaderTagId("VertexLM"));
drawSettings.overrideMaterial = errorMaterial;
context.DrawRenderers(cullingResults, ref drawSettings, ref filterSetting);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

[CreateAssetMenu(menuName = "CustomRP/SPR1")]
public class SRP1Asset : RenderPipelineAsset
{
protected override RenderPipeline CreatePipeline()
{
return new SRP1(this);
}
}
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Shader "SRP1/Standard"{
Properties{
_Color1("Color", Color) = (1,1,1,1)
_MainTex("Main Tex", 2D) = "white" {}
}
SubShader{
// 如果想使用URP
//Tags { "RenderType" = "Opaque" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline"}

// LightMode 的设置导致了URP无法使用这个shader
Tags { "RenderType" = "Opaque" "LightMode" = "SRP1Shader" }
Pass{


HLSLPROGRAM
#pragma vertex RP1Vertex
#pragma fragment RP1Fragment
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"

CBUFFER_START(UnityPerMaterial)
float4 _Color1;
sampler2D _MainTex;
float4 _MainTex_ST;
CBUFFER_END

CBUFFER_START(UnityPerFrame)
float4x4 unity_MatrixVP;
CBUFFER_END

CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;
float4x4 unity_WorldToObject;
float4 unity_LODFade;
float4 unity_WorldTransformParams;
CBUFFER_END

struct Attributes {
float3 position : POSITION;
float4 texcoord : TEXCOORD0;
};
struct Varyings {
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
};
Varyings RP1Vertex(Attributes input) {
Varyings output;
float4 world_pos = mul(unity_ObjectToWorld,float4(input.position,1.0));
output.position = mul(unity_MatrixVP,world_pos);
output.uv = TRANSFORM_TEX(input.texcoord, _MainTex);
return output;
}
float4 RP1Fragment(Varyings input) :SV_TARGET {
float4 texColor = tex2D(_MainTex, input.uv);
return _Color1 * texColor;
//return float4(1.0,1.0,1.0,1.0);
}
ENDHLSL
}
}
//FallBack "Diffuse"
//FallBack "Hidden/Universal Render Pipeline/FallbackError"

}

SRP和URP、HDRP的关系

  • URP和HDRP是基于SRP实现的
  • 相当于是unity根据游戏类型的需要,针对性的做出来两套可编程渲染管线。
  • 有利于对于渲染不熟悉的开发者使用SRP,上面说了很多SRP功能。其中batch非常强大,但是传统的技术实现起来比较难。

引用

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×