【Shader】屏幕后處理筆記

是什么?

顧名思義就是在得到屏幕渲染圖后我們?cè)趯?duì)這個(gè)圖做一定的處理呀舔,這個(gè)處理就差不多我們平時(shí)p圖的哪些操作弥虐,改亮度,對(duì)比度媚赖,模糊啥的霜瘪。

怎么做?

這里unity給我們一個(gè)接口-OnRenderImage

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

在這個(gè)方法中我們一般使用Graphics.Blit來(lái)做融合處理惧磺。

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);

簡(jiǎn)單的原理就是建一個(gè)材質(zhì)把這個(gè)材質(zhì)的效果疊加到source圖上去颖对,所以我們的所寫(xiě)的Shader中必須有一個(gè)叫_MainTex的屬性。

都說(shuō)是后處理了豺妓,最后渲染得到的圖是通過(guò)攝像機(jī)得到的惜互,所以我們需要把這些處理的腳本放在跟攝像機(jī)一個(gè)GameObject上。首先我們需要判斷當(dāng)前平臺(tái)是否支持琳拭,然后需要?jiǎng)?chuàng)建一個(gè)材質(zhì)训堆。這里我們有一個(gè)基類(lèi)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();
    }
    //在最開(kāi)始調(diào)用
    protected void CheckResoures()
    {
        var isSupported = CheckSupport();
        if (!isSupported)
        {
            NoSupport();
        }
    }
    //檢查是否支持
    protected bool CheckSupport()
    {
        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
        {
            Debug.LogWarning("此平臺(tái)不支持圖片效果后處理");
            return false;
        }
        return true;
    }

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

    //檢查shader是否存在并創(chuàng)建該shader的材質(zhì)
    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;
            }
        }
    }
}

調(diào)整屏幕亮度白嘁、飽和度坑鱼、對(duì)比度

要做到這個(gè)三個(gè)效果我們只需要在片元方法中,調(diào)節(jié)其中顏色值即可絮缅。首先獲得屏幕:

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

首先我們來(lái)看如何調(diào)整亮度:

fixed3 finalCol = renderTex.rgb * _Brightness; 

在調(diào)整飽和度:

//這個(gè)應(yīng)該是一個(gè)經(jīng)驗(yàn)公式
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); 

最后設(shè)置對(duì)比度即可:

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

我們?cè)贠nRenderImage中設(shè)置這三個(gè)參數(shù)即可:

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);
    }
}

亮度的效果還是可以用來(lái)做開(kāi)場(chǎng)動(dòng)畫(huà)和結(jié)束動(dòng)畫(huà)鲁沥,挺好看的。

image

邊緣檢測(cè)

卷積: 是指使用卷積核對(duì)一張圖像中的每個(gè)像素進(jìn)行一系列操作耕魄。卷積核一般是一個(gè)正方形網(wǎng)格結(jié)構(gòu)(3x3或者是2x2)画恰,每正方形網(wǎng)格中的格子都會(huì)有一個(gè)數(shù)值,稱(chēng)為權(quán)重值吸奴。既然是積就需要相乘允扇,比如我們需要計(jì)算某一個(gè)像素的卷積缠局,就把一個(gè)卷核的中心格子放在哪個(gè)像素上,然后依次計(jì)算核中每個(gè)元素和其覆蓋的圖像像素值得乘積并求和考润,得到該像素的卷積狭园。

卷積示意圖

這個(gè)我看了幾次,才看明白哦糊治。這個(gè)就很像乘以矩陣啥的唱矛,我們可以把卷積核理解成一個(gè)常量。對(duì)井辜,就是相當(dāng)于掃雷那種感覺(jué)我們?cè)谂乓粋€(gè)點(diǎn)是否是雷就看周?chē)臄?shù)字嘛绎谦,這個(gè)周?chē)木涂梢岳斫鉃榫矸e核。我們這個(gè)時(shí)候已知周?chē)臄?shù)字抑胎,然后把周?chē)淖峙c那個(gè)格子的顏色相乘然后燥滑,最后把所有相乘的值相加就得到了卷積渐北。

那我們現(xiàn)在獲得了卷積值阿逃,卷積值越大就越可能是邊緣點(diǎn)。我們知道邊緣為什么是邊緣赃蛛?就是因?yàn)樗c其他地方的顏色差別很恃锉。當(dāng)然這個(gè)卷積核肯定是特定的,這樣就可以檢測(cè)出來(lái)顏色大小呕臂。

3種常見(jiàn)的邊緣檢測(cè)算子

邊緣檢測(cè)cs代碼

邊緣檢測(cè)shader代碼

