UnityShader之屏幕特效基礎


1、什么是屏幕特效

我們這里講的屏幕特效技術,指的是在渲染完整個場景后得到的屏幕圖象的基礎上,再對這個屏幕圖像做一系列處理,實現出屏幕特效,使用這種技術可以為屏幕畫面增添各種風格的藝術效果,比如泛光、景深、模糊等等。
 

2、unity實現屏幕特效的原理

如上所述,要實現屏幕特效,首先要抓取渲染完整個場景得到的屏幕圖像,在unity中,提供了OnRenderImage函數,方便我們進行這樣的操作。它的聲明如下:MonoBehaviour.OnRenderImage(RenderTexture src,RenderTexture dest);unity會把當前渲染得到的圖像存儲在第一個參數對應的渲染紋理中,通過自定義的一系列操作后,得到目標渲染紋理(第二個參數中的渲染紋理),目標渲染紋理會最終顯示在屏幕上。在OnRenderImage函數中,使用Graphics.Blit函數來對渲染紋理進行處理。這里我們做一個可以改變畫面亮度、飽和度、以及對比度的簡單屏幕特效。
 

3、C#腳本實現

////////////////////////////////////////////////////////////////////
//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//                 佛祖保佑          永無BUG                      //
////////////////////////////////////////////////////////////////////


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class ScreenEffect : MonoBehaviour {

    public Shader effectShader;  
    private Material effectMaterial;
    public Material EffectMaterial
    {
        get
        {
            effectMaterial = CreateMaterial(effectShader, effectMaterial);
            return effectMaterial;
        }
    }

    [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;    //對比度


    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (EffectMaterial != null)
        {
            EffectMaterial.SetFloat("_Brightness", brightness);
            EffectMaterial.SetFloat("_Saturation", saturation);
            EffectMaterial.SetFloat("_Contrast", contrast);
            //對渲染紋理進行處理
            Graphics.Blit(src, dest, EffectMaterial);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }

    private void Start()
    {
        bool isSupported = CheckSupport();

        if (isSupported == false)
        {
            this.enabled = false;
        }
    }

   
    // 檢測當前平台是否支持屏幕特效
    private bool CheckSupport()
    {
        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
        {
            Debug.LogWarning("當前平台不支持!");
            return false;
        }
        return true;
    }

    
    // 創建材質
    private Material CreateMaterial(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;
        }
    }
}

4、Shader實現

Shader "yzpShader/ScreenEffect" {
    Properties {
        _MainTex ("Base (RGB)", 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"  
              
            sampler2D _MainTex;  
            half _Brightness;
            half _Saturation;
            half _Contrast;
              
            struct v2f {
                float4 pos : SV_POSITION;
                half2 uv: TEXCOORD0;
            };
              
            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;
                fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
                finalColor = lerp(luminanceColor, finalColor, _Saturation);
                
                // 計算對比度改變后的顏色
                fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
                finalColor = lerp(avgColor, finalColor, _Contrast);
                
                return fixed4(finalColor, renderTex.a);  
            }  
              
            ENDCG
        }  
    }
    
    Fallback Off
}

5、測試結果

首先將C#腳本掛在場景相機上,並將上面寫好的shader拖拽到ScreenEffect腳本的effectShader上,修改該腳本的brightness、saturation、contrast值,可以得出下面這樣的效果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM