溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

發(fā)布時間:2022-01-05 15:14:15 來源:億速云 閱讀:318 作者:小新 欄目:大數(shù)據(jù)

這篇文章主要為大家展示了“Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整”這篇文章吧。

一.概念介紹

我們在做游戲的時候,雖然現(xiàn)在有了Unity等引擎,不用我們自己處理一些繁瑣的東西,但是不管怎么樣,最后顯示在屏幕上的還是一些RGB的像素信息,了解這些基本的概念,肯定對我們做游戲有更大的幫助。

1.顏色模型的概念

既然是校正屏幕的顏色,我們有必要了解一下我們要校正的這幾個屬性的概念。這里就不得不提到我們常用的顏色定義方式,RGB顏色模型和HSV顏色模型。

1.1RGB顏色模型

RGB顏色模型也就是我們最常用的三原色,紅綠藍(lán)。RGB顏色模型在混色時屬于加法混色,RGB中每種顏色數(shù)值越高,色彩越明亮。RBG為(0,0,0)時為黑色,RGB為(255,255,255)時為白色。計(jì)算機(jī)在處理顏色信息時一般都采用RGB顏色模型,可以很精確地表示某種顏色。

1.2HSV顏色模型

RGB顏色模型對于計(jì)算機(jī)來說很容易計(jì)算,但是并不適合人類理解,于是就有了HSV顏色模型,所謂HSV代表的是Hue(色相),Saturation(飽和度),Value(色調(diào))也有一種說法是HSB模型,B代表的是Brightness(明度)。當(dāng)然,還有一些說法,比如HSL模型,L代表的是Lightness(亮度)。HSV模型使用一個圓錐形坐標(biāo)系,頂面對應(yīng)的V(Value色調(diào))為1,表示顏色較亮,底面的Value為0,表示顏色較暗;而H(Hue色相)是由繞著V軸的旋轉(zhuǎn)角度給定,從紅色開始逆時針方向計(jì)算,紅色對應(yīng)0度,綠色對應(yīng)120度,藍(lán)色對應(yīng)240度;S(Saturation飽和度)由模型的半徑來代表,由內(nèi)向外Saturation逐漸增大,圓心處為0,邊緣處為1。下圖是HSV顏色模型的圖示:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

1.3RGB顏色模型和HSV顏色模型的轉(zhuǎn)化

既然兩種顏色模型都可以表示顏色,那么兩者之間一定有某種轉(zhuǎn)化關(guān)系;

RGB轉(zhuǎn)化到HSV模型:

假設(shè)RGB分別用(r,g,b)代表,其中r,g,b分別為0-1之間的實(shí)數(shù);max為r,g,b中最大值,min為最小值;HSV分別用(h,s,v)表示,h為0-360之間實(shí)數(shù),而s和v分別為0-1之間的實(shí)數(shù),轉(zhuǎn)化關(guān)系如下:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

2.亮度,飽和度,對比度,灰度的概念

2.1亮度

圖像中RGB值的大小,RGB各個值越大,那么亮度越亮,越小,亮度越暗。比如我們要增加亮度,那么直接增加RGB值即可。

2.2飽和度

指的是顏色的純度。一般用彩度除以明度,表征彩色偏離同亮度灰色的程度。簡單來說,當(dāng)顏色越偏向某個值,即越偏離灰度,飽和度越大;當(dāng)顏色越偏向灰度,飽和度越小。

下面是百度百科關(guān)于飽和度的一段定義:

飽和度是指色彩的鮮艷程度,也稱色彩的純度。飽和度取決于該色中含色成分和消色成分(灰色)的比例。含色成分越大,飽和度越大;消色成分越大,飽和度越小。純的顏色都是高度飽和的,如鮮紅,鮮綠?;祀s上白色,灰色或其他色調(diào)的顏色,是不飽和的顏色,如絳紫,粉紅,黃褐等。完全不飽和的顏色根本沒有色調(diào),如黑白之間的各種灰色

2.3對比度

指的是一幅圖像中明暗區(qū)域最亮的白和最暗的黑之間不同亮度層級的測量,差異范圍越大代表對比越大,差異范圍越小代表對比越小。一般來說對比度越大,圖像越清晰醒目,色彩也越鮮明艷麗;而對比度小,則會讓整個畫面都灰蒙蒙的。

