Post Processing Stack V2 安装和使用03

本文项目地址:https://e.coding.net/man_man/PostProcessStackExample.git

创建自定义特效

创建自定义特系需要两个文件:c# 和HLSL文件

HLSL文件会被编程成GLSL,Metal 和其他API所以不用担心平台限制。

我们来看一个c#代码例子:

using System;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;

[Serializable]
[PostProcess(typeof(GrayscaleRenderer), PostProcessEvent.AfterStack, "Custom/Grayscale")]
public sealed class Grayscale : PostProcessEffectSettings
{
    [Range(0f, 1f), Tooltip("Grayscale effect intensity.")]
    public FloatParameter blend = new FloatParameter { value = 0.5f };
}

public sealed class GrayscaleRenderer : PostProcessEffectRenderer<Grayscale>
{
    public override void Render(PostProcessRenderContext context)
    {
        var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Grayscale"));
        sheet.properties.SetFloat("_Blend", settings.blend);
        context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
    }
}

重要:这段代码必须存储在一个名为Grayscale.cs的文件中。因为在Unity中序列化的工作原理,你必须确保文件以你的设置类名称命名,否则无法正常序列化。

我们需要两个类,一个用来存储设置(数据),另一个用来处理渲染部分(逻辑)。

Settings

设置类保存了我们的效果数据。这些是你在Volumn inspector中看到的所有面向用户的字段。

[Serializable]
[PostProcess(typeof(GrayscaleRenderer), PostProcessEvent.AfterStack, "Custom/Grayscale")]
public sealed class Grayscale : PostProcessEffectSettings
{
    [Range(0f, 1f), Tooltip("Grayscale effect intensity.")]
    public FloatParameter blend = new FloatParameter { value = 0.5f };
}

首先,你需要确保这个类是扩展了PostProcessEffectSettings的类,并且可以被序列化,所以不要忘了[Serializable]属性!

其次,你需要告诉Unity这是一个持有后处理数据的类。这就是[PostProcess()]属性的作用。第一个参数是将设置链接到一个渲染器(下一节会有更多介绍)。第二个参数是效果的注入点。现在你有3个可用的参数:

  • BeforeTransparent:效果将只在 transparent pass 之前应用于不透明的对象。
  • BeforeStack:效果将在内置堆栈启动前应用。这包括抗锯齿、景深、色调映射等。
  • AfterStack:效果会在内置堆栈之后,在FXAA(如果启用了的话)和final-pass dithering之前应用。

对于参数本身,你可以使用任何你需要的类型,但如果你想让这些参数可以被覆盖,并且在卷中可以混合,你就必须使用boxed fields。在本例中,我们将简单地添加一个固定范围为01FloatParameter。 你可以通过浏览/PostProcessing/Runtime/中的ParameterOverride.cs源文件来获得完整的内置参数类列表,或者你也可以按照同样的源文件中的方法创建自己的参数类。

注意,你也可以重写PostProcessEffectSettings的IsEnabledAndSupported()方法来设置你自己对效果的要求(如果它需要特定的硬件),甚至可以在满足条件之前自动地禁用效果。例如,在我们的例子中,如果 blend 参数为 0,我们可以像这样自动禁用效果:

public override bool IsEnabledAndSupported(PostProcessRenderContext context)
{
    return enabled.value
        && blend.value > 0f;
}
That way the effect won't be executed at all unless blend > 0.


这样一来,除非 blend > 0,否则效果根本不会被执行。

Renderer

现在我们来看看渲染逻辑。我们的渲染器扩展了PostProcessEffectRendererT是附加到这个渲染器的设置类型。

public sealed class GrayscaleRenderer : PostProcessEffectRenderer<Grayscale>
{
    public override void Render(PostProcessRenderContext context)
    {
        var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Grayscale"));
        sheet.properties.SetFloat("_Blend", settings.blend);
        context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
    }
}

一切都在Render()方法中发生,该方法需要一个PostProcessRenderContext作为参数。这个上下文保存着你可以使用的有用数据,当效果被渲染时,会被传递给其他效果。请查看 /PostProcessing/Runtime/PostProcessRenderContext.cs 中的可用数据列表(该文件有大量注释)。

PostProcessEffectRenderer<T>还有一些其他的方法可以被覆盖,比如。

void Init():在创建渲染器时调用。
DepthTextureMode GetLegacyCameraFlags():用于设置摄像机标志,并请求深度贴图、运动向量等。
void ResetHistory():当 "重置历史 "事件被调度时调用。主要用于清除历史缓冲区之类的时间效果。
void Release():当渲染器被破坏时调用。如果你需要的话,在那里做清理工作。
我们的效果很简单。我们需要做两件事。

