背景
眾所周知,Unity3D支援自定義後處理效果,實現過程有三步:
- 新增著色器,在著色器裡書寫後處理程式碼;
- 新增材質,把材質和著色器繫結;
- 給相機新增指令碼,重寫其OnRenderImage方法,將材質傳入Graphics.Blit方法中。
但是在做最近的一個專案時,我使用了Unity3D的官方後處理外掛Post Processing Stack V2(以下簡稱PPV2)來簡化輝光、環境光遮蔽這類後處理效果的使用。但之後我又需要自定義一些後處理效果,此時就出現了問題。我發現我的OnRenderImage方法沒有正常地接收到渲染幀經過外掛處理後的紋理,而是接收到一個純黑紋理,最後輸出的也是純黑,使得我的後處理效果無法正常工作,網上也找不到實際原因,可能和渲染管線的不同有關。為了解決這個問題,必須基於PPV2自定義一個效果,然後在其他程式碼中操作這個效果裡的引數,由PPV2來執行我們的後處理效果。這個國內國外的教程都非常少,我主要參考了PPV2的官方文件,在這裡給出。
程式碼
著色器
Shader "Hidden/Custom/Blend" {
HLSLINCLUDE
#include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"
TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
TEXTURE2D_SAMPLER2D(_DesTex, sampler_DesTex);
float _Alpha;
float4 Frag(VaryingsDefault i) : SV_Target {
float4 col1 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
float4 col2 = SAMPLE_TEXTURE2D(_DesTex, sampler_DesTex, i.texcoord);
float4 col = lerp(col2, col1, _Alpha);
return col;
}
ENDHLSL
SubShader {
Cull Off ZWrite Off ZTest Always
Pass {
HLSLPROGRAM
#pragma vertex VertDefault
#pragma fragment Frag
ENDHLSL
}
}
}
基本和文件中的一致,只是修改了片元著色器函式裡的程式碼,實現將兩張紋理進行混合的過程,另外由於這個文件比較新,例項的Shader語法好像和以前的CG語言不太一樣,不知道是不是換成了HLSL。
效果自定義
using System;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;
[Serializable]
[PostProcess(typeof(BlendRenderer), PostProcessEvent.AfterStack, "Custom/Blend")]
public sealed class Blend : PostProcessEffectSettings {
public TextureParameter DesTex = new TextureParameter();
public FloatParameter Alpha = new FloatParameter();
}
public sealed class BlendRenderer : PostProcessEffectRenderer<Blend>
{
public override void Render(PostProcessRenderContext context) {
var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Blend"));
sheet.properties.SetTexture("_DesTex", settings.DesTex);
sheet.properties.SetFloat("_Alpha", settings.Alpha);
context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
}
}
這裡定義了兩個類,一個是設定類,提供了後處理效果所需的各種屬性,其中支援的屬性型別可以在專案下Packages/Post Processing/PostProcessing/Runtime/ParameterOverride.cs裡找到,對應的基礎型別有int、float、color、vector2、vector3、vector4、spline和texture。第二個類用來重寫後處理方法,一般在這裡指定要用的shader和給shader裡的變數賦值。
修改效果引數
void Start() {
m_Blend = ScriptableObject.CreateInstance<Blend>();
m_Blend.enabled.Override(true);
m_Blend.Alpha.Override(1f);
m_Blend.DesTex.Override(Texture2D.blackTexture);
m_Volume = PostProcessManager.instance.QuickVolume(8, 100f, m_Blend);
// 8是後處理所在的層
}
這一段是初始化,先建立後處理效果,然後將其加入到後處理體積中。初始化後處理效果引數用Override方法,注意QuickVolume方法的第一個引數非常重要,它對應在PostProcessing Layer元件裡填寫的層的編號。
m_Blend.DesTex.value = tex; // tex -> Texture2D
m_Blend.Alpha.value = Alpha; // Alpha -> float
平常賦值直接修改屬性名的value屬性。
private void OnDestroy() {
RuntimeUtilities.DestroyVolume(m_Volume, true, true);
}
注意在物件被銷燬時要將建立的臨時後處理體積銷燬。如果沒有這一段,更換場景時後處理會繼續工作,不是我們想要的效果。
總結
Unity3D+Post Processing Stack V2自定義後處理效果其實也是隻有三步,就是編寫後處理著色器、編寫後處理效果類、編寫操作後處理引數類。主要還是國內外的教程沒有與時俱進導致資料查詢困難,希望更多的新教程能不斷湧現,方便開發者的學習。