builtIn 转 URP 实操记录

builtIn 转 URP 实操记录

先贴下官方的介绍

( Universal Render Pipeline overview )

官方的文档讲的内容在完整上来说是最全的,但是细节的东西还是得自己看看。网上也有不是其他的帖子,和教程可以结合看看

( Unity C# and Shader Tutorials )

Catlike Coding 的教程应该是最仔细的(不过版本可能比较旧),毕竟到处都是翻译这里的。

一开始没有仔细看过文档,一路踩坑,记录一下。


builtIn 转URP 需要处理的内容

这里列举三个方面:shader、后处理、相机

一、shader

旧的builtIn 需要替换成 URP 的 hlsl 对应的函数,网上也有很多帖子了

( 周陶生:从 Builtin 管线升级到 URP )

具体的内容还需要看自己的项目,有些函数不清楚的就只能自己去翻源码看看。


(1)shader代码修改

之前写了个粗糙的转换工具,参考 shaderToy 的工具,用正则表达替换对应的函数。

比如:

private static void BaseReplace(ref string shaderStr, string pattern, string replacement)
     shaderStr = Regex.Replace(shaderStr, pattern, replacement);
// 雾效
private static void ReplaceFog(ref string oldShaderStr)
   BaseReplace(ref oldShaderStr, @"UNITY_FOG_COORDS\(([^(,]+?)\)", "float fogCoord : TEXCOORD$1;");
   BaseReplace(ref oldShaderStr, @"UNITY_TRANSFER_FOG\(([^,]+?)\,([^,]+?)\)", "$1.fogCoord = ComputeFogFactor($2.z)");
   BaseReplace(ref oldShaderStr, @"UNITY_APPLY_FOG_COLOR\(\s?(?=.)([^,]+?)\,\s?([^,]+?)\,\s?([^,].*?)\);", "$2.rgb = MixFog($2.rgb,$1); //$3 ");
   BaseReplace(ref oldShaderStr, @"UNITY_APPLY_FOG\(\s?(?=.)([^,]+?)\,\s?([^,]+?)\);", "$2.rgb = MixFog($2.rgb,$1);");
 private static void ReplaceSampler2D(ref string oldShaderStr)
    BaseReplace(ref oldShaderStr, @"(sampler2D|sampler2D_float|uniform sampler2D|uniform sampler2D_float)\s?(.*);", "TEXTURE2D ($2);SAMPLER(sampler$2);");
 private static void ReplaceText2D(ref string oldShaderStr)
    BaseReplace(ref oldShaderStr, @"tex2D\s?\(([^,]+?)\,([^,]+?)\)", "SAMPLE_TEXTURE2D($1,sampler$1,$2)");
    BaseReplace(ref oldShaderStr, @"tex2Dlod\s?\(([^,]+?)\,([^,].*?)\);", "SAMPLE_TEXTURE2D_LOD($1,sampler$1,$2);");
    //BaseReplace(ref oldShaderStr, @"UNITY_SAMPLE_TEX2D\s?\?(([^,]+?)\,([^,]+?)\)", "SAMPLE_TEXTURE2D($1,sampler$1,$2)");
}


(2)SRPBatch

SRPBatch 的开启和使用,主要是多pass的合批

比如:

这三个正方形,用的是双pass,同一个sahder,不同材质球。按照 SRPBatch 来说,应该要合成一个才对。

这里需要解决两个问题,一个是 CBUFF、一个是LightMode

1、多pass的情况,将面板自定义的参数都写一个CBUFF 下

SubShader
    ......
    HLSLINCLUDE
    #include ......
    CBUFFER_START(UnityPerMaterial)
    ......
    CBUFFER_END
    ENDHLSL
    pass{...}
    pass{...}
}

使用 HLSLINCLUDE...ENDHLSL 写在 SubShader中,就不需要每个pass添加了。加完后会在shader面板上发现已经能合批了

但是,在 Frame Debug 面板上发现还是因为多pass导致无法合批。这里就涉及第二个问题

2、LightMode

在使用URP shader的时候,使用光照的pass会添加

    Tags { "LightMode" = "UniversalForward" } 

在额外的pass 添加

    Tags { "LightMode" = "SRPDefaultUnlit" } 

SRPDefaultUnlit 和 UniversalForward 是在同一个渲染队列的,所以会导致合批失败。正确的做法是自己定义一个 LightMode

在创建 URP 管线的 PipelineAsset_Renderer 添加 Renderer Feature 添加 Render Object

添加名字,作用的Layer Mask 等

然后将多pass 中的 LightMode 替换成自定义的 customModel

    Tags { "LightMode" = "customModel" } 

这时候再看 Frame Debug ,就会发现合批成功了。


(3)c# 部分的渲染代码

commandBuff 以及部分的 OnPreCull, OnPreRender, OnPostRender和 OnRenderImage 些个函数

这部分还是不太懂,后续再学习下。

OnRenderImage 等替换成 OnRenderObject 等 函数,这个确实没有实际跑过,但是因为项目的部分shader在这个函数后会有不正常的显示,加上中台TA问我,确定这个能用吗?也让我一度怀疑是不能用。不过没有花时间验证,还是得再深入学习。略过这部分先了。


二、后处理

PostProcessing-v2 是 unity builtIn 下后处理的插件,在URP下不支持,需要使用URP的 Volume 。

但是在使用的过程中发现,原本只是相对场景做后处理的,结果 UI界面也被影响了,于是这里引申出相机的修改


三、相机

URP 下的相机和 builtIn 下的不一样。具体的参数和设置可以去看下官方的文档。

这里说下 Render Type

Render Type 包括 Base 和 Overlay

场景中需要至少一个Base 类型的相机,为了解决后处理对UI的影响,渲染UI的camera需要将类型设置为 Overlay,并在 Base 类型的camera中添加进队列中

比如:

Camera sceneCamera = Camera.main;
Camera uiCamera = GameObject.Find("UICamera").GetComponent<Camera>();
var cameraData = sceneCamera.GetUniversalAdditionalCameraData();
cameraData.cameraStack.Add(uiCamera);

打开 GetUniversalAdditionalCameraData 会发现,cameraData 在相机初始化的时候不一定有,需要add,这里感觉会有坑。因为切到URP下,在相机上看应该说是默认挂了脚本的。

public static UniversalAdditionalCameraData GetUniversalAdditionalCameraData(this Camera camera)
    var gameObject = camera.gameObject;