先上图:
亮度调整
饱和度调整
对比度
代码主要分成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为正常颜色 即可