Unity在更新到Unity2019.4之后,大家或许已经发现,在使用URP(通用渲染管线)的情况下,Unity原来的Post Processing插件好像不起效了。原来Unity在Unity2019.4之后在URP内部集成了屏幕后处理的功能,使用方法也很简单,直接在Hierachy视图右键,选择Volume/Global Volume,我们就可以在Hierarchy视图看到一个Global Volume游戏对象。选中它,在资源检视面板可以看到有一个Volume组件,这就是URP实现屏幕后处理的核心组件。

在资源检视面板上,我们看到Volume组件下面有个Profile选项,要求我们给Volume组件选定一个volume profile文件,这个文件保存了我们为场景添加的屏幕后处理特效和效果参数,Volume需要通过读取这个文件的数据来实现我们需要的效果。我们可以直接点击New按钮,unity会自动在当前场景所在目录下新建一个和场景同名的目录,然后在该目录下生成一个profile文件。或者我们可以在Project视图右键选择Create/Volume profile在当前目录下生成一个profile文件。

给Volume配置好profile文件之后,检视面板会变成下图所示:

Volume Overrides

Volume Overrides是存储屏幕后处理效果的配置参数的基本单元,一个profile文件其实就是多个Volume Override的集合。当然,我们可以创建多个profile文件,而这些profile文件可以通过Volume Framework进行规范管理。下面说一下怎么通过Volume Override添加屏幕后处理效果。

点击Add Override/Post-processing/Bloom,我们就可以将Bloom Override添加到检视面板上了。

设置好参数,我们对比一下前后的效果:

除了Bloom效果之外,Unity还给我们提供了另外15种后处理效果,大家可以参考unity给的官方文档:

Volume Overrides​docs.unity3d.com

添加自定义Override

虽然,Unity给我们提供了很多内置的屏幕后处理特效,但是在实际的工程项目开发中,这些特效有时候是不能完全满足我们的需求的,这时候我们就希望可以对Volume Override进行扩展。下面我们就一起来探讨一下怎么对Volume Overide进行扩展吧。

在展开下面的讨论之前,我们先来了解一下URP源码的目录结构:

|--Package|--com.unity.render-piplines.universal|--Editor|--Runtime|--...|--Materials|--Overrides|--Passes|--...|--...|--Shaders|--...

而Unity URP内置的一些后处理特效代码就放在Overrides文件夹下面:

以Bloom为例,双击点开查看一下源码:

using System;namespace UnityEngine.Rendering.Universal
{[Serializable, VolumeComponentMenu("Post-processing/Bloom")]public sealed class Bloom : VolumeComponent, IPostProcessComponent{[Tooltip("Filters out pixels under this level of brightness. Value is in gamma-space.")]public MinFloatParameter threshold = new MinFloatParameter(0.9f, 0f);[Tooltip("Strength of the bloom filter.")]public MinFloatParameter intensity = new MinFloatParameter(0f, 0f);[Tooltip("Changes the extent of veiling effects.")]public ClampedFloatParameter scatter = new ClampedFloatParameter(0.7f, 0f, 1f);[Tooltip("Clamps pixels to control the bloom amount.")]public MinFloatParameter clamp = new MinFloatParameter(65472f, 0f);[Tooltip("Global tint of the bloom filter.")]public ColorParameter tint = new ColorParameter(Color.white, false, false, true);[Tooltip("Use bicubic sampling instead of bilinear sampling for the upsampling passes. This is slightly more expensive but helps getting smoother visuals.")]public BoolParameter highQualityFiltering = new BoolParameter(false);[Tooltip("Dirtiness texture to add smudges or dust to the bloom effect.")]public TextureParameter dirtTexture = new TextureParameter(null);[Tooltip("Amount of dirtiness.")]public MinFloatParameter dirtIntensity = new MinFloatParameter(0f, 0f);public bool IsActive() => intensity.value > 0f;public bool IsTileCompatible() => false;}
}

首先,我们发现Bloom类带有一个Attribute标签,它的作用就是把Bloom添加到add Overrides菜单里面。另外,每个后处理功能必须要继承VolumeComponent类和实现IPostProcessComponent接口,这是为了将新加的后处理功能集成到Volume Framework的规范管理中。另外,我们发现Bloom类中的属性并不是C#或unity中的常规数据类型,这是因为Volume Framework对这些类型做了一层封装,其目的是为了使得资源检测界面更加美观。

