【Unity Shader】从数值角度分析颜色调整(亮度、对比度和饱和度)

您所在的位置:网站首页 屏幕的饱和度怎么调整比例不变 【Unity Shader】从数值角度分析颜色调整(亮度、对比度和饱和度)

【Unity Shader】从数值角度分析颜色调整(亮度、对比度和饱和度)

2024-07-07 03:41| 来源: 网络整理| 查看: 265

第一次写博客。

因为前段时间看《Unity Shader入门精要》时,不理解12章第2节中luminance值计算公式的原理,书中也没有对此进行详尽解释,同时在网上也很难查阅到相关的资料。但在查阅了一些数字图像处理相关的知识后,也终于理解了其中的原理,所以打算写篇博客分享一下我个人对此的理解。

一、颜色模型

因为网上有很多关于颜色模型相关概念、知识的资料,所以在此我就不做详细介绍了,在这只简单介绍一下本文的主角RGB颜色模型。

RGB全称是Red、Green、Blue,即红绿蓝三色,是最常见最常用的三原色。通过混合不同比例的红绿蓝三原色,可以得到自然界中我们能看到的绝大多数颜色。

为了方便定义混色的比例,同时因为在给颜色分级的时候大部分芯片是八位的,所以把每种颜色按亮度分为0~255共256个等级,即RGB值。

RGB值越小时,对应颜色越暗;RGB值越大时,对应颜色越亮。因此不难理解为什么RGB(0,0,0)是黑色,RGB(255,255,255)是白色。

在Unity Shader中,把RGB值从[0,255]映射到了[0,1]之中,套用  1÷256×对应颜色RGB值  计算公式,同时采用  2舍3入  的计数保留法就能得到该颜色在Unity中的数值表示。

举个栗子:

1、首先在PS中随便调一个不常见的颜色

2、然后使用上面的公式计算这个颜色RGB值在Unity Shader中的映射值

R: 1/256*124 ≈ 0.485 G: 1/256*132 ≈ 0.516 B: 1/256* 88  ≈ 0.344

3、接着在Unity Shdaer的片元着色器中直接输出这三个值

 4、下图是该颜色值在Unity中的显示,大家可以用截屏软件在截屏时自带的RGB吸色功能对比一下两张色图()的RGB值是否是一致的。

二、Unity Shader的Lerp()函数

在正式讲解亮度、饱和度和对比度的调整原理前,先来聊聊Unity Shader中Lerp()函数这个坑。关于Lerp()函数公式在这里就不做过多的解释了,网上也有很多相关资料。

lerp(a, b, w);

这里主要想说的是这个函数输入值w的区间与其他大多数博客中所说的根本就不一样!

只要在搜索引擎中搜索“unity lerp函数”,查到的博客、资料都会跟你说w值只能是0~1之间的数,有的博客还会说如果你输入的w值超出了[0,1],就会被限制为0或者1。

所以我当时就很懵,因为在《Unity Shader入门精要》中输入的w值都超过了[0,1]这个区间

 后来我发现,其实Unity Shader中的Lerp()函数是把a~b之间的差值等分为了无数份,这是因为0~1之间能等分为多少份不可估量。这时就能根据w值在[0,1]中的什么位置,来定义Lerp()应该输出什么值。

当w1时,输出的值就是 输入值b加上每一份的差值。也就是因为Lerp()函数有这个独特的性质,才能用来调整颜色的亮度、饱和度和对比度。

三、亮度

从最简单的亮度开始分析。

//《Unity Shader入门精要》中的原代码。其中_Brightness是亮度值 fixed3 finalColor = renderTex.rgb * _Brightness;  

上文说到[0,255]这256个等级是每种颜色的亮度等级,同时Unity Shader把RGB值从[0,255]映射到了[0,1]。

因此不难理解此处的代码实则是对对应像素的RGB值进行了一个统一缩放,在保证了三原色的混合比例不变的情况下,改变了对应颜色的明暗度。

四、对比度 

对比度,实际上指的是一个画面中显示的  RGB值最大的像素  与  RGB值最小的像素  之间的差值的大小,也就是最亮的像素与最暗的像素之间的差值,因此称为对比度。

//《Unity Shader入门精要》中的原代码。其中_Contrast是对比度值fixed3 avgColor = fixed3(0.5, 0.5, 0.5); finalColor = lerp(avgColor, finalColor, _Contrast); 

此处使用fixed3(0.5, 0.5, 0.5)是因为0.5是[0,1]之间的中值,使用0.5对原RGB值进行插值。

当_Contrast1时,画面中所有的像素RGB值都会离0.5越来越远,此时画面中最亮的像素与最暗的像素之间的差值就逐渐增大,也就是对比度逐渐变大。

这也是PS中的旧版对比度算法原理。

五、饱和度

“纯度是指色彩的纯净程度,也就是色彩的饱和度。物体的饱和度取决于该物体表面选择性的反射能力。在同一色相中添加白色、黑色或灰色都会降低它的纯度。”

--《平面设计配色从入门到精通》曹茂鹏

//《Unity Shader入门精要》中的原代码。其中_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);

因为有Lerp()函数的存在,只要我们能得到目标像素饱和度为0时的RGB值,当_Saturation>1时,利用Lerp()函数的性质,就能起到增大目标像素颜色饱和度的作用。

由上面的饱和度概念可推,往一种颜色中添加大量的黑白灰色,当该颜色中的黑白灰色的量远大于原颜色的量时,可以认为该颜色的灰度值就是该颜色饱和度为0时的RGB值。因此,当一个画面饱和度为0时,得到的应该是该画面对应的灰度图。

PS中的饱和度调整:

代码中luminance值的计算公式求的就是目标像素RGB颜色值对应的灰度等级。

0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b

对于这条公式,我后来查找到该公式是RGB转YUV的BT709明亮度转换公式,是基于人眼感知的图像灰度处理公式。这条公式通过计算每个像素RGB值对应的灰度值,来把RGB彩色图像转换为灰度图。

YUV颜色模型起初是用于解决彩色电视和黑白电视兼容性问题,其中的Y值表示明亮度,也是灰阶值,这里的luminance值其实就是这个Y值。

对于这个公式的三个系数为什么不是0.5,0.5,0.5,而是0.2125,0.7154,0.0721。那是因为人眼对红绿蓝三色的敏感程度不同,所以计算灰度的时候要加权平均。这个系数主要是根据人眼对R,G,B三原色的敏感性不同而导出的系数。如果想知道更多详细信息可以查阅“色度学”相关资料。

类似的,还有如下公式:

Y = 0.299*R + 0.587*G + 0.114*B

虽然这条公式与上一条公式在系数上有很大的不同,但是实际上得到的灰度图结果仅以我们人类肉眼来看,很难看出其中的不同。因此,在计算一个画面时,使用上面哪条公式都是OK的。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3