UnityShader-屏幕后處理(調節(jié)亮度,飽和度,對比度)

一、什么是屏幕后處理

在渲染完整個場景得到屏幕圖像后,再對這個圖像進行一系列的操作,實現各種屏幕特效。常用于處理景深、描邊,圖像模糊等特效。

二、實現原理

想要實現屏幕后處理的基礎在于得到渲染后的整個屏幕的圖像,即抓取屏幕,在Unity中為我們提供了一個方便的接口——OnRenderImage函數:
MonoBehaviour.OnRenderImage(RenderTexture src, RenderTexture dest)
src表示源紋理,即沒有經過處理之前的紋理,dest表示目標紋理,即處理后的紋理,
目標紋理可以在Camera中的Target Texture設置,如下圖:


TargetTexture.png

默認情況下OnRenderImage是在整個屏幕渲染完以后(也就是在不透明和透明物體之后都渲染完以后)調用,在一些特殊的情況下,我們需要在渲染完不透明物體的Pass(即渲染隊列小于等于2500的pass,例如內置的
AlphaTest,Background,Geometry,等都在這個范圍內)后立即就調用OnRenderImage,換句話說就是我們不希望將透明物體也包括在屏幕后處理中,這時我們需要在OnRenderImage函數前面添加[ImageEffectOpaque]屬性來達到目的。

在OnRenderImage函數中我們通常通過Graphics.Blit函數對紋理進行處理,它有3種函數聲明:
Graphics.Blit(Texture src,RenderTexture dest);
Graphics.Blit(Texture src,RenderTexture dest,Material mat ,int pass = -1);
Graphics.Blit(Texture src,Material mat ,int pass = -1);
src表示當前屏幕紋理或者上一步處理后得到的渲染紋理,dest表示目標渲染紋理,如果他的值為null,那么就會直接將處理后的紋理渲染到屏幕上面。mat是使用的材質,這個材質使用的shader將會對源紋理進行各種特效處理。而源紋理(src)將會被傳遞給shader中的_MainTex的紋理屬性。pass的默認參數是-1,表示將會依次調用shader中的每個pass,否則,只會調用給定索引的pass。

三、實例

1、基類實現

在進行屏幕后處理前我們需要一系列的條件檢測,例如當前平臺是否支持渲染紋理和屏幕特效,是否支持當前使用的unity shader等。為此,我們創(chuàng)建一個用于屏幕后處理效果的基類(PostEffectsBase.cs),在實現屏幕效果時,我們只需要繼承這個基類,再實現派生類中不同操作即可。
基類實現PostEffectsBase.cs:

using UnityEngine;
using System.Collections;

//在編輯器狀態(tài)下執(zhí)行該腳本
[ExecuteInEditMode]
//剛需組件(Camera)
[RequireComponent (typeof(Camera))]
public class PostEffectsBase : MonoBehaviour {

    // 在Start()中調用
    protected void CheckResources() {
        bool isSupported = CheckSupport();
        
        if (isSupported == false) {
            NotSupported();
        }
    }

    // 平臺渲染紋理與屏幕特效支持檢測
    protected bool CheckSupport() {
        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) {
            Debug.LogWarning("This platform does not support image effects or render textures.");
            return false;
        }
        
        return true;
    }

    // 當不支持的時候,將腳本的enabled設置為false
    protected void NotSupported() {
        enabled = false;
    }
    
    protected void Start() {
        CheckResources();
    }

    // 檢測Material和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;
        }
    }
}

2、調節(jié)亮度,飽和度,對比度

(1)創(chuàng)建腳本(BrightnessSaturationAndContrast.cs),繼承基類,重寫OnRenderImage函數

using UnityEngine;
using System.Collections;

public class BrightnessSaturationAndContrast : PostEffectsBase {
    //綁定的shader
    public Shader briSatConShader;
    private Material briSatConMaterial;
    public Material material {  
        get {
            //調用基類的CheckShaderAndCreateMaterial方法綁定shader與Material
            briSatConMaterial = CheckShaderAndCreateMaterial(briSatConShader, briSatConMaterial);
            return briSatConMaterial;
        }  
    }
    //亮度值
    [Range(0.0f, 3.0f)]
    public float brightness = 1.0f;

     //飽和度
    [Range(0.0f, 3.0f)]
    public float saturation = 1.0f;
     //對比度
    [Range(0.0f, 3.0f)]
    public float contrast = 1.0f;
    //重寫OnRenderImage方法
    void OnRenderImage(RenderTexture src, RenderTexture dest) {
        if (material != null) {
            //設置shader中的各個值
            material.SetFloat("_Brightness", brightness);
            material.SetFloat("_Saturation", saturation);
            material.SetFloat("_Contrast", contrast);
            //將源紋理通過material處理,復制到目標紋理中
            Graphics.Blit(src, dest, material);
        } else {
            Graphics.Blit(src, dest);
        }
    }
}

(2)編寫Shader特效

Shader "Change Brightness Saturation And Contrast" {
    Properties {
        //Graphics.Blit函數傳入的src
        _MainTex ("Source Texture", 2D) = "white" {}
        //亮度值
        _Brightness ("Brightness", Float) = 1
       //飽和度
        _Saturation("Saturation", Float) = 1
       //對比度
        _Contrast("Contrast", Float) = 1
    }
    SubShader {
        Pass {  
            //關閉深度寫入
            ZTest Always Cull Off ZWrite Off
            
            CGPROGRAM  
            #pragma vertex vert  
            #pragma fragment frag  
              
            #include "UnityCG.cginc"  
            //CG中代碼塊中聲明對應的變量
            sampler2D _MainTex;  
            half _Brightness;
            half _Saturation;
            half _Contrast;
              
            struct v2f {
                float4 pos : SV_POSITION;
                half2 uv: TEXCOORD0;
            };
            //頂點著色器,坐標轉換以及獲取uv值  
            v2f vert(appdata_img v) {
                v2f o;
                
                o.pos = UnityObjectToClipPos(v.vertex);
                
                o.uv = v.texcoord;
                         
                return o;
            }
            //片元著色器
            fixed4 frag(v2f i) : SV_Target {
                //紋理采樣
                fixed4 renderTex = tex2D(_MainTex, i.uv);  
                  
                // 亮度值調整
                fixed3 finalColor = renderTex.rgb * _Brightness;
                
                // 該像素對應的亮度值
                fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
                //使用該亮度值創(chuàng)建一個飽和度為0的顏色
                fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
                //將之前的顏色與該顏色進行插值運算,得到調整飽和度后的顏色
                finalColor = lerp(luminanceColor, finalColor, _Saturation);
                
                // 創(chuàng)建一個對比度度為0的顏色
                fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
                //將之前的顏色與該顏色進行插值運算,得到調整對比度后的顏色
                finalColor = lerp(avgColor, finalColor, _Contrast);
                 //返回最終顏色   
                return fixed4(finalColor, renderTex.a);  
            }  
              
            ENDCG
        }  
    }
    
    Fallback Off
}

(3)返回unity編輯器,將ChangeBrightnessSaturationAndContrast.shader賦值給BrightnessSaturationAndContrast.cs腳本的briSatConShader變量,調整亮度值,飽和度,對比度的值,查看效果

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容