那么,我们现在就可以仿照这个代码来写一个自己的后处理特效了,以高斯模糊为例,直接粘贴代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using System;namespace UnityEngine.Experiemntal.Rendering.Universal
{[Serializable,VolumeComponentMenu("Addition-post-processing/GaussianBlur")]public class GaussianBlur : VolumeComponent, IPostProcessComponent{public GaussianFilerModeParameter filterMode = new GaussianFilerModeParameter(FilterMode.Bilinear);public ClampedIntParameter blurCount = new ClampedIntParameter(1, 1, 4);public ClampedIntParameter downSample = new ClampedIntParameter(1, 1, 4);public ClampedFloatParameter indensity = new ClampedFloatParameter(0f, 0, 20);//public public bool IsActive(){return active && indensity.value != 0;}public bool IsTileCompatible(){return false;}}[Serializable]public sealed class GaussianFilerModeParameter : VolumeParameter<FilterMode> { public GaussianFilerModeParameter(FilterMode value, bool overrideState = false) : base(value, overrideState) { } }
}

然后我们看看Add Volumes菜单有什么变化。

可以看到高斯模糊已经被添加到add volume菜单上了,但是现在这个功能还没有效果,这是因为我们现在只是添加了这个功能一些必要的参数,具体的实现过程还没有写。接下来我们继续追溯Unity URP是怎么实现后处理的。

打开Runtime/Passes路径下的PostProcessPass.cs,然后我们发现,URP中内置的后处理特效全都定义在这了:

继续往下查找,这些实例初始化的地方都在Execute(ScriptableRenderContext context, ref RenderingData renderingData)函数里面:

而最终实现后处理渲染的地方是在void Render(CommandBuffer cmd, ref RenderingData renderingData)函数中:

SetupBloom方式则是具体的实现逻辑,有兴趣的可以自己独自去探究了,本文就不在深入介绍了。

那么我们要添加自己定义的后处理效果难道是要修改URP插件吗?理智告诉我们这样是不可取的,最好的结果当然是把我们自定义的特效的代码跟官方的插件完全解耦,而unity也给我们提供了这样的工具,那就是RenderFeature。RenderFeature的作用是可以让我们扩展渲染的pass,可以灵活的在渲染的各个阶段插入commandbuffer,这个插入点由RenderPassEvent决定。下面就让我们一起来创建一个RenderFeature。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;namespace UnityEngine.Experiemntal.Rendering.Universal
{public class AdditionPostProcessRendererFeature : ScriptableRendererFeature{public RenderPassEvent evt = RenderPassEvent.AfterRenderingTransparents;public AdditionalPostProcessData postData;AdditionPostProcessPass postPass;public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){var cameraColorTarget = renderer.cameraColorTarget;var cameraDepth = renderer.cameraDepth;var dest = RenderTargetHandle.CameraTarget;if (postData == null)return;postPass.Setup(evt, cameraColorTarget, cameraDepth, dest, postData);renderer.EnqueuePass(postPass);}public override void Create(){postPass = new AdditionPostProcessPass();}}
}

每个RenderFeature必须要继承ScriptableRendererFeature抽象类,并且实现AddRenderPasses跟Create函数。在ScriptableRendererFeature对象被初始化的时候,首先会调用Create方法,我们可以在这构建一个ScriptableRenderPass实例,然后在AddRenderPasses方法中对其进行初始化并把它添加到渲染队列中,这里大家或许已经明白,ScriptableRendererFeature对象跟ScriptableRenderPass对象需要搭配使用。创建好AdditionPostProcessRendererFeature,我们就可以在ForwardRenderer中添加新定义的RenderFeature了。

