builtIn 转 URP 实操记录
先贴下官方的介绍
( Universal Render Pipeline overview )
官方的文档讲的内容在完整上来说是最全的,但是细节的东西还是得自己看看。网上也有不是其他的帖子,和教程可以结合看看
( Unity C# and Shader Tutorials )
Catlike Coding 的教程应该是最仔细的(不过版本可能比较旧),毕竟到处都是翻译这里的。
一开始没有仔细看过文档,一路踩坑,记录一下。
builtIn 转URP 需要处理的内容
这里列举三个方面:shader、后处理、相机
一、shader
旧的builtIn 需要替换成 URP 的 hlsl 对应的函数,网上也有很多帖子了
具体的内容还需要看自己的项目,有些函数不清楚的就只能自己去翻源码看看。
(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;