這篇文章主要為大家展示了“Unity Shader后處理中如何實(shí)現(xiàn)簡(jiǎn)單的顏色調(diào)整”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Unity Shader后處理中如何實(shí)現(xiàn)簡(jiǎn)單的顏色調(diào)整”這篇文章吧。
創(chuàng)新互聯(lián)是專業(yè)的宕昌網(wǎng)站建設(shè)公司,宕昌接單;提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行宕昌網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
我們?cè)谧鲇螒虻臅r(shí)候,雖然現(xiàn)在有了Unity等引擎,不用我們自己處理一些繁瑣的東西,但是不管怎么樣,最后顯示在屏幕上的還是一些RGB的像素信息,了解這些基本的概念,肯定對(duì)我們做游戲有更大的幫助。
既然是校正屏幕的顏色,我們有必要了解一下我們要校正的這幾個(gè)屬性的概念。這里就不得不提到我們常用的顏色定義方式,RGB顏色模型和HSV顏色模型。
RGB顏色模型也就是我們最常用的三原色,紅綠藍(lán)。RGB顏色模型在混色時(shí)屬于加法混色,RGB中每種顏色數(shù)值越高,色彩越明亮。RBG為(0,0,0)時(shí)為黑色,RGB為(255,255,255)時(shí)為白色。計(jì)算機(jī)在處理顏色信息時(shí)一般都采用RGB顏色模型,可以很精確地表示某種顏色。
RGB顏色模型對(duì)于計(jì)算機(jī)來(lái)說(shuō)很容易計(jì)算,但是并不適合人類理解,于是就有了HSV顏色模型,所謂HSV代表的是Hue(色相),Saturation(飽和度),Value(色調(diào))也有一種說(shuō)法是HSB模型,B代表的是Brightness(明度)。當(dāng)然,還有一些說(shuō)法,比如HSL模型,L代表的是Lightness(亮度)。HSV模型使用一個(gè)圓錐形坐標(biāo)系,頂面對(duì)應(yīng)的V(Value色調(diào))為1,表示顏色較亮,底面的Value為0,表示顏色較暗;而H(Hue色相)是由繞著V軸的旋轉(zhuǎn)角度給定,從紅色開(kāi)始逆時(shí)針?lè)较蛴?jì)算,紅色對(duì)應(yīng)0度,綠色對(duì)應(yīng)120度,藍(lán)色對(duì)應(yīng)240度;S(Saturation飽和度)由模型的半徑來(lái)代表,由內(nèi)向外Saturation逐漸增大,圓心處為0,邊緣處為1。下圖是HSV顏色模型的圖示:
既然兩種顏色模型都可以表示顏色,那么兩者之間一定有某種轉(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)系如下:
圖像中RGB值的大小,RGB各個(gè)值越大,那么亮度越亮,越小,亮度越暗。比如我們要增加亮度,那么直接增加RGB值即可。
指的是顏色的純度。一般用彩度除以明度,表征彩色偏離同亮度灰色的程度。簡(jiǎn)單來(lái)說(shuō),當(dāng)顏色越偏向某個(gè)值,即越偏離灰度,飽和度越大;當(dāng)顏色越偏向灰度,飽和度越小。
下面是百度百科關(guān)于飽和度的一段定義:
飽和度是指色彩的鮮艷程度,也稱色彩的純度。飽和度取決于該色中含色成分和消色成分(灰色)的比例。含色成分越大,飽和度越大;消色成分越大,飽和度越小。純的顏色都是高度飽和的,如鮮紅,鮮綠?;祀s上白色,灰色或其他色調(diào)的顏色,是不飽和的顏色,如絳紫,粉紅,黃褐等。完全不飽和的顏色根本沒(méi)有色調(diào),如黑白之間的各種灰色
指的是一幅圖像中明暗區(qū)域最亮的白和最暗的黑之間不同亮度層級(jí)的測(cè)量,差異范圍越大代表對(duì)比越大,差異范圍越小代表對(duì)比越小。一般來(lái)說(shuō)對(duì)比度越大,圖像越清晰醒目,色彩也越鮮明艷麗;而對(duì)比度小,則會(huì)讓整個(gè)畫(huà)面都灰蒙蒙的。
灰度使用黑色調(diào)表示物體,即用黑色為基準(zhǔn)色,不同的飽和度的黑色來(lái)顯示圖像。 每個(gè)灰度對(duì)象都具有從 0%(白色)到100%(黑色)的亮度值。
了解了一些基本的色彩概念,我們就可以開(kāi)始進(jìn)行處理了。首先我們看一下Unity后處理效果的原理。
所謂屏幕后處理,簡(jiǎn)單來(lái)說(shuō)就是渲染流水線的最后階段,對(duì)由整個(gè)場(chǎng)景生成的一張圖片進(jìn)行處理,比如HDR,運(yùn)動(dòng)模糊等等效果,通過(guò)屏幕空間的后處理,可以整體改變整個(gè)游戲的風(fēng)格或者效果。所以,要制作屏幕后處理,我們需要兩樣?xùn)|西,一個(gè)是用于渲染后處理效果的shader,而另一個(gè)是我們需要調(diào)用這個(gè)渲染的腳本,好在Unity為我們提供了相關(guān)的功能。
該函數(shù)在MonoBehaviour中提供,該函數(shù)在所有渲染完成后才進(jìn)行調(diào)用,也就是我們上文所說(shuō)的生成了一張場(chǎng)景圖片,函數(shù)的原型如下:
void OnRenderImage(RenderTexture sourceTexture,RenderTexture destTexture);
RenderTexture表示的是渲染紋理,我們渲染物體并不是僅僅渲染在屏幕空間,也可以將物體渲染到特定紋理上,也就是RenderTexture。sourceTexture就是我們渲染的場(chǎng)景圖片,而destTexture是目標(biāo)渲染紋理。我們可以在這個(gè)函數(shù)中進(jìn)行相關(guān)的后處理效果,使用帶有后處理效果shader的材質(zhì)將場(chǎng)景內(nèi)容重新渲染。
該函數(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時(shí),直接將源紋理拷貝到屏幕;mat是拷貝時(shí)使用的材質(zhì),也就是我們后處理時(shí)使用的材質(zhì),Unity會(huì)使用該材質(zhì)將源紋理進(jìn)行處理拷貝給目標(biāo)紋理,pass是使用的材質(zhì)shader所使用的pass,我們知道,一個(gè)shader中可能有多個(gè)pass,使用哪個(gè)pass進(jìn)行處理就可以從該參數(shù)傳入,當(dāng)然,默認(rèn)為-1時(shí)表示所有的pass都會(huì)執(zhí)行。
在了解了Untiy的后處理流程后,我們就可以著手寫(xiě)我們的亮度對(duì)比度飽和度調(diào)整后處理了。
后處理效果需要兩部分,分別是腳本部分和shader部分,我們分別來(lái)看一下。
后處理腳本主要做的是兩件事,第一件是獲取需要的shader,生成材質(zhì),第二件是通過(guò)OnRenderImage使用材質(zhì)處理屏幕效果。第一步具有一些普遍性,不管是什么后處理效果,都要有這一步相同的操作,所以我們將該步驟抽離出來(lái),創(chuàng)建一個(gè)后處理效果的基類PostEffectBase,代碼如下:
using UnityEngine; using System.Collections; //非運(yùn)行時(shí)也觸發(fā)效果 [ExecuteInEditMode] //屏幕后處理特效一般都需要綁定在攝像機(jī)上 [RequireComponent(typeof(Camera))] //提供一個(gè)后處理的基類,主要功能在于直接通過(guò)Inspector面板拖入shader,生成shader對(duì)應(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,就都自動(dòng)具有了通過(guò)shader生成后處理材質(zhì)的功能。
接下來(lái)就是我們這一篇的亮度,飽和度,對(duì)比度調(diào)整的腳本,腳本很簡(jiǎn)單,主要的功能就在于設(shè)置幾個(gè)參數(shù),覆寫(xiě)OnRenderImage函數(shù)后將參數(shù)實(shí)時(shí)傳入shader,然后通過(guò)Blit函數(shù)完成后處理效果,代碼如下:
using UnityEngine; using System.Collections; //繼承自PostEffectBase public class ColorAdjustEffect : PostEffectBase { //通過(guò)Range控制可以輸入的參數(shù)的范圍 [Range(0.0f, 3.0f)] public float brightness = 1.0f;//亮度 [Range(0.0f, 3.0f)] public float contrast = 1.0f; //對(duì)比度 [Range(0.0f, 3.0f)] public float saturation = 1.0f;//飽和度 //覆寫(xiě)OnRenderImage函數(shù) void OnRenderImage(RenderTexture src, RenderTexture dest) { //僅僅當(dāng)有材質(zhì)的時(shí)候才進(jìn)行后處理,如果_Material為空,不進(jìn)行后處理 if (_Material) { //通過(guò)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); } } }
這樣,我們的后處理腳本就完成了。涉及到以下幾個(gè)知識(shí)點(diǎn):
1.可以通過(guò)[Range(min,max)]來(lái)控制Inspector面板中的值,限定其范圍,并提供滑動(dòng)條控制。
2.OnRenderImage函數(shù)每幀渲染完全部?jī)?nèi)容后執(zhí)行,我們?cè)诿恳粠O(shè)置Material的各項(xiàng)參數(shù),通過(guò)Material.SetXXX("name",value)可以向shader中傳遞各種參數(shù)。
3.各種后處理效果可以疊加,這里的dest并不一定就是屏幕。不過(guò)后處理是很耗費(fèi)性能的,一方面是pixel shader全屏幕overdraw,另一方面,一個(gè)rendertexture的內(nèi)存占用很大,尤其是大分辨率手機(jī)上,多個(gè)后處理效果可能造成內(nèi)存耗盡,程序崩潰。
終于步入正題了,下面看一下后處理效果的shader。由于后處理效果是對(duì)于一個(gè)場(chǎng)景的渲染圖進(jìn)行處理,所以vertex shader基本沒(méi)有什么好說(shuō)的,大部分后處理都是基于pixel shader。先整理一下思路:
最簡(jiǎn)單的是亮度,我們可以直接在采樣texture后乘以一個(gè)系數(shù),達(dá)到放大或者縮小rgb值的目的,這樣就可以調(diào)整亮度了。
其次是飽和度,飽和度是離灰度偏離越大,飽和度越大,我們首先可以計(jì)算一下同等亮度條件下飽和度最低的值,根據(jù)公式:gray = 0.2125 * r + 0.7154 * g + 0.0721 * b即可求出該值(公式應(yīng)該是一個(gè)經(jīng)驗(yàn)公式),然后我們使用該值和原始圖像之間用一個(gè)系數(shù)進(jìn)行差值,即可達(dá)到調(diào)整飽和度的目的。
最后是對(duì)比度,對(duì)比度表示顏色差異越大對(duì)比度越強(qiáng),當(dāng)顏色為純灰色,也就是(0.5,0.5,0.5)時(shí),對(duì)比度最小,我們通過(guò)在對(duì)比度最小的圖像和原始圖像通過(guò)系數(shù)差值,達(dá)到調(diào)整對(duì)比度的目的。代碼如下:
//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 } //每個(gè)shader都有Subshaer,各個(gè)subshaer之間是平行關(guān)系,只可能運(yùn)行一個(gè)subshader,主要針對(duì)不同硬件 SubShader { //真正干活的就是Pass了,一個(gè)shader中可能有不同的pass,可以執(zhí)行多個(gè)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:帶有位置和一個(gè)紋理坐標(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亮度直接乘以一個(gè)系數(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對(duì)比度:首先計(jì)算對(duì)比度最低的值 fixed3 avgColor = fixed3(0.5, 0.5, 0.5); //根據(jù)Contrast在對(duì)比度最低的圖像和原圖之間差值 finalColor = lerp(avgColor, finalColor, _Contrast); //返回結(jié)果,alpha通道不變 return fixed4(finalColor, renderTex.a); } ENDCG } } //防止shader失效的保障措施 FallBack Off }
完成shader和后處理腳本后,我們可以創(chuàng)建一個(gè)場(chǎng)景,在場(chǎng)景的MainCamera下掛在上該腳本,然后把ColorAdjustEffect的shader賦給腳本的shader槽,如下圖所示:
首先將亮度,對(duì)比度,飽和度都置為1,場(chǎng)景如下所示:
調(diào)整亮度的圖像效果如下:
調(diào)整對(duì)比度效果如下:
調(diào)整飽和度的情況如下圖:
以上是“Unity Shader后處理中如何實(shí)現(xiàn)簡(jiǎn)單的顏色調(diào)整”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前名稱:UnityShader后處理中如何實(shí)現(xiàn)簡(jiǎn)單的顏色調(diào)整
URL地址:http://aaarwkj.com/article40/gppdeo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、企業(yè)建站、品牌網(wǎng)站建設(shè)、外貿(mào)建站、網(wǎng)站收錄、關(guān)鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)