原文链接
作者:洪智
链接:www.jianshu.com/p/3fef69e2e…
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
正文
本文基于 Unity2020.2,URP10,更新于 20210303
本文初版内容翻译自:From Built-in to URP
译者:大智
后续补充:大智
内置管线 Shader 升级到 URP 详细手册
总体结构
1、在 SubShader 的 Tags 中添加 "RenderPipeline" = "UniversalPipeline"
2、所有 URP 着色器都是 HLSL 编写的,使用宏 HLSL 包含的 shader 代码
3、使用 HLSLINCLUDE 替代 CGINCLUDE
| 内置管线 | URP |
|---|---|
| CGPROGRAM HLSLPROGRAM | HLSL程序 |
| ENDCG ENDHLSL | ENDHLSL |
| CGINCLUDE HLSLINCLUDE | HLSLINCLUDE |
Include文件
| 内容 | 内置管线 | URP |
|---|---|---|
| Core | UnityCG.cginc | Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl |
| Light | AutoLight.cginc | Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl |
| Shadow | AutoLight.cginc | Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl |
| 表面着色器 | Lighting.cginc | URP 内没有,可以参考项目:在此处 |
| 其他有用的包括: |
- Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl
- Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl
- Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl
- Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl
- Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl
- Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl
- Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareOpaqueTextue.hlsl
灯光模式 LightMode
| 内置管线 | URP |
|---|---|
| ForwardBase | UniversalForward |
| ForwardAdd | 移除 |
| Deferred 以及相关 | 尚未支持 |
| Vertex 及相关 | 移除 |
| ShadowCaster | ShadowCaster |
| MotionVectors | 尚未支持 |
支持的其他照明模式包括:
- DepthOnly
- Meta (for lightmap baking)
- Universal2D
变体 Variants
URP 支持某些变体,因此,根据你使用的功能,可能需要使用 #pragma multi_compile 添加一些关键字:
_MAIN_LIGHT_SHADOWS_MAIN_LIGHT_SHADOWS_CASCADE_ADDITIONAL_LIGHTS_VERTEX_ADDITIONAL_LIGHTS_ADDITIONAL_LIGHT_SHADOWS_SHADOWS_SOFT_MIXED_LIGHTING_SUBTRACTIVE
预定义的着色器宏
辅助宏
| 内置管线 | URP |
|---|---|
| UNITY_PROJ_COORD(a) | 移除了,使用 a.xy / a.w 代替 |
| UNITY_INITIALIZE_OUTPUT(type,name) | ZERO_INITIALIZE(type,name) |
阴影贴图
必须 include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”
| 内置管线 | URP |
|---|---|
| UNITY_DECLARE_SHADOWMAP(tex) | TEXTURE2D_SHADOW_PARAM(textureName,samplerName) |
| UNITY_SAMPLE_SHADOW(tex,uv) | SAMPLE_TEXTURE2D_SHADOW(textureName,samplerName,coord3) |
| UNITY_SAMPLE_SHADOW_PROJ(tex,uv) | SAMPLE_TEXTURE2D_SHADOW(textureName,samplerName,coord4.xyz/coord4.w) |
纹理/采样器声明宏
Unity 有很多纹理/采样器宏来改善 API 之间的交叉兼容性,但是人们并不习惯使用它们。URP 中这些宏的名称有所变化。由于数量很多,全部的宏可以在 API includes中查看,下面主要列举一些常用的:
| 内置管线 | URP |
|---|---|
| UNITY_DECLARE_TEX2D(name) | TEXTURE2D(textureName); SAMPLER(samplerName); |
| UNITY_DECLARE_TEX2D_NOSAMPLER(name) | TEXTURE2D(textureName); |
| UNITY_DECLARE_TEX2DARRAY(name) | TEXTURE2D_ARRAY(textureName); SAMPLER(samplerName); |
| UNITY_SAMPLE_TEX2D(name,uv) | SAMPLE_TEXTURE2D(textureName,samplerName,coord2) |
| UNITY_SAMPLE_TEX2D_SAMPLER(name,samplername,uv) | SAMPLE_TEXTURE2D(textureName,samplerName,coord2) |
| UNITY_SAMPLE_TEX2DARRAY(name,uv) | SAMPLE_TEXTURE2D_ARRAY(textureName,samplerName,coord2,index) |
| UNITY_SAMPLE_TEX2DARRAY_LOD(name,uv,lod) | SAMPLE_TEXTURE2D_ARRAY_LOD(textureName,samplerName,coord2,index,lod) |
需要注意 SCREENSPACE_TEXTURE 变成了 TEXTURE2D_X。如果你想要在 VR 中(Single Pass Instanced 或 Multi-view 模式)制作屏幕效果,你必须使用 TEXTURE2D_X 定义纹理。这个宏会为你处理正确的纹理声明(是否为数组)。对这个纹理采样的时候必须使用 SAMPLE_TEXTURE2D_X,并且对 uv 使用 UnityStereoTransformScreenSpaceTex。
Shader 辅助函数
下列函数可以在此文件中找到:“Packages/com.unity.render-pipelines.core/ShaderLibrary/SpaceTransforms.hlsl”.
顶点转换函数
| 内置管线 | URP |
|---|---|
| float4 UnityObjectToClipPos(float3 pos) | float4 TransformObjectToHClip(float3 positionOS) |
| float3 UnityObjectToViewPos(float3 pos) | TransformWorldToView(TransformObjectToWorld(positionOS)) |
法线转换函数
| 内置管线 | URP |
|---|---|
| float4 UnityObjectToWorldNormal(float3 pos) | float4 TransformObjectToWorldNormal(float3 normalOS) |
通用辅助函数
| 内置管线 | URP | |
|---|---|---|
| float3 UnityWorldSpaceViewDir(float4 v) | GetCameraPositionWS() - i.worldPos | |
| float3 UnityObjectToWorldDir(float4 v) | TransformObjectToWorldDir(real3 dirOS) | |
| float3 ObjSpaceViewDir(float4 v) | 移除了,可以使用TransformWorldToObject(GetCameraPositionWS()) - objectSpacePosition ; | |
| float2 ParallaxOffset(half h,half height,half3 viewDir) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| fixed Luminance(fixed3 c) | real Luminance(real3 linearRgb) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl” |
| fixed3 DecodeLightmap(fixed4 color) | real3 DecodeLightmap(real4 encodedIlluminance, real4 decodeInstructions) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/EntityLighting.hlsl” URP 中的 decodeInstructions 是 half4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h) |
| float4 EncodeFloatRGBA(float v) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| float DecodeFloatRGBA(float4 enc) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| float2 EncodeFloatRG(float v) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| float DecodeFloatRG(float2 enc) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| float2 EncodeViewNormalStereo(float3 n) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| float3 DecodeViewNormalStereo(float4 enc4) | 移除了。可以从 UnityCG.cginc 复制过来 | |
| TANGENT_SPACE_ROTATION |
前向渲染辅助函数
| 内置管线 | URP | |
|---|---|---|
| float3 UnityWorldSpaceLightDir(float4 v) | _MainLightPosition.xyz - TransformObjectToWorld(objectSpacePosition) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
| float3 ObjSpaceLightDir(float4 v) | TransformWorldToObject( _MainLightPosition.xyz)-objectSpacePosition | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
| float3 Shade4PointLights(…) | 可以使用 half3 VertexLighting(float3 positionWS, half3 normalWS) | 对于 VertexLighting(...) include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
屏幕空间辅助函数
| 内置管线 | URP | |
|---|---|---|
| float4 ComputeScreenPos(float4 clipPos) | float4 ComputeScreenPos(float4 positionCS) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl” |
| float4 ComputeGrabScreenPos(float4 clipPos) | 移除了 |
顶点照明辅助函数↑
| 内置管线 | URP | |
|---|---|---|
| float3 ShadeVertexLights (float4 vertex, float3 normal) | 移除了,可以尝试使用UNITY_LIGHTMODEL_AMBIENT.xyz + VertexLighting(...) | 对于VertexLighting(...) include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
可以在“Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl”中找到很多工具函数。
内置着色器变量
除了光照相关的变量外,其他的变量名都基本没变
照明↑
| 内置管线 | URP | |
|---|---|---|
| _LightColor0 | _MainLightColor | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
| _WorldSpaceLightPos0 | _MainLightPosition | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl” |
| _LightMatrix0 | 移除了。目前尚不支持 Cookie | |
| unity_4LightPosX0,unity_4LightPosY0,unity_4LightPosZ0 | 在 URP 中,其他光源存储在数组/缓冲区中(取决于平台)。使用Light GetAdditionalLight(uint i, float3 positionWS)获取额外光源信息 | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
| unity_4LightAtten0 | 在 URP 中,其他光源存储在数组/缓冲区中(取决于平台)。使用Light GetAdditionalLight(uint i, float3 positionWS)获取额外光源信息 | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
| unity_LightColor | 在 URP 中,其他光源存储在数组/缓冲区中(取决于平台)。使用Light GetAdditionalLight(uint i, float3 positionWS)获取额外光源信息 | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
| unity_WorldToShadow | float4x4 _MainLightWorldToShadow[MAX_SHADOW_CASCADES + 1] 或者_AdditionalLightsWorldToShadow[MAX_VISIBLE_LIGHTS] | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl” |
如果要使用循环所有其他灯光 GetAdditionalLight(...),GetAdditionalLightsCount() 可以使用来查询其他灯光计数。
其他
阴影
有关阴影的更多信息,“Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl”
| 内置管线 | URP | |
|---|---|---|
| UNITY_SHADOW_COORDS(x) | 移除了。DIY,例如float4 shadowCoord : TEXCOORD0; | |
| TRANSFER_SHADOW(a) | a.shadowCoord = TransformWorldToShadowCoord(worldSpacePosition) | 启用 cascades 时,对片段执行此操作以避免视觉鬼影 |
| SHADOWS_SCREEN | 移除了。不支持。 |
雾
有关雾的更多信息,“Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl”.
| 内置管线 | URP |
|---|---|
| UNITY_FOG_COORDS(x) | 移除了。DIY,例如float fogCoord : TEXCOORD0; |
| UNITY_TRANSFER_FOG(o*,outpos) | o.fogCoord = ComputeFogFactor(clipSpacePosition.z); |
| UNITY_APPLY_FOG(coord,col) | color = MixFog(color,i.fogCoord); |
深度
要使用相机深度纹理,需要 include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl” ,然后会自动声明 _CameraDepthTexture,也会包含辅助函数 SampleSceneDepth(...) 和 LoadSceneDepth(...)。
| 内置管线 | URP | |
|---|---|---|
| LinearEyeDepth(sceneZ) | LinearEyeDepth(sceneZ, _ZBufferParams) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl” |
| Linear01Depth(sceneZ) | Linear01Depth(sceneZ, _ZBufferParams) | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl” |
其他中的其他
| 内置管线 | URP | |
|---|---|---|
| ShadeSH9(normal) | SampleSH(normal) | Include “Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl” |
| unity_ColorSpaceLuminance | 移除了。使用 Luminance() | Include “Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl” |
后处理/视觉特效
URP 不支持OnPreCull,OnPreRender,OnPostRender 和 OnRenderImage 这些方法。URP 支持OnRenderObject 和 OnWillRenderObject,但是如果在 URP 中使用你可能会发现问题。因此,如果你曾经在旧管线创建视觉效果时使用它们,那么现在你需要学习新方法了。URP包含以下注入点:
beginCameraRendering(ScriptableRenderContext context, Camera camera)endCameraRendering(ScriptableRenderContext context, Camera camera)beginFrameRendering(ScriptableRenderContext context,Camera[] cameras)endFrameRendering(ScriptableRenderContext context,Camera[] cameras)
用法示例:
**
void OnEnable()
{
RenderPipelineManager.beginCameraRendering += MyCameraRendering;
}
void OnDisable()
{
RenderPipelineManager.beginCameraRendering -= MyCameraRendering;
}
void MyCameraRendering(ScriptableRenderContext context, Camera camera)
{
...
if(camera == myEffectCamera)
{
...
}
...
}
就像我说的那样,OnWillRenderObject 是受支持的,但是,如果你需要在其中执行渲染调用(例如,水反射/折射),它将无法正常工作。调用 Camera.Render(),你将看到以下消息:
Recursive rendering is not supported in SRP (are you calling Camera.Render from within a render pipeline?)
翻译过来就是:
SRP 不支持递归渲染(你是从渲染管道中调用 Camera.Render 吗?)
在这种情况下,URP 中应该将 OnWillRenderObject 替换为 begin/endCameraRendering(如上面的例子),并调用 RenderSingleCamera(),而不是 Camera.Render()。更改上面的示例,你将获得以下内容
**
void MyCameraRendering(ScriptableRenderContext context, Camera camera)
{
...
if(camera == myEffectCamera)
{
...
UniversalRenderPipeline.RenderSingleCamera(context, camera);
}
...
}
使用后处理的另一种方法是使用 ScriptableRendererFeature。这篇文章很好地解释了使用 RenderFeature 的描边效果。ScriptableRendererFeature 可以让你将 ScriptableRenderPass(es) 注入到渲染管线的不同阶段,因此是创建后处理效果的强大工具。注入位置可以包含以下:
BeforeRenderingBeforeRenderingShadowsAfterRenderingShadowsBeforeRenderingPrepassesAfterRenderingPrePassesBeforeRenderingOpaquesAfterRenderingOpaquesBeforeRenderingSkyboxAfterRenderingSkyboxBeforeRenderingTransparentsAfterRenderingTransparentsBeforeRenderingPostProcessingAfterRenderingPostProcessingAfterRendering
这是 ScriptableRendererFeature 使用自定义材质执行 Blit 的简单示例:
**
public class CustomRenderPassFeature : ScriptableRendererFeature
{
class CustomRenderPass : ScriptableRenderPass
{
CustomRPSettings _CustomRPSettings;
RenderTargetHandle _TemporaryColorTexture;
private RenderTargetIdentifier _Source;
private RenderTargetHandle _Destination;
public CustomRenderPass(CustomRPSettings settings)
{
_CustomRPSettings = settings;
}
public void Setup(RenderTargetIdentifier source, RenderTargetHandle destination)
{
_Source = source;
_Destination = destination;
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
_TemporaryColorTexture.Init("_TemporaryColorTexture");
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get("My Pass");
if (_Destination == RenderTargetHandle.CameraTarget)
{
cmd.GetTemporaryRT(_TemporaryColorTexture.id, renderingData.cameraData.cameraTargetDescriptor, FilterMode.Point);
cmd.Blit(_Source, _TemporaryColorTexture.Identifier());
cmd.Blit(_TemporaryColorTexture.Identifier(), _Source, _CustomRPSettings.m_Material);
}
else
{
cmd.Blit(_Source, _Destination.Identifier(), _CustomRPSettings.m_Material, 0);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public override void FrameCleanup(CommandBuffer cmd)
{
if (_Destination == RenderTargetHandle.CameraTarget)
{
cmd.ReleaseTemporaryRT(_TemporaryColorTexture.id);
}
}
}
[System.Serializable]
public class CustomRPSettings
{
public Material m_Material;
}
public CustomRPSettings m_CustomRPSettings = new CustomRPSettings();
CustomRenderPass _ScriptablePass;
public override void Create()
{
_ScriptablePass = new CustomRenderPass(m_CustomRPSettings);
_ScriptablePass.renderPassEvent = RenderPassEvent.AfterRenderingOpaques;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
_ScriptablePass.Setup(renderer.cameraColorTarget, RenderTargetHandle.CameraTarget);
renderer.EnqueuePass(_ScriptablePass);
}
}
你可以通过单击 “Create > Rendering > Universal Render Pipeline > Renderer Feature” 来创建一个 ScriptableRendererFeature。你创建的功能必须添加到你的中 ForwardRenderer。为此,选择 ForwardRenderer,单击 Add Renderer Feature,然后选择要添加的功能。你可以在 Inspector 中公开属性,例如上面的例子中包含了一个材质球属性。