【Shader】屏幕后處理筆記

是什么?

顧名思義就是在得到屏幕渲染圖后我們在對這個圖做一定的處理,這個處理就差不多我們平時p圖的哪些操作,改亮度,對比度,模糊啥的。

怎么做?

這里unity給我們一個接口-OnRenderImage

//src為我們得到屏幕渲染圖 dest為我們處理后的一定結果
MonoBehaviour.OnRenderImage (RenderTexture src,RenderTexture dest)

在這個方法中我們一般使用Graphics.Blit來做融合處理。

public static void Blit(Texture source, RenderTexture dest, Material mat, [Internal.DefaultValue("-1")] int pass);
public static void Blit(Texture source, RenderTexture dest, Material mat);
public static void Blit(Texture source, Material mat);

簡單的原理就是建一個材質把這個材質的效果疊加到source圖上去,所以我們的所寫的Shader中必須有一個叫_MainTex的屬性。

都說是后處理了,最后渲染得到的圖是通過攝像機得到的,所以我們需要把這些處理的腳本放在跟攝像機一個GameObject上。首先我們需要判斷當前平臺是否支持,然后需要創建一個材質。這里我們有一個基類PostEffectBase。如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class PostEffectBase : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        CheckResoures();
    }
    //在最開始調用
    protected void CheckResoures()
    {
        var isSupported = CheckSupport();
        if (!isSupported)
        {
            NoSupport();
        }
    }
    //檢查是否支持
    protected bool CheckSupport()
    {
        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
        {
            Debug.LogWarning("此平臺不支持圖片效果后處理");
            return false;
        }
        return true;
    }

    //取消該腳本效果
    protected void NoSupport()
    {
        enabled = false;
    }

    //檢查shader是否存在并創建該shader的材質
    protected Material CheckShaderAndCreateMaterial(Shader shader,Material material){
        if (shader==null)
        {
            return null;
        }
        if (shader.isSupported&&material&&material.shader==shader)
        {
            return material;
        }
        if (!shader.isSupported)
        {
            return null;
        }else
        {
            material=new Material(shader);
            material.hideFlags=HideFlags.DontSave;
            if (material)
            {
                return material;
            }else
            {
                return null;
            }
        }
    }
}

調整屏幕亮度、飽和度、對比度

要做到這個三個效果我們只需要在片元方法中,調節其中顏色值即可。首先獲得屏幕:

fixed4 renderTex = tex2D(_MainTex, i.uv); 

首先我們來看如何調整亮度:

fixed3 finalCol = renderTex.rgb * _Brightness; 

在調整飽和度:

//這個應該是一個經驗公式
fixed luminance = 0.2125 * renderTex.r + 0.7254 * renderTex.g + 0.0721 * renderTex.b; 
fixed3 luminaceColor = fixed3(luminance, luminance, luminance); 
finalCol == lerp(luminaceColor, finalCol, _Saturation); 

最后設置對比度即可:

fixed3 avgColor = fixed3(0.5, 0.5, 0.5); 
finalCol = lerp(avgColor,finalCol,_Contrast); 
return fixed4(finalCol,renderTex.a); 

我們在OnRenderImage中設置這三個參數即可:

void OnRenderImage(RenderTexture src, RenderTexture dest)
{
    if (material!=null)
    {
        material.SetFloat("_Brightness",brightness);
        material.SetFloat("_Saturation",saturation);
        material.SetFloat("_Contrast",contrast);

        Graphics.Blit(src,dest,material);
    }else
    {
        Graphics.Blit(src,dest);
    }
}

亮度的效果還是可以用來做開場動畫和結束動畫,挺好看的。

image

邊緣檢測

卷積: 是指使用卷積核對一張圖像中的每個像素進行一系列操作。卷積核一般是一個正方形網格結構(3x3或者是2x2),每正方形網格中的格子都會有一個數值,稱為權重值。既然是積就需要相乘,比如我們需要計算某一個像素的卷積,就把一個卷核的中心格子放在哪個像素上,然后依次計算核中每個元素和其覆蓋的圖像像素值得乘積并求和,得到該像素的卷積。

