未使用光照计算的shader升级后不做修改仍然可以使用,但是可能会不兼容SRP Batcher,所以仍然需要修改,使用了光照计算的shader必须要修改。
SubShader的Tags中增加 “RenderPipeline”="UniversalPipeline"声明
要保证多pass物体正确绘制,需要确保有个pass打上 UniversalForward
的tag,其余pass有 SRPDefaultUnlit
的tag也行,没有也行。
HLSLPROGRAM 替换 CGPROGRAM
HLSLINCLUDE 替换 INCLUDE
ENDHLSL 替换 ENDCG
fixed
替换为:half
或者 float
FallBack
FallBack “Hidden/Universal Render Pipeline/FallbackError”
LightMode
"LightMode" 要改为URP支持的模式, 比如
"LightMode" = "Forward"
替换为
"LightMode" = "UniversalForward"
其他常用URP的mode类型:
"LightMode" = "Universal2D"
"LightMode" = "Meta"
"LightMode" = "DepthOnly"
"LightMode" = "ShadowCaster"
使用URP ShaderLibrary引用Core.hlsl替换内置渲染管线中的UnityCG.cginc
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
替换
#include "UnityCG.cginc"
其他库类似:
#include "Lighting.HLSLinc"
替换为:
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitForwardPass.hlsl"
阴影:
#include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
内置结构体、内置函数 和矩阵
appdata_full 这种结构体不能用了,如何一一替换我就不举例了
内置函数 和矩阵需要查阅Packages/Universal RP/ShaderLibrary/UnityInput
内置结构体、函数需要查阅
Packages/Universal RP/ShaderLibrary/Input
Packages/Universal RP/ShaderLibrary/Core
使用 TransformObjectToHClip 替换 UnityObjectToClipPos
或者改成如下写法:
Varyings vert(Attributes IN) {
Varyings OUT;
VertexPositionInputs positionInputs = GetVertexPositionInputs(IN.positionOS.xyz);
OUT.positionCS = positionInputs.positionCS;
// Or this :
//OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
OUT.color = IN.color;
return OUT;
}
GetVertexPositionInputs 计算不同坐标系中的位置,结果包含世界坐标系坐标,观察坐标系坐标,裁剪坐标系坐标,标准设备坐标系坐标,未使用到的坐标不会被包含到编译出的shader中,所以不会有额外的不必要的计算量。TRANSFORM_TEX 在内置渲染管线和URP中都可以用。GetVertexNormalInputs 可以将法线和切线从对象坐标系变换到世界坐标系。也可以用 TransformObjectToWorldNormal(IN.normalOS) 代替。
VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
在URP中纹理和采样器的定义改成如下写法:
// 将_BaseMap声明为Texture2D对象
TEXTURE2D(_MainTex);
// 将_BaseMap声明为Texture2D对象
SAMPLER(sampler_MainTex);
float4 frag (v2f i) : SV_Target
{
float4 col = SAMPLE_TEXTURE2D(_BaseMap,sampler_BaseMap, i.texcoord);
return col;
}
区分 multi_compile 和 shader_feature,剥离不需要的编译选项,减少shader变体。
https://zhuanlan.zhihu.com/p/77043332
https://www.jianshu.com/p/8750704a2f4c
URP不支持表面着色器,URP ShaderLibrary 中处理光照计算的函数在 Lighting.hlsl中,该文件需要手动include。
//这些编译指令用于接收阴影
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _SHADOWS_SOFT
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
当使用Lighting.hlsl支持光照和阴影,应该添加下面的编译选项,如果没有定义,ShaderLibrary会跳过一些计算。
// Main Light Shadows
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
// Additional Lights & Shadows
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
// Soft Shadows
#pragma multi_compile _ _SHADOWS_SOFT
// Other (Mixed lighting, baked lightmaps, fog)
#pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile_fog
// Supporting shadows will also require passing a positionWS,
// and shadowCoord into the fragment shader, again you'll have
// to see the Lighting sections for actual examples.
为了处理雾,使用ComputeFogFactor 和 MixFog 函数。
#pragma multi_compile_fog
struct Varyings {
...
half fogFactor : TEXCOORD5;
// or whatever unused texcoord
// if none are unused pack it together with a half3 or something
}
...
// In the vertex shader :
half fogFactor = ComputeFogFactor(positionInputs.positionCS.z);
// In the fragment, just before returning the color :
color.rgb = MixFog(color.rgb, IN.fogFactor);
在URP中是使用的single-pass
前向渲染,也就是单Pass。
转URP的时候我们会发现 以前多Pass的shader会异常,只会渲染第一个Pass。
如果我们确实需要多Pass怎么办?
我们可以通过设置第一个Pass的LightMode为:UniversalForward
就行了。
例如:
Shader "lcl/Shader"
{
Properties
{
_Color("Color", Color) = (1,1,1,1)
_MainTex("Albedo", 2D) = "white" {
}
}
SubShader {
LOD 100
Lighting Off
Pass
{
Tags {
"LightMode"="UniversalForward"}
...
}
Pass {
Tags {
"LightMode"="SRPDefaultUnlit"}
...
}
}
但是不推荐多Pass渲染,因为会打断 SRP Batcher,使DrawCall增加。(当然 如果没使用SRP Batcher则不影响)
具体什么是SRP Batcher可以参考这里
https://zhuanlan.zhihu.com/p/165574008
https://zhuanlan.zhihu.com/p/165388825
·如果确实需要可以通过RendererFeatures
实现多Pass效果
Shader中所有的内置属性例如unity_ObjectToWorld
,unity_SHAr
等,都要在一个名为UnityPerDraw
的CBUFFER中声明;
所有的Material属性都要在一个名为UnityPerMaterial
的CBUFFER中声明。
CBUFFER_START(UnityPerMaterial)
//Properties
CBUFFER_END
CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;
CBUFFER_END
例如:
Properties
{
_Color1 ("Color 1", Color) = (1,1,1,1)
_Color2 ("Color 2", Color) = (1,1,1,1)
}
//原本的写法
//float4 _Color1;
//float4 _Color2;
//兼容SRP Batcher的写法
CBUFFER_START(UnityPerMaterial)
float4 _Color1;
float4 _Color2;
CBUFFER_END
CBUFFER_START(UnityPerDraw)
float4x4 unity_ObjectToWorld;
CBUFFER_END
如果shader报错:Shader error in ‘Unlit/SampleUnlit’: redefinition of ‘unity_ObjectToWorld’,重复定义,如果自己的shader代码里面没有,那么就是引入了其他的库文件里面包含了该变量。
最后,我们看Shader的面板,如果出现了类似的提示:
则表示 该属性 未包含在 CBUFFER_START(UnityPerMaterial) 里面。
注意:如果Shader使用了多Pass渲染,则会打断 SRP Batcher。
https://zhuanlan.zhihu.com/p/254810253
https://blog.csdn.net/wannaconquer/article/details/114092927