后处理就是在相机在最终渲染之前再对这个图片做一个整体处理。主要用到 OnRenderImage
函数和 Graphics.Blit
。
颜色矫正
明度调节 饱和调节 对比调节代码比较简单,书中将整个屏幕后处理都提出了一个父类出来,当然也可以直接像我这样。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class ColorCorrectCtl : MonoBehaviour {
public Shader colorCorrectShader;
private Material material;
[Range(0,5)]
public float brightness = 1;
[Range(0, 5)]
public float saturation = 1;
[Range(0, 5)]
public float contrast = 1;
// Use this for initialization
private void Start () {
Init();
}
private 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);
}
}
/// <summary>
/// 检查 Shader 是否可用并且创造材质球
/// </summary>
/// <returns></returns>
private bool Init()
{
if (colorCorrectShader.isSupported)
{
material = new Material(colorCorrectShader);
return true;
}
else
{
Debug.LogError("Shader 不支持", gameObject);
return false;
}
}
}
Shader "ZhangQr/ColorCorrect"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
// 因为那几个参数不用在 Shader 的界面控制,所以不需要写
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
ZWrite Off // 不然如果不透明的物体渲染在后处理之后,那么就会出错
Cull Off // 其实不关也可以吧
ZTest Always // 这句不写的话,不能在编辑器模式下运行,即便在脚本中写了 [ExecuteInEditMode]
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Brightness; // 亮度
float _Saturation; // 饱和度
float _Contrast; // 对比色
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
// 亮度
fixed3 retCol = col.rgb * _Brightness;
// 对比度
float luminance = 0.2125f * col.r + 0.7154f * col.g + 0.0721f * col.b;
fixed3 saturation = fixed3(luminance,luminance,luminance);
retCol = lerp(saturation,retCol,_Saturation);
// 对比度
fixed3 contrast = fixed3(0.5,0.5,0.5);
retCol = lerp(contrast,retCol,_Contrast);
UNITY_APPLY_FOG(i.fogCoord, col);
return fixed4(retCol,col.a);
}
ENDCG
}
}
}
Shader 里面的 lerp
跟 C# 里面的还是有点不一样,后者 t 只能从 0-1,但前者应该是 0-正无穷吧。所以其实对于饱和和对比来说,都是只需要知道一个下限然后使用插值就能自动弥补一些东西,做成非常好看的效果,饱和的下限是一张黑白图:
它是根据人眼对于颜色的敏感度不同计算出来的,也就是
float luminance = 0.2125f * col.r + 0.7154f * col.g + 0.0721f * col.b
。对比的下限是灰色,也就是 0.5r,0.5g,0.5b。如下图:
灰色
总结一下就是插值真是个好东西。
网友评论