卷積示意圖

這個我看了幾次,才看明白哦。這個就很像乘以矩陣啥的,我們可以把卷積核理解成一個常量。對,就是相當于掃雷那種感覺我們在排一個點是否是雷就看周圍的數字嘛,這個周圍的就可以理解為卷積核。我們這個時候已知周圍的數字,然后把周圍的字與那個格子的顏色相乘然后,最后把所有相乘的值相加就得到了卷積。

那我們現在獲得了卷積值,卷積值越大就越可能是邊緣點。我們知道邊緣為什么是邊緣?就是因為他與其他地方的顏色差別很。當然這個卷積核肯定是特定的,這樣就可以檢測出來顏色大小。

3種常見的邊緣檢測算子

邊緣檢測cs代碼

邊緣檢測shader代碼

我這里沒有實現這個功能,說的是我的shader不支持平臺。。。。

高斯模糊

使用的原理與求邊緣的原理差不多,也是使用一個卷積核,但是這里叫做高斯核,這里有一個求高斯核的權重的公式,


公式

然后我們可以跟求邊緣一樣求得卷積。這里我們做了一個優化,把二維的正方形高斯核轉化成兩個一維的高斯核,就是轉化中間的橫豎那一列和行。

把一個二維5x5的高斯核轉化為兩個一維高斯核
效果

高斯模糊cs代碼
高斯模糊shader代碼


Bloom效果

這個效果是做到一種高光部分過爆的效果,帶有朦朧效果。
原理就是先生成高亮部分的圖,然后對這個圖做高斯模糊最終獲得一張圖(模擬光線圖),然后把模糊圖與原圖做一個混合即可。
所以這用了4個pass塊,幾次來處理。

效果圖

Bloom效果cs代碼
Bloom效果shader代碼


運動模糊

做運動模糊一般有很多種方式:
1.累計緩存:把每一幀的圖像記錄下來,然后把記錄下來的圖片連續混合起來顯示,這樣就可以做出動態模糊同時也可以做出虛影的效果。這個消耗很大。
2.速度緩存:緩存中存儲了各個像素當前的運動速度,然后利用該值來決定模糊的方向大小。

這里作者使用得的第一個方式的優化來實現,在得到之前渲染結果,不斷把當前的渲染圖像疊加到之前的渲染圖像中,從而產生一種運動軌跡的視覺效果。

在OnRenderImage中,我們就把當前渲染得到得的圖不斷存入acumulationTexture中。

void OnRenderImage(RenderTexture src, RenderTexture dest)
{
    if (material != null)
    {
        if (accumulationTexture==null||accumulationTexture.width!=src.width||
        accumulationTexture.height!=src.height)
        {
            DestroyImmediate(accumulationTexture);
            accumulationTexture=new RenderTexture(src.width,src.height,0);
            accumulationTexture.hideFlags=HideFlags.HideAndDontSave;
            Graphics.Blit(src,accumulationTexture);
        }
        //恢復操作 發生在渲染到紋理而該紋理又沒有被提前清空或銷毀的情況
        accumulationTexture.MarkRestoreExpected();

        material.SetFloat("_BlurAmount",1.0f-blurAmount);

        Graphics.Blit(src,accumulationTexture,material);
        Graphics.Blit(accumulationTexture,dest);
    }
    else
    {
        Graphics.Blit(src, dest);
    }
}

我們在shader中需要分別處理透明通道和顏色通道在兩個pass塊里,因為我們在獲得模糊虛影時,需要設置虛影的長度,這個長度就是我們的設置的模糊參數。

實現效果

看起來還是很酷炫得的。

Bloom效果cs代碼
Bloom效果shader代碼

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,224評論 6 529
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,916評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,014評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,466評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,245評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,795評論 1 320
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,869評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,010評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,524評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,487評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,634評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,173評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,884評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,282評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,541評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,236評論 3 388
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,623評論 2 370

推薦閱讀更多精彩內容