docs.unity3d.com
    显示 / 隐藏目录

    自定义后期处理

    高清渲染管线 (High Definition Render Pipeline, HDRP) 允许您编写自己的后期处理效果,这些效果会自动集成到体积中。自定义效果需要两个文件。一个是 C# 自定义后期处理(C# 文件),另一个是关联的全屏着色器(HLSL 文件)。您可以为每个文件生成一个模板:

    • C# 自定义后期处理:在 Assets 文件夹中右键单击,然后选择 Create > Rendering > C# Post Process Volume。

    • 全屏着色器:在 Assets 文件夹中右键单击,然后选择 Create > Shader > HDRP > Post Process。

    请注意,默认情况下,如果只是将自定义效果添加到体积中,则自定义效果不会运行。还需要将效果添加到项目的支持效果列表中。(与用于效果排序的列表相同,请参阅“效果排序”部分)。

    示例

    本示例说明如何创建灰度效果。要开始这一过程,请执行以下操作:

    1. 创建一个 C# 自定义后期处理文件(在 Assets 文件夹中右键单击,然后选择 Create > Rendering > C# Post Process Volume),并将其命名为 GrayScale。请注意,由于序列化在 Unity 中的工作方式,因此文件名和类名必须相同,否则 Unity 不能正确地对其进行序列化。

    2. 将示例代码从 GrayScale C# 脚本部分复制到 C# Post Process Volume 中。

    3. 创建一个全屏后期处理着色器(在 Assets 文件夹中右键单击,然后选择 Create > Shader > HDRP > Post Process),并将其命名为 GrayScale。

    4. 将示例代码从 GrayScale Shader 部分复制到您的后期处理着色器中。

    5. 将 GrayScale 效果添加到您的项目执行的自定义后期处理列表中。为此,请选择 Edit > Project Settings > HDRP Default Settings,然后在 After Post Process 列表的底部,单击 +,再选择 GrayScale。

    6. 现在可以向场景中的 Volumes 添加 GrayScale 后期处理覆盖。要更改效果设置,请单击折叠箭头下方的小号 all 文本,然后使用 Intensity 滑动条进行调整。

    7. (可选)可为后期处理效果创建自定义编辑器。有关如何执行此操作的信息,请参阅自定义编辑器。

    GrayScale C# 脚本

    以下是 C# 自定义后期处理文件。自定义后期处理效果将配置数据和逻辑存储在同一个类中。要创建效果的设置,可以使用从 VolumeParameter 继承的预先存在的类,或者如果要使用预先存在的类不包含的属性,则可以创建一个从 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 允许您在每个注入点自定义您的自定义后期处理效果的顺序。要对效果排序,请执行以下操作:

    1. 选择 Edit > Project Settings,然后选择 HDRP Default Settings 选项卡。

    2. 向下滚动,直到找到 Custom Post Process Orders 部分。此部分包含三个列表,每个注入点一个。

    3. 将自定义效果添加到这些列表中,以便 HDRP 可以渲染这些自定义效果。

    HDRP 按照从列表自上而下处理效果,每个列表的执行顺序为:

    1. 透明前。

    2. 后期处理前。

    3. 后期处理后。

    自定义编辑器

    默认情况下,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。

    • 在包含后期处理的体积中,确保其具有足够高的优先级,并且您的摄像机在其边界范围内。

    返回到顶部
    Copyright © 2023 Unity Technologies — 商标和使用条款
    • 法律条款
    • 隐私政策
    • Cookie
    • 不要出售或分享我的个人信息
    • Your Privacy Choices (Cookie Settings)