2.4灰度

灰度使用黑色調(diào)表示物體,即用黑色為基準(zhǔn)色,不同的飽和度的黑色來顯示圖像。 每個灰度對象都具有從 0%(白色)到100%(黑色)的亮度值。

了解了一些基本的色彩概念,我們就可以開始進(jìn)行處理了。首先我們看一下Unity后處理效果的原理。

二.Unity屏幕后處理原理

所謂屏幕后處理,簡單來說就是渲染流水線的最后階段,對由整個場景生成的一張圖片進(jìn)行處理,比如HDR,運(yùn)動模糊等等效果,通過屏幕空間的后處理,可以整體改變整個游戲的風(fēng)格或者效果。所以,要制作屏幕后處理,我們需要兩樣?xùn)|西,一個是用于渲染后處理效果的shader,而另一個是我們需要調(diào)用這個渲染的腳本,好在Unity為我們提供了相關(guān)的功能。


1.OnRenderImage函數(shù)

該函數(shù)在MonoBehaviour中提供,該函數(shù)在所有渲染完成后才進(jìn)行調(diào)用,也就是我們上文所說的生成了一張場景圖片,函數(shù)的原型如下:

 void OnRenderImage(RenderTexture sourceTexture,RenderTexture destTexture);    

RenderTexture表示的是渲染紋理,我們渲染物體并不是僅僅渲染在屏幕空間,也可以將物體渲染到特定紋理上,也就是RenderTexture。sourceTexture就是我們渲染的場景圖片,而destTexture是目標(biāo)渲染紋理。我們可以在這個函數(shù)中進(jìn)行相關(guān)的后處理效果,使用帶有后處理效果shader的材質(zhì)將場景內(nèi)容重新渲染。

2.Graphics.Blit函數(shù)

該函數(shù)是Graphics的函數(shù),用于將源紋理拷貝到目標(biāo)紋理,函數(shù)原型如下:

public static void Blit(Texture source,RenderTexture dest);    
public static void Blit(Texture source,RenderTexture dest, Material mat, int pass = -1);    
public static void Blit(Texture source,Material mat, int pass = -1);

source是源紋理,dest是目標(biāo)紋理,當(dāng)dest為null時,直接將源紋理拷貝到屏幕;mat是拷貝時使用的材質(zhì),也就是我們后處理時使用的材質(zhì),Unity會使用該材質(zhì)將源紋理進(jìn)行處理拷貝給目標(biāo)紋理,pass是使用的材質(zhì)shader所使用的pass,我們知道,一個shader中可能有多個pass,使用哪個pass進(jìn)行處理就可以從該參數(shù)傳入,當(dāng)然,默認(rèn)為-1時表示所有的pass都會執(zhí)行。

在了解了Untiy的后處理流程后,我們就可以著手寫我們的亮度對比度飽和度調(diào)整后處理了。

三.后處理效果代碼

后處理效果需要兩部分,分別是腳本部分和shader部分,我們分別來看一下。

1.腳本部分

后處理腳本主要做的是兩件事,第一件是獲取需要的shader,生成材質(zhì),第二件是通過OnRenderImage使用材質(zhì)處理屏幕效果。第一步具有一些普遍性,不管是什么后處理效果,都要有這一步相同的操作,所以我們將該步驟抽離出來,創(chuàng)建一個后處理效果的基類PostEffectBase,代碼如下:

using UnityEngine;  
using System.Collections;  
  
//非運(yùn)行時也觸發(fā)效果  
[ExecuteInEditMode]  
//屏幕后處理特效一般都需要綁定在攝像機(jī)上  
[RequireComponent(typeof(Camera))]  
//提供一個后處理的基類,主要功能在于直接通過Inspector面板拖入shader,生成shader對應(yīng)的材質(zhì)  
public class PostEffectBase : MonoBehaviour {  
  
    //Inspector面板上直接拖入  
    public Shader shader = null;  
    private Material _material = null;  
    public Material _Material  
    {  
        get  
        {  
            if (_material == null)  
                _material = GenerateMaterial(shader);  
            return _material;  
        }  
    }  
  