接着我们需要实现AdditionPostProcessPass。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;namespace UnityEngine.Experiemntal.Rendering.Universal
{/// <summary>/// 对URP屏幕后处理扩展/// </summary>public class AdditionPostProcessPass : ScriptableRenderPass{/// <summary>/// 高斯模糊/// </summary>RenderTargetIdentifier m_ColorAttachment;RenderTargetIdentifier m_CameraDepthAttachment;RenderTargetHandle m_Destination;const string k_RenderPostProcessingTag = "Render AdditionalPostProcessing Effects";const string k_RenderFinalPostProcessingTag = "Render Final AdditionalPostProcessing Pass";//additonal effects settingsGaussianBlur m_GaussianBlur;MaterialLibrary m_Materials;AdditionalPostProcessData m_Data;RenderTargetHandle m_TemporaryColorTexture01;RenderTargetHandle m_TemporaryColorTexture02;RenderTargetHandle m_TemporaryColorTexture03;public AdditionPostProcessPass(){m_TemporaryColorTexture01.Init("_TemporaryColorTexture1");m_TemporaryColorTexture02.Init("_TemporaryColorTexture2");m_TemporaryColorTexture03.Init("_TemporaryColorTexture3");}public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){var stack = VolumeManager.instance.stack;m_GaussianBlur = stack.GetComponent<GaussianBlur>();var cmd = CommandBufferPool.Get(k_RenderPostProcessingTag);Render(cmd, ref renderingData);context.ExecuteCommandBuffer(cmd);CommandBufferPool.Release(cmd);}public void Setup(RenderPassEvent @event, RenderTargetIdentifier source,RenderTargetIdentifier cameraDepth, RenderTargetHandle destination, AdditionalPostProcessData data){m_Data = data;renderPassEvent = @event;m_ColorAttachment = source;m_CameraDepthAttachment = cameraDepth;m_Destination = destination;m_Materials = new MaterialLibrary(data);}void Render(CommandBuffer cmd,ref RenderingData renderingData){ref var cameraData = ref renderingData.cameraData;if (m_GaussianBlur.IsActive() && !cameraData.isSceneViewCamera){SetupGaussianBlur(cmd, ref renderingData, m_Materials.gaussianBlur);}}public void SetupGaussianBlur(CommandBuffer cmd, ref RenderingData renderingData, Material blurMaterial){RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;opaqueDesc.width = opaqueDesc.width >> m_GaussianBlur.downSample.value;opaqueDesc.height = opaqueDesc.height >> m_GaussianBlur.downSample.value;opaqueDesc.depthBufferBits = 0;cmd.GetTemporaryRT(m_TemporaryColorTexture01.id, opaqueDesc, m_GaussianBlur.filterMode.value);cmd.GetTemporaryRT(m_TemporaryColorTexture02.id, opaqueDesc, m_GaussianBlur.filterMode.value);cmd.GetTemporaryRT(m_TemporaryColorTexture03.id, opaqueDesc, m_GaussianBlur.filterMode.value);cmd.BeginSample("GaussianBlur");cmd.Blit(this.m_ColorAttachment, m_TemporaryColorTexture03.Identifier());for (int i = 0; i < m_GaussianBlur.blurCount.value; i++){blurMaterial.SetVector("_offsets", new Vector4(0, m_GaussianBlur.indensity.value, 0, 0));cmd.Blit(m_TemporaryColorTexture03.Identifier(), m_TemporaryColorTexture01.Identifier(), blurMaterial);blurMaterial.SetVector("_offsets", new Vector4(m_GaussianBlur.indensity.value, 0, 0, 0));cmd.Blit(m_TemporaryColorTexture01.Identifier(), m_TemporaryColorTexture02.Identifier(), blurMaterial);cmd.Blit(m_TemporaryColorTexture02.Identifier(), m_ColorAttachment);}cmd.Blit(m_TemporaryColorTexture03.Identifier(), this.m_Destination.Identifier());cmd.EndSample("Blur");}}
}

创建ScriptableRenderPass对象我们必须要重写Execute方法,URP会自动调用这个方法来执行我们的后处理任务。为了方便对自定义后处理特效的效果的管理,我们可以仿照URP的管理方式,创建一个ScriptableObject对象,主要负责管理自定义后处理特效的shader,代码如下:

