1.后处理基类
//屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效。
//基类的作用有二:检测平台是否支持后处理效果,及创建一个用于处理渲染纹理的材质
/// <summary>
/// 屏幕后处理效果基类
/// </summary>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]//使屏幕后处理效果在编辑窗口也生效
[RequireComponent(typeof(Camera))]//首先,所有屏幕后处理效果都需要绑定在某个摄像机上
public class PostEffectsBase : MonoBehaviour
{
/// <summary>
/// 检测资源,如果不支持,关闭脚本活动
/// </summary>
protected void Start()
{
if (CheckSupport() == false)
enabled = false;
}
/// <summary>
/// 检测平台是否支持图片渲染
/// </summary>
/// <returns></returns>
protected bool CheckSupport()
{
if (SystemInfo.supportsImageEffects == false)
{
Debug.LogWarning("This platform does not support image effects or render textures.");
return false;
}
return true;
}
protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
// 指定一个Shader来创建一个用于处理渲染纹理的材质
//第一个参数指定了该特效需要使用的Shader,第二个参数则是用于后期处理的材质。
{
if (shader == null || !shader.isSupported)
return null;
if (material && material.shader == shader)
return material;
material = new Material(shader);
material.hideFlags = HideFlags.DontSave;
return material;
}
}
2.饱和度对比度亮度调节后处理效果
(1)c#(挂载到相机)
//摄像机脚本
using UnityEngine;
using System.Collections;
public class BrightnessSaturation : PostEffectsBase//继承之前创建的基类
{
//声明需要的shder并创建相应材质(也可以在基类里写这些)
public Shader briSatConShader;//要在编辑器里挂一下相关shader
private Material briSatConMaterial;
public Material material
{
get
{
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;
//Unity为我们提供了这样一个方便的接口——OnRenderImage函数
//当我们在脚本中声明此函数后,Unity会把当前渲染得到的图像存储在第一个参数对应的源渲染纹理src中,即未处理的屏幕截屏
//通过函数中的一系列操作后,再把目标渲染纹理,即第二个参数dest对应的渲染纹理显示到屏幕上。
//处理src成为dest的函数,是Graphics.Blit函数。
void OnRenderImage(RenderTexture src, RenderTexture dest)//当前渲染得到的图像(处理前),目标渲染纹理(处理后)
{
if (material != null)
//检查材质是否可用。如果可用,就把参数传递给材质,再调用Graphics.Blit进行处理;否则,直接把原图像显示到屏幕上,不做任何处理。
{
material.SetFloat("_Brightness", brightness);
material.SetFloat("_Saturation", saturation);
material.SetFloat("_Contrast", contrast);
Graphics.Blit(src, dest, material);//我们通常是利用Graphics.Blit函数来完成对渲染纹理的处理。
//参数src对应了源纹理,在屏幕后处理技术中,这个参数通常就是当前屏幕的渲染纹理或是上一步处理后得到的渲染纹理。
//src纹理将会被传递给Shader中名为_MainTex的纹理属性。
//参数dest是目标渲染纹理,如果它的值为null就会直接将结果显示在屏幕上。
//参数mat是我们使用的材质,这个材质使用的Unity Shader将会进行各种屏幕后处理操作
//参数pass的默认值为-1,表示将会依次调用Shader内的所有Pass。否则,只会调用给定索引的Pass。
}
else
{
Graphics.Blit(src, dest);//材质不可用。直接把原图像显示到屏幕上,不做任何处理。
}
}
}
(2)shader
//饱和度等改变
Shader "Custom/Brightness Saturation And Contrast" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}//Graphics.Blit(src, dest, material)将把第一个参数传递给Shader中名为_MainTex的属性
//下面调节的参数都通过摄像机脚本获得(material.SetFloat("_Brightness", brightness);
_Brightness ("Brightness", Float) = 1
_Saturation("Saturation", Float) = 1
_Contrast("Contrast", Float) = 1
}
SubShader {
Pass {
ZTest Always
Cull Off
ZWrite Off
//屏幕后处理实际上是在场景中绘制了一个与屏幕同宽同高的四边形面片,为了防止它对其他物体产生影响,我们需要设置相关的渲染状态。
//关闭了深度写入,是为了防止它“挡住”在其后面被渲染的物体
//例如,如果当前的OnRenderImage函数在所有不透明的Pass执行完毕后立即被调用,不关闭深度写入就会影响后面透明的Pass的渲染
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
half _Brightness;
half _Saturation;
half _Contrast;
//struct a2v...
//使用了Unity内置的appdata_img结构体作为顶点着色器的输入,它只包含了图像处理时必需的顶点坐标和纹理坐标等变量。
struct v2f {
float4 pos : SV_POSITION;
half2 uv: TEXCOORD0;
};
v2f vert(appdata_img v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.te