    //根據(jù)shader創(chuàng)建用于屏幕特效的材質(zhì)  
    protected Material GenerateMaterial(Shader shader)  
    {  
        if (shader == null)  
            return null;  
        //需要判斷shader是否支持  
        if (shader.isSupported == false)  
            return null;  
        Material material = new Material(shader);  
        material.hideFlags = HideFlags.DontSave;  
        if (material)  
            return material;  
        return null;  
    }  
       
}

然后,我們以后所有的后處理效果腳本都可以繼承該類PostEffectBase,就都自動具有了通過shader生成后處理材質(zhì)的功能。

接下來就是我們這一篇的亮度,飽和度,對比度調(diào)整的腳本,腳本很簡單,主要的功能就在于設(shè)置幾個參數(shù),覆寫OnRenderImage函數(shù)后將參數(shù)實(shí)時傳入shader,然后通過Blit函數(shù)完成后處理效果,代碼如下:

using UnityEngine;  
using System.Collections;  
  
//繼承自PostEffectBase  
public class ColorAdjustEffect : PostEffectBase {  
  
    //通過Range控制可以輸入的參數(shù)的范圍  
    [Range(0.0f, 3.0f)]  
    public float brightness = 1.0f;//亮度  
    [Range(0.0f, 3.0f)]  
    public float contrast = 1.0f;  //對比度  
    [Range(0.0f, 3.0f)]  
    public float saturation = 1.0f;//飽和度  
  
    //覆寫OnRenderImage函數(shù)  
    void OnRenderImage(RenderTexture src, RenderTexture dest)  
    {  
        //僅僅當(dāng)有材質(zhì)的時候才進(jìn)行后處理,如果_Material為空,不進(jìn)行后處理  
        if (_Material)  
        {  
            //通過Material.SetXXX("name",value)可以設(shè)置shader中的參數(shù)值  
            _Material.SetFloat("_Brightness", brightness);  
            _Material.SetFloat("_Saturation", saturation);  
            _Material.SetFloat("_Contrast", contrast);  
            //使用Material處理Texture,dest不一定是屏幕,后處理效果可以疊加的!  
            Graphics.Blit(src, dest, _Material);  
        }  
        else  
        {  
            //直接繪制  
            Graphics.Blit(src, dest);  
        }  
    }  
}

這樣,我們的后處理腳本就完成了。涉及到以下幾個知識點(diǎn):

1.可以通過[Range(min,max)]來控制Inspector面板中的值,限定其范圍,并提供滑動條控制。

2.OnRenderImage函數(shù)每幀渲染完全部內(nèi)容后執(zhí)行,我們在每一幀設(shè)置Material的各項(xiàng)參數(shù),通過Material.SetXXX("name",value)可以向shader中傳遞各種參數(shù)。

3.各種后處理效果可以疊加,這里的dest并不一定就是屏幕。不過后處理是很耗費(fèi)性能的,一方面是pixel shader全屏幕overdraw,另一方面,一個rendertexture的內(nèi)存占用很大,尤其是大分辨率手機(jī)上,多個后處理效果可能造成內(nèi)存耗盡,程序崩潰。

2.shader部分

終于步入正題了,下面看一下后處理效果的shader。由于后處理效果是對于一個場景的渲染圖進(jìn)行處理,所以vertex shader基本沒有什么好說的,大部分后處理都是基于pixel shader。先整理一下思路:

最簡單的是亮度,我們可以直接在采樣texture后乘以一個系數(shù),達(dá)到放大或者縮小rgb值的目的,這樣就可以調(diào)整亮度了。

其次是飽和度,飽和度是離灰度偏離越大,飽和度越大,我們首先可以計(jì)算一下同等亮度條件下飽和度最低的值,根據(jù)公式:gray = 0.2125 * r + 0.7154 * g + 0.0721 * b即可求出該值(公式應(yīng)該是一個經(jīng)驗(yàn)公式),然后我們使用該值和原始圖像之間用一個系數(shù)進(jìn)行差值,即可達(dá)到調(diào)整飽和度的目的。