我這里沒(méi)有實(shí)現(xiàn)這個(gè)功能破托,說(shuō)的是我的shader不支持平臺(tái)。歧蒋。土砂。。

高斯模糊

使用的原理與求邊緣的原理差不多谜洽,也是使用一個(gè)卷積核萝映,但是這里叫做高斯核,這里有一個(gè)求高斯核的權(quán)重的公式阐虚,


公式

然后我們可以跟求邊緣一樣求得卷積序臂。這里我們做了一個(gè)優(yōu)化,把二維的正方形高斯核轉(zhuǎn)化成兩個(gè)一維的高斯核实束,就是轉(zhuǎn)化中間的橫豎那一列和行奥秆。

把一個(gè)二維5x5的高斯核轉(zhuǎn)化為兩個(gè)一維高斯核
效果

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


Bloom效果

這個(gè)效果是做到一種高光部分過(guò)爆的效果,帶有朦朧效果咸灿。
原理就是先生成高亮部分的圖构订,然后對(duì)這個(gè)圖做高斯模糊最終獲得一張圖(模擬光線圖),然后把模糊圖與原圖做一個(gè)混合即可避矢。
所以這用了4個(gè)pass塊悼瘾,幾次來(lái)處理签赃。

效果圖

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


運(yùn)動(dòng)模糊

做運(yùn)動(dòng)模糊一般有很多種方式:
1.累計(jì)緩存:把每一幀的圖像記錄下來(lái),然后把記錄下來(lái)的圖片連續(xù)混合起來(lái)顯示分尸,這樣就可以做出動(dòng)態(tài)模糊同時(shí)也可以做出虛影的效果锦聊。這個(gè)消耗很大。
2.速度緩存:緩存中存儲(chǔ)了各個(gè)像素當(dāng)前的運(yùn)動(dòng)速度箩绍,然后利用該值來(lái)決定模糊的方向大小孔庭。

這里作者使用得的第一個(gè)方式的優(yōu)化來(lái)實(shí)現(xiàn),在得到之前渲染結(jié)果材蛛,不斷把當(dāng)前的渲染圖像疊加到之前的渲染圖像中圆到,從而產(chǎn)生一種運(yùn)動(dòng)軌跡的視覺(jué)效果。

在OnRenderImage中卑吭,我們就把當(dāng)前渲染得到得的圖不斷存入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);
        }
        //恢復(fù)操作 發(fā)生在渲染到紋理而該紋理又沒(méi)有被提前清空或銷(xiāo)毀的情況
        accumulationTexture.MarkRestoreExpected();

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

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

我們?cè)趕hader中需要分別處理透明通道和顏色通道在兩個(gè)pass塊里,因?yàn)槲覀冊(cè)讷@得模糊虛影時(shí)豆赏,需要設(shè)置虛影的長(zhǎng)度挣菲,這個(gè)長(zhǎng)度就是我們的設(shè)置的模糊參數(shù)嘉蕾。

實(shí)現(xiàn)效果

看起來(lái)還是很酷炫得的彻况。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谈秫,隨后出現(xiàn)的幾起案子抚岗,更是在濱河造成了極大的恐慌或杠,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宣蔚,死亡現(xiàn)場(chǎng)離奇詭異向抢,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)胚委,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)挟鸠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人篷扩,你說(shuō)我怎么就攤上這事兄猩。” “怎么了鉴未?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵枢冤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我铜秆,道長(zhǎng)淹真,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任连茧,我火速辦了婚禮核蘸,結(jié)果婚禮上巍糯,老公的妹妹穿的比我還像新娘。我一直安慰自己客扎,他們只是感情好祟峦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著徙鱼,像睡著了一般宅楞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上袱吆,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天厌衙,我揣著相機(jī)與錄音,去河邊找鬼绞绒。 笑死婶希,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蓬衡。 我是一名探鬼主播喻杈,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼撤蟆!你這毒婦竟也來(lái)了奕塑?” 一聲冷哼從身側(cè)響起堂污,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤家肯,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后盟猖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體讨衣,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年式镐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了反镇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娘汞,死狀恐怖歹茶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情你弦,我是刑警寧澤惊豺,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站禽作,受9級(jí)特大地震影響尸昧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旷偿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一烹俗、第九天 我趴在偏房一處隱蔽的房頂上張望爆侣。 院中可真熱鬧,春花似錦幢妄、人聲如沸兔仰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)斋陪。三九已至,卻和暖如春置吓,著一層夾襖步出監(jiān)牢的瞬間无虚,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工衍锚, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留友题,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓戴质,卻偏偏與公主長(zhǎng)得像度宦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子告匠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容