using UnityEngine;
using System.Collections;
using System;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.ProjectWindowCallback;
#endif
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering;namespace UnityEngine.Experiemntal.Rendering.Universal
{[Serializable]public class AdditionalPostProcessData : ScriptableObject{#if UNITY_EDITOR[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812")][MenuItem("Assets/Create/Rendering/Universal Render Pipeline/Additional Post-process Data", priority = CoreUtils.assetCreateMenuPriority3 + 1)]static void CreateAdditionalPostProcessData(){//ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance<CreatePostProcessDataAsset>(), "CustomPostProcessData.asset", null, null);var instance = CreateInstance<AdditionalPostProcessData>();AssetDatabase.CreateAsset(instance, string.Format("Assets/Settings/{0}.asset", typeof(AdditionalPostProcessData).Name));Selection.activeObject = instance;}
#endif[Serializable]public sealed class Shaders{public Shader gaussianBlur = Shader.Find("Custom/GaussianBlur");}public Shaders shaders;}
}

然后在Project面板,右键选择菜单Create/Rendering/Universal Render Pipeline/Additional Post-process Data,就会在Settings目录下创建一个AdditionalPostProcessData.asset文件,然后把它赋值给ForwardRenderer下的AdditionPostProcessRendererFeature即可。

在AdditionPostProcessPass中,我还引用了一个MaterialLibrary对象,这个对象的作用是可以动态创建每个自定义后处理效果所需要的材质,直接粘贴源代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;namespace UnityEngine.Experiemntal.Rendering.Universal
{public class MaterialLibrary{public readonly Material gaussianBlur;public MaterialLibrary(AdditionalPostProcessData data){gaussianBlur = Load(data.shaders.gaussianBlur);}Material Load(Shader shader){if (shader == null){Debug.LogErrorFormat($"Missing shader. {GetType().DeclaringType.Name} render pass will not execute. Check for missing reference in the renderer resources.");return null;}else if (!shader.isSupported){return null;}return CoreUtils.CreateEngineMaterial(shader);}internal void Cleanup(){CoreUtils.Destroy(gaussianBlur);}}
}

最后最重要的一部分就是我们的shader了,话不多说,直接上代码吧:

Shader "Custom/GaussianBlur"
{Properties{_MainTex("Base (RGB)", 2D) = "white" {}_offsets("Offset",vector) = (0,0,0,0)}HLSLINCLUDE#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"//#include "Packages/com.unity.render-pipelines.universal/Shaders/PostProcessing/Common.hlsl"CBUFFER_START(UnityPerMaterial)float4 _MainTex_ST;float4 _MainTex_TexelSize;float4 _offsets;CBUFFER_ENDstruct ver_blur{float4 positionOS : POSITION;float2 uv : TEXCOORD0;UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f_blur{float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float4 uv01 : TEXCOORD1;float4 uv23 : TEXCOORD2;float4 uv45 : TEXCOORD3;UNITY_VERTEX_OUTPUT_STEREO};TEXTURE2D(_MainTex);SAMPLER(sampler_MainTex);//vertex shaderv2f_blur vert_blur(ver_blur v){v2f_blur o;UNITY_SETUP_INSTANCE_ID(v);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);o.pos = TransformObjectToHClip(v.positionOS.xyz);o.uv = v.uv;_offsets *= _MainTex_TexelSize.xyxy;o.uv01 = v.uv.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);o.uv23 = v.uv.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;o.uv45 = v.uv.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;return o;}//fragment shaderfloat4 frag_blur(v2f_blur i) : SV_Target{half4 color = half4(0,0,0,0);//将像素本身以及像素左右(或者上下,取决于vertex shader传进来的uv坐标)像素值的加权平均color = 0.4 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv);color += 0.15 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv01.xy);color += 0.15 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv01.zw);color += 0.10 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv23.xy);color += 0.10 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv23.zw);color += 0.05 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv45.xy);color += 0.05 * SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, i.uv45.zw);return color;}ENDHLSL//开始SubShaderSubShader{Tags {"RenderType"="Opaque" "RenderPipeline"="UniversalPipeline"}LOD 100ZTest Always Cull Off ZWrite OffPass{Name "Gaussian Blur"//后处理效果一般都是这几个状态//使用上面定义的vertex和fragment shaderHLSLPROGRAM#pragma vertex vert_blur#pragma fragment frag_blurENDHLSL}}//后处理效果一般不给fallback,如果不支持,不显示后处理即可
}

system volume information是什么文件_如何扩展Unity URP的后处理Volume组件相关推荐

  1. U盘中毒了?教你如何删除System Volume Information这个顽固文件夹

    不得不说cmd命令很好用呢.最近我的U盘中毒了,格式化都删除不了System Volume Information这个顽固的文件夹,真心伤不起哇!还好现在解决了问题.看来以后得好好对待U盘,不能乱用了 ...

  2. U盘中毒,无法删除System Volume Information文件夹

    情景:U盘中毒,U盘内的文件夹名称变成.exe后缀,且多出一个名为System Volume Information的文件夹,对U盘进行格式化后,所有文件消失,当拔出U盘,再次插入电脑时,发现Syst ...

  3. 优盘中毒,里面有(System Volume Information文件夹)删除不了?教你怎么解决

    又发现我的优盘里面还有其他东西... 这次是个System Volume Information文件夹,怎么删都删不了,学校的打印店电脑不要乱插!!! 解决步骤 输入以下命令 重置隐藏文件(E为E盘, ...

  4. 删除U盘中的System Volume Information 文件夹的方法

    在使用U盘测试ARM板的时候,会发现System Volume Information这个文件夹阴魂不散,总是存在,在Windows下是看不见的,即便将文件的查看属性设置为显示隐藏文件. 在使用U盘进 ...

  5. 小小知识点(十八)U盘中病毒了,System Volume Information文件夹删除不掉

    win+R调出命令窗口后搜索cmd,启用cmd命令编辑器,并输入以下命令: attrib "H:\System Volume Information" -s   //这句话可以选择 ...

  6. 如何删除U盘中System Volume Information文件夹

    教你如何删除System Volume Information这个顽固文件夹 我的电脑是win10,win+R搜索cmd,启用cmd命令编辑器,并按顺序输入以下命令: 1. attrib " ...

  7. u盘中毒如何删除system volume information文件

    最近U盘因为插别人的电脑上中毒了,出现了System Volume Information文件夹,然后搜了相关解决方法,确实有效,但由于大家写的都太相似了,没有考虑到每台计算机的具体状况,感觉对新手小 ...

  8. 关于碰到优盘插入电脑检测到病毒并且优盘里文件只显示System Volume Information文件夹的问题解决。

    关于碰到优盘插入电脑检测到病毒并且优盘里文件只显示System Volume Information文件夹的问题解决. 我曾经也碰到过优盘没怎么用过,去了一趟打印店,之后突然发现插到电脑上,电脑检测到 ...

  9. 清除文件计算机病毒是,删除电脑病毒文件System Volume Information的方法

    有些用户反馈说电脑运行速度变慢,而且还卡,检查后发现System Volume Information文件夹引起的,这是一个病毒文件,需要及时删除.然而用很多方法怎么也删除不掉System Volum ...

最新文章

  1. python实现字符串切割
  2. 听大佬学长RQY报告有感
  3. 【C#文件锁】C#加密解密文件小工具
  4. 分享一些支持多租户的开源框架
  5. CCF201709-2 公共钥匙盒
  6. html5与python哪个好_3个原因告诉你,为什么选择HTML5大前端?
  7. shell脚本修改文本中匹配行之前的行的方法
  8. 良好的开端是成功的第一步———构建程序
  9. 【面试】最容易被问到的N种排序算法!
  10. 数据结构(主席树):HZOI 2016 采花
  11. Refactoring Game Entities with Components
  12. 【GIS导论】实验六 叠加分析
  13. 综合金融服务方案模板
  14. 如何编写优秀的单元测试用例
  15. 数据库管理系统属于计算机应用,数据库管理系统属于应用软件吗?
  16. 飞鸽传书【经典版】(飞鸽传书2011)
  17. 9个优秀的标签云免费生成工具
  18. 安装Ubuntu Core系统
  19. 四大新品齐发:荣耀打造无缝智慧全场景生态
  20. 区块链开发中使用最流行的编程语言

热门文章

  1. Python 中 3 个不可思议的返回
  2. python语言易错知识点强化
  3. 浮点类型误区 “!=”
  4. C#比较两个日期的大小两种案例解析
  5. 吴恩达深度学习——2.2 Logistic回归
  6. 去哪儿-21-debuggiing-testing
  7. 【稀疏向量技术是什么?】差分隐私系统学习记录(六)
  8. 群组密钥交换的新方法研究与分析【会议】
  9. LeetCode自我总结(对链表进行插入排序)
  10. Matlab--三维散点插值成曲面