屏幕后处理——亮度.饱和度.对比度

先上图:

亮度调整

饱和度调整

对比度

 

代码主要分成3部分主程

1.PostEffectsBase 在进行屏幕处理之前,我们需要检查一系列条件是否满足,例如当前平台是否支持渲染文理和屏幕特效,是否支持当前使用的unity Shader等。为此,我们创建了一个用于屏幕后处理效果的基类,在实现

各种屏幕特效时,我们只需要继承自该基类,再实现派生类中不同的操作即可。

PostEffectsBase 代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//在编辑器状态下可执行该脚本来查看效果
[ExecuteInEditMode] 
//屏幕后处理特效一般需要绑定在摄像机上
[RequireComponent(typeof(Camera))]
public class PostEffectsBase : MonoBehaviour {

    
    void Start () {
        CheckResources();
    }



    protected void CheckResources()
    {
        bool isSupported = CheckSupport();
        //如果显卡检测 返回false
        if (isSupported == false)
        {
            //NotSupported()方法,即不显示
            NotSupported();
        }
    }
    //检查显卡是否支持
   protected bool CheckSupport()
    {
        //如果显卡不支持图像后期处理
        if (SystemInfo.supportsImageEffects == false)
        {
            //返回false
            return false;
        }
        //如果支持图像后处理,返回true
        return true;
    }
    //图像不显示
    protected void NotSupported()
    {
        enabled = false;
    }


    //CheckShaderAndCreateMaterial函数接受两个参数,第一个参数指定了改特效需要使用的Shader
    //第二个参数则是用于后期处理的材质。该函数首先检查Shader的可用性,检查通过后就返回一个使
    //用了该shader的材质,否则返回null.
    protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
    {   //如果shader为空
        if (shader == null)
        {
            return null;
        }
        //shader.isSupported:能在终端用户的图形卡上运行这个着色器&& 并且存在material 他的shader是我们输入的shader
        if (shader.isSupported && material && material.shader == shader)
        {
            return material;
        }
        
        if (!shader.isSupported)
        {
            return null;
        }
        //上面都不满足的话,重新创建新的材质球
        else
        {
            material = new Material(shader);
            //hideFlags:控制对象销毁的位掩码
            //HideFlags.DontSave对象不会保存到场景中。加载新场景时不会被破坏。
            material.hideFlags = HideFlags.DontSave;
            return material;
        }

    }
  }

 

2.调整屏幕的亮度、饱和度、对比度

代码如下:

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

public class BrightnessSaturationAndContrast : PostEffectsBase
{
    //亮度 对比度 饱和度 参数
    //亮度
    [Range(0.0f, 3.0f)]
    public float brightness = 1.0f;
    //饱和度
    [Range(0.0f, 3f)]
    public float saturation = 1.0f;
    //对比度
    [Range(0.0f, 3f)]
    public float contrast = 1.0f;

    //可以拖入shader
    public Shader m_shader;
    //自定义生成material
    private Material m_material;
    //根据基类写的方法生成material
    public Material material
    {
        get
        {
            m_material = CheckShaderAndCreateMaterial(m_shader, m_material);
            return m_material;
        }
    }

    //定义OnRenderImage函数来进特效处理
    //当OnRenderImage函数被调用的时候,他会检查材质球是否可用。如果可用,就把参数传递给材质,
    //再调用Graphics.Blit进行处理;否则,直接把原图像显示到屏幕上,不做任何处理。
    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);
        }
    }
}

 

 3.shader的代码如下:

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _brightness("brightness",float) = 1
        _saturation("saturation",float) = 1
        _contrast("contrast",float) =1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            ZTest Always 
            Cull Off
            ZWrite Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            half _brightness;
            half _saturation;
            half _contrast;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                //亮度
                fixed4 renderTex = tex2D(_MainTex, i.uv);
                fixed3 finalColor = renderTex.rgb * _brightness;

                //饱和度
                fixed Luminance = 0.215 * 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
        }
    }
}

 

 知识点:

   ♦

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

  src: 原纹理 ,当前屏幕的文理,也是传给材质球的_MainTex的图   

  dest :目标文理,经过shader返回的图 。如果他的值为null就会直接将结果显示在屏幕上

  met:材质球

  pass:默认为-1,表示将依次调用shader内的pass。否则只会调用给定索引的Pass

  ♦lerp函数(a,b,w):很多人都觉得w为0到1范围,然后返回值是a到b之间 其实并不仅仅是这些

看下它的内部算法是:

float3 lerp(float3 a, float3 b, float w)
{
return a + w*(b-a);
}

当w大于1 的时候 ,会按照a到b的规律继续放大他们的差异

所以饱和度跟对比度 增加的时候都是用这种方式来完成的

这里的亮度是直接乘以了一个系数  其实也可以用这种方式来做

只是a为黑色 b为正常颜色 即可

  

 

转载于:https://www.cnblogs.com/baicaishisan/p/7678422.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值