Technology Scriptable Rendering Pipeline - chaolunner/CloudNotes GitHub Wiki

渲染路径 Rendering Path

在SRP之前,Unity提供了ForwardDeferred两种主流的Render Path。实际开发中,使用Standard Shader基本可以满足大部分需求,也可以使用Custom Shader来对Standard Shader进行扩展。如果有定制的渲染需求,还可使用Command Buffer来扩展现有的管线。

大部分情况下,我们只能为项目选择一种渲染路径。Unity默认情况下是Forward Rendering Path。但是,可为多个摄像机配置不同的Rendering Path。

https://github.com/chaolunner/CloudNotes/wiki/Images/Technology/rendering-path.png

  • 前向渲染路径(Forward Rendering Path)

    https://github.com/chaolunner/CloudNotes/wiki/Images/Technology/forward-rendering.png

    上图只是大致的描述Forward的原理,在Unity中Lighting可以不在Fragment Shader阶段,这里不展开讨论。Forward Rendering中的Lighting和受光照影响的物体个数是成正比的,也就是受光照影响的物体*灯光数,一个物体受多个光影响的情况下,会多次计算光照从而得出最终颜色。

  • 延迟渲染路径(Deferred Rendering Path)

    https://github.com/chaolunner/CloudNotes/wiki/Images/Technology/deferred-rendering.png

    Deferred Rendering中Lighting与受光照影响的物体无关,只与最终屏幕大小相关,也就是 最终屏幕分辨率*灯光数。

    Deferred Rendering需要先将必要的信息渲染至Color Buffer,Depth Buffer,Normals Buffer,然后在最后执行Lighting。这要求显卡支持MRT(multiple render targets)。

    使用Deferred Rendering注意事项:

    • 要求显卡支持MRT,老旧的显卡可能不支持。会有兼容性问题。
    • 要求显卡高带宽,老旧显卡可能存在问题。会有兼容性问题。
    • 无法处理透明物体渲染(除非Forward和Deferred混合使用,使用Forward处理透明物体)。
    • 有些基于Deferred Rendering的引擎无法支持抗锯齿,但其实可通过Edge detection(边缘检测)或FXAA(Fast Approximate Anti-Aliasing 快速近似抗锯齿)来处理。
    • 只支持单材质,除非使用Deferred Lighting。

可编程管线 Scriptable Rendering Pipeline

Unity的SRP(Scriptable Render Pipeline)允许开发者使用C#控制Unity的渲染流程。在最新的Unity版本中还提供了两种渲染管线:

  • URP 通用渲染管线 针对移动和XR平台,基于Single-Pass Forward Rendering,一次渲染多个实时光。
  • HDRP 高清渲染管线,针对主机和PC平台,支持Forward Rendering 和 Deferred Rendering。
  • 自定义SRP 可实现自定义渲染管线。

Custom SRP(非常好的学习地方)

也可以参考我根据这一系列教程,编写的 Easy Render Pipeline

通用渲染管线

  • 光照

    • 实时光照
      • 按照每个物体进行光照剔除
      • 在一个批次进行渲染
      • 针对每个物体的限制:
        • 1盏主方向光
        • 4盏附加光(Point/Spot)
      • 每个相机中总共16盏可见光
    • 基于物理的光线衰减
      • 只受强度控制,不受范围影响
  • SRP Batcher

    • 对于不同材质但Shader相同的对象进行合批。利用CBuffer储存材质中的属性,避免每次渲染的时候创建,渲染的时候将不同材质的CBuffer一并提交GPU。
    • 运行时需要调用 GraphicsSettings.useScriptableRenderPipelineBatching = true;
  • Shaders stripping (先要了解一下 Shader Keywords

    • 基于URP的设置。比如:如果禁用Additional Lights,URP会从构建中删除所有相关的变体。

    • 剥离无效的变体组合。比如:已定义 _MAIN_LIGHT_SHADOWS_CASCADE 但是 _MAIN_LIGHT_SHADOWS无效,因此会被剥离。

    • 剥离未使用的Pass。如果您在配置中选择不支持阴影,则会从构建中剥离所有 Shadow caster pass。

    • Scriptable Shader Variants Stripping

      示例,可以剥离与DEBUG配置关联的所有着色器变体,这些变量由开发Player构建中使用的DEBUG关键字标识。

      using UnityEditor;
      using UnityEditor.Build;
      using UnityEditor.Rendering;
      using UnityEngine;
      using UnityEngine.Rendering;
      
      class ShaderDebugBuildProcessor : IPreprocessShaders
      {
      	ShaderKeyword m_KeywordDebug;
      
      	public ShaderDebugBuildProcessor()
      	{
      		m_KeywordDebug = new ShaderKeyword("DEBUG");
      	}
      
      	public int callbackOrder { get { return 0; } }
      
      	public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> shaderCompilerData)
      	{
      		// In development, don't strip debug variant
      		if (EditorUserBuildSetting.development) return;
      
      		for (int i = 0; i < shaderCompilerData.Count; ++i)
      		{
      			if (shaderCompilerData[i].shaderKeywordSet.IsEnabled(m_KeywordDebug))
      			{
      				shaderCompilerData[i].RemoveAt(i);
      				--i;
      			}
      		}
      	}
      }
      
  • Shader 模板 UniversalPipelineTemplateShader.shader

任意门 HDRP版

下面是原始版本的Shader,但是在HDRP中有色差,主要是Post Process(后期处理)导致的。

Shader "Unlit/ScreenCutoutShader"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
	}
	SubShader
	{
		Tags{ "Queue" = "Transparent" "IgnoreProjector" = "True" "RenderType" = "Transparent" }
		Lighting Off
		Cull Back
		ZWrite On
		ZTest Less
		
		Fog{ Mode Off }

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				//float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
				float4 screenPos : TEXCOORD1;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.screenPos = ComputeScreenPos(o.vertex);
				return o;
			}
			
			sampler2D _MainTex;

			fixed4 frag (v2f i) : SV_Target
			{
				i.screenPos /= i.screenPos.w;
				fixed4 col = tex2D(_MainTex, float2(i.screenPos.x, i.screenPos.y));
				
				return col;
			}
			ENDCG
		}
	}
}

所以我们需要让Shader在Post Process之后渲染。

HDRP的 Unlit Shader有一个 Rendering Pass 选项,通过选择 After post-process,可以解决这个问题。

因此我们可以右键创建 Create->Shader->HDRP->Unlit Graph

然后参考下面的图片设置:

https://github.com/chaolunner/CloudNotes/wiki/Images/Technology/hdrp-screen-cutout-shader.png

https://github.com/chaolunner/CloudNotes/wiki/Images/Technology/hdrp-screen-cutout-mat.png