blend 参数值发送给着色器。
用我们的源图像作为输入,用着色器Blit一个全屏传递到目的地。

因为我们只使用command buffers,所以系统依赖MaterialPropertyBlock来存储着色器数据。你不需要自己创建这些数据,因为框架会自动为你做池化处理,以节省时间并确保性能最佳。所以我们只需要为我们的着色器请求一个PropertySheet,并在其中设置统一。

最后,我们使用上下文提供的CommandBuffer,用我们的源码、目的码、表和通证号来blit a fullscreen pass。

C#部分就到此为止了。

Shader

编写自定义效果着色器也是相当直接的,但在开始之前有几件事你应该知道。这个框架大量使用宏来抽象平台的差异,让你的生活更轻松。兼容性是关键,对于即将推出的Scriptable Render Pipelines更是如此。

完整的代码列表。

Shader "Hidden/Custom/Grayscale"
{
    HLSLINCLUDE

        #include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"

        TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
        float _Blend;

        float4 Frag(VaryingsDefault i) : SV_Target
        {
            float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
            float luminance = dot(color.rgb, float3(0.2126729, 0.7151522, 0.0721750));
            color.rgb = lerp(color.rgb, luminance.xxx, _Blend.xxx);
            return color;
        }

    ENDHLSL

    SubShader
    {
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            HLSLPROGRAM

                #pragma vertex VertDefault
                #pragma fragment Frag

            ENDHLSL
        }
    }
}

首先要注意的是:我们已经不使用CG块了。如果未来与Scriptable Render Pipelines的兼容性对你来说很重要,请不要使用它们,因为它们会在切换时破坏着色器,因为CG块会在着色器中添加你不想要的隐藏代码。相反,使用HLSL块。

至少你需要包含 StdLib.hlsl。它包含了预先配置的顶点着色器和变化结构(VertDefault、VaryingsDefault),以及大部分你需要的数据来编写常用效果。

纹理声明使用宏来完成。要获得可用的宏列表,我们建议你查看/PostProcessing/Shaders/API/中的一个API文件。

除此之外,其他的都是标准的着色器代码。在这里我们计算出当前像素的亮度,然后用_Blend uniform将像素的颜色与亮度进行对比,然后返回结果。

重要的是:如果在你的任何场景中都没有引用这个着色器,那么它将不会被建立,并且在编辑器外运行游戏时,效果将无法工作。将其添加到 Resources folder中,或者将其放在Edit -> Project Settings -> Graphics中的Always Included Shaders

Effect ordering

内置效果是自动排序的,但是自定义效果呢?只要你创建一个新的效果或将其导入到你的项目中,它就会被添加到Post Process LayerCustom Effect Sorting list中。
它们将按注入点进行预排序,但你可以随意重新排序。顺序是按层级排序的,这意味着你可以针对每个相机用不同的排序方式。

Custom editor

默认情况下,设置类的编辑器会自动为你创建。但有时你会希望对字段的显示方式有更多的控制权。就像经典的Unity组件一样,你可以创建自定义编辑器。

重要的是:和经典的编辑器一样,你必须将这些编辑器放在一个编辑器文件夹中。
如果我们要为我们的Grayscale效果复制默认的编辑器,它的样子是这样的:

using UnityEngine.Rendering.PostProcessing;
using UnityEditor.Rendering.PostProcessing;

[PostProcessEditor(typeof(Grayscale))]
public sealed class GrayscaleEditor : PostProcessEffectEditor<Grayscale>
{
    SerializedParameterOverride m_Blend;

    public override void OnEnable()
    {
        m_Blend = FindParameterOverride(x => x.blend);
    }

    public override void OnInspectorGUI()
    {
        PropertyField(m_Blend);
    }
}

Additional notes

出于性能上的考虑,FXAA希望每个像素的LDR亮度值存储在其源目标的alpha通道中。如果你需要FXAA,并希望在AfterStack注入点注入自定义效果,请确保最后执行的效果在alpha通道中包含LDR亮度值(或者直接从传入的源中复制alpha)。如果不是的话FXAA将无法正常工作。

FXAA:FXAA全称为“Fast Approximate Anti-Aliasing”,翻译成中文就是“快速近似抗锯齿”。它是传统MSAA(多重采样抗锯齿)效果的一种高性能近似值。它是一种单程像素着色器,和MLAA一样运行于目标游戏渲染管线的后期处理阶段,但不像后者那样使用DirectCompute,而只是单纯的后期处理着色器,不依赖于任何GPU计算API。正因为如此,FXAA技术对显卡没有特殊要求,完全兼容NVIDIA、AMD的不同显卡(MLAA仅支持A卡)和DX9、DX10、DX11

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值