最后是對比度,對比度表示顏色差異越大對比度越強(qiáng),當(dāng)顏色為純灰色,也就是(0.5,0.5,0.5)時,對比度最小,我們通過在對比度最小的圖像和原始圖像通過系數(shù)差值,達(dá)到調(diào)整對比度的目的。代碼如下:

//shader的目錄  
Shader "Custom/ColorAdjustEffect"  
{  
    //屬性塊,shader用到的屬性,可以直接在Inspector面板調(diào)整  
    Properties   
    {  
        _MainTex ("Albedo (RGB)", 2D) = "white" {}  
        _Brightness("Brightness", Float) = 1  
        _Saturation("Saturation", Float) = 1  
        _Contrast("Contrast", Float) = 1  
    }  
  
    //每個shader都有Subshaer,各個subshaer之間是平行關(guān)系,只可能運(yùn)行一個subshader,主要針對不同硬件  
    SubShader  
    {  
        //真正干活的就是Pass了,一個shader中可能有不同的pass,可以執(zhí)行多個pass  
        Pass  
            {  
                //設(shè)置一些渲染狀態(tài),此處先不詳細(xì)解釋  
                ZTest Always Cull Off ZWrite Off  
                  
                CGPROGRAM  
                //在Properties中的內(nèi)容只是給Inspector面板使用,真正聲明在此處,注意與上面一致性  
                sampler2D _MainTex;  
                half _Brightness;  
                half _Saturation;  
                half _Contrast;  
  
                //vert和frag函數(shù)  
                #pragma vertex vert  
                #pragma fragment frag  
                #include "Lighting.cginc"  
  
                //從vertex shader傳入pixel shader的參數(shù)  
                struct v2f  
                {  
                    float4 pos : SV_POSITION; //頂點(diǎn)位置  
                    half2  uv : TEXCOORD0;    //UV坐標(biāo)  
                };  
  
                //vertex shader  
                //appdata_img:帶有位置和一個紋理坐標(biāo)的頂點(diǎn)著色器輸入  
                v2f vert(appdata_img v)  
                {  
                    v2f o;  
                    //從自身空間轉(zhuǎn)向投影空間  
                    o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
                    //uv坐標(biāo)賦值給output  
                    o.uv = v.texcoord;  
                    return o;  
                }  
  
                //fragment shader  
                fixed4 frag(v2f i) : SV_Target  
                {  
                    //從_MainTex中根據(jù)uv坐標(biāo)進(jìn)行采樣  
                    fixed4 renderTex = tex2D(_MainTex, i.uv);  
                    //brigtness亮度直接乘以一個系數(shù),也就是RGB整體縮放,調(diào)整亮度  
                    fixed3 finalColor = renderTex * _Brightness;  
                    //saturation飽和度:首先根據(jù)公式計(jì)算同等亮度情況下飽和度最低的值:  
                    fixed gray = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;  
                    fixed3 grayColor = fixed3(gray, gray, gray);  
                    //根據(jù)Saturation在飽和度最低的圖像和原圖之間差值  
                    finalColor = lerp(grayColor, finalColor, _Saturation);  
                    //contrast對比度:首先計(jì)算對比度最低的值  
                    fixed3 avgColor = fixed3(0.5, 0.5, 0.5);  
                    //根據(jù)Contrast在對比度最低的圖像和原圖之間差值  
                    finalColor = lerp(avgColor, finalColor, _Contrast);  
                    //返回結(jié)果,alpha通道不變  
                    return fixed4(finalColor, renderTex.a);  
                }  
                    ENDCG  
        }  
    }  
    //防止shader失效的保障措施  
    FallBack Off  
}

四.效果展示

完成shader和后處理腳本后,我們可以創(chuàng)建一個場景,在場景的MainCamera下掛在上該腳本,然后把ColorAdjustEffect的shader賦給腳本的shader槽,如下圖所示:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

首先將亮度,對比度,飽和度都置為1,場景如下所示:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

調(diào)整亮度的圖像效果如下:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

調(diào)整對比度效果如下:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

調(diào)整飽和度的情況如下圖:

Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整

以上是“Unity Shader后處理中如何實(shí)現(xiàn)簡單的顏色調(diào)整”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI