Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

亮度、饱和度、对比度

在屏幕后处理的Shader中 需要设置深度测试、剔除、深度写入 - ZTest Always 打开深度测试 - Cull Off 关闭剔除 - ZWrite Off 关闭深度写入 主要是避免它"挡住"后面的渲染物体

1.基本原理

1.亮度


想要改变颜色的亮度
只需要对图像的每个像素点进行加法运算或乘法运算即可


也就是说,我们只需要在Shader当中加入一个控制亮度的float类型的变量
然后用颜色的RGB乘以该变量即可
一般我们会采用乘法的形式
即:
最终颜色 = 源颜色 * 亮度变量

2.饱和度


想要改变颜色的饱和度
只需要对图像的每个像素的颜色值 相对于灰度颜色进行插值来实现

基本原理如下: 1. 计算灰度值
利用图像的颜色RGB计算一个平均值,得到一个灰度值
但是由于人眼对不同的颜色敏感程度不同,所以一般不会直接计算平均值
图形学中一般使用加权平均法来计算灰度值
常用的权重基于Rec,790标准(高清电视和许多数字图像格式中常用标准) - R 红色通道权重 0.2126 - G 绿色通道权重 0.7152 - B 蓝色通道权重 0.0722
所以计算灰度值公式:
灰度值L = 0.2126 * R + 0.7152 * G + 0.0722 * B 2. 生成灰度颜色
利用第一步中计算出来的灰度值,生成一个灰度颜色
灰度颜色 = (L,L,L) 3. 插值计算
使用插值函数,在灰度颜色和原始颜色之间进行插值计算
插值系数就是用于控制饱和度的float类型变量
最终颜色 = lerp(灰度颜色,源颜色,饱和度变量) - 饱和度变量=0时,结果为灰度颜色 - 饱和度变量=1时,保持原始颜色不变 - 饱和度变量=0~1之间时,灰度颜色和原始颜色的混合 - 饱和度变量 >1时,颜色的RGB值超出原始范围,从而使颜色看起来更饱和

3.对比度


想要改变图像颜色的的对比度
只需要对图像的每个像素的颜色值 相对于中性灰色进行插值来实现

基本原理: 1. 声明中性颜色变量 即:RGB都为0.5的颜色变量
中性颜色 = (0.5,0.5,0.5) 2. 插值计算
使用插值函数,在灰度颜色和原始颜色之间进行插值计算
插值系数就是用于控制对比度的float类型变量
最终颜色 = lerp(中性颜色,源颜色,对比度变量) - 对比度变量 = 0 时,此时对比度降到最低,变为中性灰色 - 对比度变量 = 1时,保持原始颜色不变 - 对比度变量 0~1 之间时,降低对比度效果,图像的亮度差异减少,使图像颜色看起来更平淡 - 对比度变量 >1时,颜色的RGB值超出原始范围,从而使颜色亮部更亮,暗部更暗,从而增加对比度

2.实现示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
Shader "Unlit/BrightnessSaturationContrast"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
//亮度变量
_Brightness("Brightness",Float) = 1
//饱和度变量
_Saturation("Sturation",Float) = 1
//对比度变量
_Contrast("Contrast",Float) = 1

}
SubShader
{
Tags{"RenderType"="Opaque"}
Pass
{
//这三个设置是屏幕后处理的标配
ZTest Always
Cull Off
ZWrite Off

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"


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

sampler2D _MainTex;
float4 _MainTex_ST;
half _Brightness;
half _Saturation;
half _Contrast;

v2f vert(appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
return o;
}

fixed4 frag(v2f i) : SV_Target
{
//从捕获的主纹理进行采样
fixed4 renderTexColor = tex2D(_MainTex, i.uv);
//亮度计算
fixed3 finalColor = renderTexColor.rgb * _Brightness;
//饱和度计算
fixed L = dot(finalColor, fixed3(0.2126, 0.7152, 0.0722));
fixed3 LCOlor = (L,L,L);
finalColor = lerp(LCOlor, finalColor, _Saturation);
//对比度计算
fixed3 avgColor = fixed3(0.5,0.5,0.5);
finalColor = lerp(avgColor, finalColor, _Contrast);
return fixed4(finalColor.rgb, 1);
}
ENDCG
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BrightnessSaturationContrast : PostEffectBase
{
[Range(0,5)]
public float brightness = 1;
[Range(0,5)]
public float saturation = 1;
[Range(0,5)]
public float constrast = 1;

protected override void OnRenderImage(RenderTexture source, RenderTexture destination)
{
base.OnRenderImage(source, destination);
}
/// <summary>
/// 更新相关属性
/// </summary>
protected override void UpadateProerty()
{
if (material != null)
{
material.SetFloat("_Brightness", brightness);
material.SetFloat("_Saturation", brightness);
material.SetFloat("_Constrast", brightness);
}
}
}

评论