自定义后期处理
高清渲染管线 (High Definition Render Pipeline, HDRP) 允许您编写自己的后期处理效果,这些效果会自动集成到体积中。自定义效果需要两个文件。一个是 C# 自定义后期处理(C# 文件),另一个是关联的全屏着色器(HLSL 文件)。您可以为每个文件生成一个模板:
C# 自定义后期处理:在 Assets 文件夹中右键单击,然后选择 Create > Rendering > C# Post Process Volume。
全屏着色器:在 Assets 文件夹中右键单击,然后选择 Create > Shader > HDRP > Post Process。
请注意,默认情况下,如果只是将自定义效果添加到体积中,则自定义效果不会运行。还需要将效果添加到项目的支持效果列表中。(与用于效果排序的列表相同,请参阅“效果排序”部分)。
示例
本示例说明如何创建灰度效果。要开始这一过程,请执行以下操作:
创建一个 C# 自定义后期处理文件(在 Assets 文件夹中右键单击,然后选择 Create > Rendering > C# Post Process Volume),并将其命名为 GrayScale。请注意,由于序列化在 Unity 中的工作方式,因此文件名和类名必须相同,否则 Unity 不能正确地对其进行序列化。
将示例代码从 GrayScale C# 脚本部分复制到 C# Post Process Volume 中。
创建一个全屏后期处理着色器(在 Assets 文件夹中右键单击,然后选择 Create > Shader > HDRP > Post Process),并将其命名为 GrayScale。
将示例代码从 GrayScale Shader 部分复制到您的后期处理着色器中。
将 GrayScale 效果添加到您的项目执行的自定义后期处理列表中。为此,请选择 Edit > Project Settings > HDRP Default Settings,然后在 After Post Process 列表的底部,单击 +,再选择 GrayScale。
现在可以向场景中的 Volumes 添加 GrayScale 后期处理覆盖。要更改效果设置,请单击折叠箭头下方的小号
all
文本,然后使用 Intensity 滑动条进行调整。(可选)可为后期处理效果创建自定义编辑器。有关如何执行此操作的信息,请参阅自定义编辑器。
GrayScale C# 脚本
以下是 C# 自定义后期处理文件。自定义后期处理效果将配置数据和逻辑存储在同一个类中。要创建效果的设置,可以使用从 VolumeParameter
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using System;
[Serializable, VolumeComponentMenu("Post-processing/Custom/GrayScale")]
public sealed class GrayScale : CustomPostProcessVolumeComponent, IPostProcessComponent
{
[Tooltip("Controls the intensity of the effect.")]
public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
Material m_Material;
public bool IsActive() => m_Material != null && intensity.value > 0f;
public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.AfterPostProcess;
public override void Setup()
{
if (Shader.Find("Hidden/Shader/GrayScale") != null)
m_Material = new Material(Shader.Find("Hidden/Shader/GrayScale"));
}
public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
{
if (m_Material == null)
return;
m_Material.SetFloat("_Intensity", intensity.value);
m_Material.SetTexture("_InputTexture", source);
HDUtils.DrawFullScreen(cmd, m_Material, destination);
}
public override void Cleanup() => CoreUtils.Destroy(m_Material);
}
首先,该示例代码使用 ClampedFloatParameter,您可能不熟悉这个类型。这种类型是浮点数,您可以将其限制为某一范围。在构造函数中:
第一个参数是属性的默认值。
第二个参数表示将属性限制到的最小值。
第三个参数表示将属性限制到的最大值。
接下来是一个 IsActive() 函数。HDRP 在 Render 函数之前调用此函数,以确保能够处理效果。如果此函数返回 false
,则 HDRP 不会处理该效果。最佳做法是检查发生了效果损坏或无效情况的每个属性配置。在此示例中,IsActive() 确保了可以找到 GrayScale.shader 并且强度大于 0。
借助 injectionPoint 覆盖,可以指定 HDRP 在管线中的何处执行效果。当前有三个注入点:
AfterOpaqueAndSky。
BeforePostProcess。
AfterPostProcess。
有关 HDRP 在何处注入自定义后期处理通道的更多详细信息,请参阅下图:
现在已经有了 Setup、Render 和 Cleanup 函数。这些函数在这里分别用于分配、使用和释放效果所需的资源。该示例使用的唯一资源是单个材质。该示例在 Setup 中创建材质,然后在 Cleanup 中使用 CoreUtils.Destroy() 来释放材质。在 Render 函数中,您可以访问 CommandBuffer,因此可以将任务加入队列中以供 HDRP 执行。此处可以使用 HDUtils.DrawFullScreen 来渲染全屏四边形。它使用 CommandBuffer 以及您传入的材质,然后将结果 bilt 到目标 RTHandle。
GrayScale 着色器
HDRP 使您能够完全控制顶点和片元着色器,因此您可以编辑它们以适合您的需求。请注意,着色器默认包含的 Common.hlsl 和 Color.hlsl 中有很多实用函数。这意味着您可以在您的效果中访问这些实用函数。例如,GrayScale 着色器使用 Luminance() 函数将线性 RGB 值转换为等效的亮度。
Shader "Hidden/Shader/GrayScale"
{
HLSLINCLUDE
#pragma target 4.5
#pragma only_renderers d3d11 ps4 xboxone vulkan metal switch
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
struct Attributes
{
uint vertexID : SV_VertexID;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};
Varyings Vert(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
return output;
}
// 用于控制后期处理效果的属性列表
float _Intensity;
TEXTURE2D_X(_InputTexture);
float4 CustomPostProcess(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
uint2 positionSS = input.texcoord * _ScreenSize.xy;
float3 outColor = LOAD_TEXTURE2D_X(_InputTexture, positionSS).xyz;
return float4(lerp(outColor, Luminance(outColor).xxx, _Intensity), 1);
}
ENDHLSL
SubShader
{
Pass
{
Name "GrayScale"
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment CustomPostProcess
#pragma vertex Vert
ENDHLSL
}
}
Fallback Off
}
如果您的所有场景均未引用着色器,则 Unity 不会构建着色器,并且当您在编辑器外部运行应用程序时,效果不起作用。要解决此问题,请将着色器添加到 Resources 文件夹,或者选择 Edit > Project Settings > Graphics,然后将着色器添加到 Always Included Shaders 列表。
请注意,如果在着色器中使用 clip() 指令,将破坏效果。
着色器输入
默认情况下,着色器模板为您提供以下输入:
输入 | 描述 |
---|---|
positionCS | 像素的裁剪空间位置。此值介于 0 和当前屏幕大小之间。 |
texcoord | 全屏 UV 坐标。此值介于 0 到 1 之间。 |
_InputTexture | 源纹理。GrayScale C# 脚本将此项传递给着色器。 |
_Intensity | 效果的强度。GrayScale C# 脚本将此项传递给着色器。 |
效果排序
HDRP 允许您在每个注入点自定义您的自定义后期处理效果的顺序。要对效果排序,请执行以下操作:
选择 Edit > Project Settings,然后选择 HDRP Default Settings 选项卡。
向下滚动,直到找到 Custom Post Process Orders 部分。此部分包含三个列表,每个注入点一个。
将自定义效果添加到这些列表中,以便 HDRP 可以渲染这些自定义效果。
HDRP 按照从列表自上而下处理效果,每个列表的执行顺序为:
透明前。
后期处理前。
后期处理后。
自定义编辑器
默认情况下,Unity 自动为类创建一个编辑器,但是,如果您想以更大力度控制 Unity 如何显示某些属性,则可以创建一个自定义编辑器。如果您确实创建了自定义编辑器脚本,请务必将该脚本放在名为 Editor 的文件夹中。
以下是 GrayScale 效果的自定义编辑器示例:
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEditor;
[VolumeComponentEditor(typeof(GrayScale))]
sealed class GrayScaleEditor : VolumeComponentEditor
{
SerializedDataParameter m_Intensity;
public override bool hasAdvancedMode => false;
public override void OnEnable()
{
base.OnEnable();
var o = new PropertyFetcher<GrayScale>(serializedObject);
m_Intensity = Unpack(o.Find(x => x.intensity));
}
public override void OnInspectorGUI()
{
PropertyField(m_Intensity);
}
}
这个自定义编辑器并不是真正有用,因为它生成的结果与 Unity 创建的编辑器生成的结果相同。自定义体积组件编辑器还支持“更多选项”按钮。要添加此按钮,必须将 hasAdvancedMode 覆盖设置为 true。然后,在 OnInspectorGUI 内部,您可以使用 isInAdvancedMode 布尔值显示更多属性。
故障排除
如果您的效果无法正确显示:
在项目设置 (Project Settings) 中,确保此效果列出在其中一个后期处理顺序列表中(请参阅效果排序)。
确认效果的着色器可以编译,并且对后期处理体积中材质的引用不为 null。
在包含后期处理的体积中,确保其具有足够高的优先级,并且您的摄像机在其边界范围内。