【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度
本系列主要參考《Unity Shaders and Effects Cookbook》一书(感谢原书作者),同一时候会加上一点个人理解或拓展。
这里是本书全部的插图。
========================================== 切割线 ==========================================
写在前面
通过上一篇我们建立了一个简化的屏幕特效系统,在这一篇,我们開始学习创建更复杂的像素操作来实现一些在当代游戏中常见的屏幕特效。
使用屏幕特效来调整游戏的总体色彩是非常重要的,这给了设计师控制游戏最后全貌的能力。
比方,通过颜色调整条来调整游戏终于画面的红蓝绿三色的密度,或者通过加入一定的色调使整个屏幕看起来像是老电影那样的效果。
这篇文章里,我们将会很多其它地学习关于调整图像颜色方面的内容。也就是,亮度、饱和度和对照度。学习这些调整颜色的方法能够让我们对屏幕特效有一个非常好的理解。
实现
这一篇非常多代码是建立在上一篇的基础上,所以非常多代码不用写啦~
- 创建一个新的脚本,命名为BSC_ImageEffect;
- 创建一个新的Shader。命名为BSC_Effect。
- 把上一篇中的C#代码拷贝到第一步中创建的脚本中,我们仅仅须要关注亮度、饱和度和对照度效果的运算。
- 把上一篇中的Shader代码拷贝到第二步中创建的Shader中。
- 把新的脚本加入到Camera上,并使用新的Shader给脚本中的Cur Shader赋值。
- 创建一个新的场景,命名为BSC_Effect。加入一个平行光,三个球体。以及一个平面。
创建4个新材质,使用自带的Specular Shader就可以,随意选择四种颜色为它们赋值,这能够使我们更好地检验我们的画面特效。最后。把4个材质赋给球体和平面。
实现
- 加入亮度、饱和度和对照度相应的新的Properties,我们要保留_MainTex属性,这是由于在创建画面特效时。该属性就是脚本传递给我们的render texture。
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_BrightnessAmount ("Brightness Amount", Range(0.0, 2.0)) = 1.0
_SaturationAmount ("Saturation Amount", Range(0.0, 1.0)) = 1.0
_ContrastAmount ("Contrast Amount", Range(0.0, 1.0)) = 1.0
} - 和曾经一样。在CGPROGRAM中建立和上述Properties之间的联系,创建相应的变量:
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag #include "UnityCG.cginc" uniform sampler2D _MainTex;
fixed _BrightnessAmount;
fixed _SaturationAmount;
fixed _ContrastAmoun - 如今,我们须要创建操作来进行真正的亮度、饱和度和对照度的计算。在frag函数上面创建以下的函数:
float3 ContrastSaturationBrightness (float3 color, float brt, float sat, float con) {
// Increase or decrease these values to
// adjust r, g and b color channels separately
float avgLumR = 0.5;
float avgLumG = 0.5;
float avgLumB = 0.5; // Luminance coefficients for getting luminance from the image
float3 LuminanceCoeff = float3 (0.2125, 0.7154, 0.0721); // Operation for brightmess
float3 avgLumin = float3 (avgLumR, avgLumG, avgLumB);
float3 brtColor = color * brt;
float intensityf = dot (brtColor, LuminanceCoeff);
float3 intensity = float3 (intensityf, intensityf, intensityf); // Operation for saturation
float3 satColor = lerp (intensity, brtColor, sat); // Operation for contrast
float3 conColor = lerp (avgLumin, satColor, con); return conColor;
}解释:这个函数的第一个參数是当前的render texture的某个像素。其它參数则是用于总体调整颜色,这些变量会通过后面的脚本传递给Shader。
函数一開始。声明了一些常量。它们被用于定义一个最主要的颜色值,以便和改动后的进行比較。
书上讲这个函数的实现的地方比較含糊不清,看不懂。我按自己的理解解释一下。这事实上是一个叠加的过程:先计算当前亮度值下的像素,再在此基础上计算当前饱和度值下的像素。最后再在此基础上计算当前对照度下的像素,并输出:
—— 当前亮度值下的像素是通过使用render texture上原始的像素乘以亮度值实现的,这非常好理解,brt越大(能够大于1),图像越偏向白色,也就越亮。—— 计算当前饱和度值下的像素。须要使用lerp函数。当中,lerp的右边界值就是上一步得到的像素值,而左边界值是当前亮度下饱和度最低的像素值。计算方法是在当前亮度的基础上,点乘LuminanceCoeff常量系数。这些系数是基于CIE颜色匹配函数的,也是业界公认的标准。
最后,sat參数在两者之间进行线性插值。sat越大(能够大于1),brtColor的份重越大。
—— 计算当前对照度下的像素是相似的过程。相同使用lerp函数。当中。lerp的右边界是上一步得到的像素值,左边界值是对照度最低的像素值。这里使用了常量avgLumin。最后,con參数在两者之间进行线性插值。
con越大(能够大于1),satColor的份重越大。
- 最后。我们须要略微改动下frag函数。使得它能够逐像素处理render texture中的每一个像素。然后再又一次输出,返回给脚本:
fixed4 frag(v2f_img i) : COLOR {
//Get the colors from the RenderTexture and the uv's
//from the v2f_img struct
fixed4 renderTex = tex2D(_MainTex, i.uv); //Apply the brightness, saturation, contrast operations
renderTex.rgb = ContrastSaturationBrightness (renderTex.rgb, _BrightnessAmount, _SaturationAmount, _ContrastAmount); return renderTex;
}
- 首先加入合适的变量来控制亮度、饱和度和对照度:
#region Variables
public Shader curShader;
public float brightnessAmount = 1.0f;
public float saturationAmount = 1.0f;
public float contrastAmount = 1.0f; private Material curMaterial;
#endregion - 然后,在OnRenderImage函数中。将新的值传递给Shader:
void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture){
if (curShader != null) {
material.SetFloat("_BrightnessAmount", brightnessAmount);
material.SetFloat("_SaturationAmount", saturationAmount);
material.SetFloat("_ContrastAmount", contrastAmount); Graphics.Blit(sourceTexture, destTexture, material);
} else {
Graphics.Blit(sourceTexture, destTexture);
}
} - 最后。我们仅仅须要在函数中,确保各变量的范围就可以。这些范围能够依据须要随意设置:
// Update is called once per frame
void Update () {
brightnessAmount = Mathf.Clamp(brightnessAmount, 0.0f, 2.0f);
saturationAmount = Mathf.Clamp(saturationAmount, 0.0f, 2.0f);
contrastAmount = Mathf.Clamp(contrastAmount, 0.0f, 3.0f);
}
以下的图显示了它的结果:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2FuZHljYXQxOTky/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />
解释
【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度的更多相关文章
- 【Unity Shaders】Unity里的雾效模拟
写在前面 熟悉Unity的都知道,Unity可以进行基本的雾效模拟.所谓雾效,就是在远离我们视角的方向上,物体看起来像被蒙上了某种颜色(通常是灰色).这种技术的实现实际上非常简单,就是根据物体距离摄像 ...
- 【Unity Shaders】使用Unity Render Textures实现画面特效——建立画面特效脚本系统
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】游戏性和画面特效——创建一个夜视效果的画面特效
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】游戏性和画面特效——创建一个老电影式的画面特效
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects —— 实现Photoshop的色阶效果
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects——打包和混合textures
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects——让sprite sheets动起来
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects——通过修改UV坐标来滚动textures
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】Using Textures for Effects介绍
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
随机推荐
- AS3开发必须掌握的内容
1.事件机制 2.显示列表 3.垃圾回收 4.常用方法 5.网络通信 6.位图动画 7.渲染机制 8.API结构 9.沙箱机制 10.资源管理 11.内存管理 12.性能优化 13.资源选择 14.安 ...
- QT实现不规则窗体
看到网上有很多不规则窗体的实现,效果很酷.于是使用QT也实现了一个,QT的不规则窗体实现非常简单,只需要设置一个mask(遮掩)图片,这个图片的格式可以使用png或bmp格式,我使用了png格式,默认 ...
- 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)
写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...
- 3.1.2 MVC模式和URL访问
本节课大纲: 一.什么是MVC //了解 M -Model 编写model类 对数据进行操作 使用Model类 来操作数据 V -View 编写html文件,页面呈现 C -Controller 编写 ...
- python中逐行读取文件的最佳方式_Drupal_新浪博客
python中逐行读取文件的最佳方式_Drupal_新浪博客 python中逐行读取文件的最佳方式 (2010-08-18 15:59:28) 转载▼ 标签: python ...
- struts2+jquery +json实现异步加载数据,亲测(原创)
//初始加载页面时 $(document).ready(function(){ //为获取单个值的按钮注册鼠标单击事件 $("#getMessage").click(functio ...
- C++ 指针—02 指针与引用的对照
★同样点: ●都是地址的概念: 指针指向一块内存,它的内容是所指内存的地址:而引用则是某块内存的别名. ★不同点: ●指针是一个实体,而引用仅是个别名: ●引用仅仅能在定义时被初始化一次,之后不可变: ...
- 解决Ubuntu下安装VMware错误could not open /dev/vmmon
在安装VMware并启动新建的虚拟系统时,会出现错误could not open /dev/vmmon. 普通情况下,这是因为ubuntu系统gcc版本号的问题.我机器上是gcc-4.5,于是我将其改 ...
- 它们的定义iOS双击Home截图按键开关
<pre name="code" class="objc"><p>双击假设Home,我会去iOS App的switcher页面,这里列出 ...
- Linux温馨提示1--安装U板块和Windwos划分
一.安装U盘 现在我用Ubuntu12.04在插入U光盘将被直接安装到/media/下, 10:33linc@Linc-Ubuntu:linc$ df -h Filesystem Size Used ...