亮度:
屏幕后处理脚本:
using UnityEngine;
using System.Collections;
//继承基类
public class BrightnessSaturationAndContrast : PostEffectsBase {
public Shader briSatConShader; //声明Shader
private Material briSatConMaterial; //创建材质
public Material material {
//调用基类CheckShaderAndCreateMaterial函数来得到对应的材质
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; //对比度
//实现真正的特效处理
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);
}
}
}
每当OnRenderlmage函数被调用时,它会检查材质是否可用。如果可用,就把参数传递给材质,再调用Graphics.Blit进行处理;否则,直接把原图像显示到屏幕上,不做任何处理。
Shader代码如下:
Shader "Unity Shaders Book/Chapter 12/Brightness Saturation And Contrast" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Brightness ("Brightness", Float) = 1
_Saturation("Saturation", Float) = 1
_Contrast("Contrast", Float) = 1
}
SubShader {
//定义用于屏幕后处理的Pass
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);
// Apply brightness
fixed3 finalColor = renderTex.rgb * _Brightness;
// Apply saturation
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);
// Apply contrast
fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
finalColor = lerp(avgColor, finalColor, _Contrast);
return fixed4(finalColor, renderTex.a);
}
ENDCG
}
}
Fallback Off
}
Graphics.Blit(sre, dest, material)将把第一一个 参数传递给Shader中名为_MainTex的属性。因此,我们必须声明-一个名为_MainTex 的纹理属性。除此之外,我们还声明了用于调整亮度、饱和度和对比度的属性,这些值将会由脚本传递而得。事实上,我们可以省略Proerties中的属性声明,Properties 中声明的属性仅仅是为了显示在材质面板中,但对于屏幕特效来说,它们使用的材质都是临时创建的,我们也不需要在材质面板上调整参数,而是直接从脚本传递给Unity Shader。
屏幕后处理实际上是在场景中绘制了一个与屏幕同宽同高的四边形面片,为了防止它对其他物体产生影响,我们需要设置相关的渲染状态。在这里,我们关闭了深度写入,是为了防止它“挡住”在其后面被渲染的物体。例如,如果当前的OnRenderlmage函数在所有不透明的Pass执行完毕后立即被调用,不关闭深度写入就会影响后面透明的Pass 的渲染。这些状态设置可以认为是用于屏幕后处理的Shader 的“标配”。
appdata_img是Unity的内置结构体,质保函图像处理时必需的顶点坐标和纹理坐标等变量。
片元着色器处理:
亮度调整:将原颜色乘以亮度系数_Brightness即可。
饱和度调整:计算该像素对应的亮度值(luminance), 这是通过对每个颜色分量乘以-一个特定的系数再相加得到的。我们使用该亮度值创建了一个饱和度为0的颜色值,并使用_Saturation属性在其和上一步得到的颜色之间进行插值,从而得到希望的饱和度颜色。
对比度调整:首先创建一个对比度为0的颜色值(各分量均为0.5),再使用_ Contrast 属性在其和上一步得到的颜色之间进行插值,从而得到最终的处理效果。