【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>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
随机推荐
- nmap -- write a nmap script
漏洞扫描 --编写Nmap脚本 2006年12月份,Nmap4.21 ALPHA1版增加脚本引擎,并将其作为主线代码的一部分.NSE脚本库现在已经有400多个脚本.覆盖了各种不同的网络机制(从SMB漏 ...
- 管道实现进程间通讯 、WaitNamedPipe
一.管道实现进程间通讯 主要的理论知识 1.什么是管道以及分类 管道是两个头的东西,每一个头各连接一个进程或者同一个进程的不同代码,依照管道的类别分有两种管道,匿名的和命名的:依照管道的传输方向分也能 ...
- java OOP及相关基础知识汇总(转)
OOP 对象有三个要素 behavior 接口是怎样的,有什么方法/field可以用? state 调用方法的时候,对象会有什么反应? 只有通过调用方法才能改变一个对象的state identity ...
- SWT可视化设计
SWT可视化设计,可以使用Google的WindowBuilder. 在Google Code中,搜索WindowBuilder就可以看到路径. 在Eclipse中 Help--->Inst ...
- LINUX编程学习笔记(十三) 遍历目录的两种方法
1 默认情况下 实际用户和有效用户是一样的 实际用户:执行用户 有效用户:权限用户 getuid() 实际用户 geteuid() 有效用户 chmod u+s 之后 ,其他人执行文件时,实际 ...
- Python批量删除指定目录下的指定类型的文件
Python作为一种脚本语言.其很适合文件级的各种操作.以下的代码能够批量删除指定目录下的所有特定类型(CSV类型)的文件. import sys, csv , operator import os ...
- OCP读书笔记(13) - 管理内存
SGA 1. 什么是LRULRU表示Least Recently Used,也就是指最近最少使用的buffer header链表LRU链表串联起来的buffer header都指向可用数据块 2. 什 ...
- GB2312引进和使用的字体
一个:先上图看到的结果,下面的屏幕截图android在测试的结果"SD卡测试".."GPS测试"和其他字符24x24字体进来. 二: 1)简单介绍 ...
- 【STL】关联容器 — hash_set
容器hash_set是以hash table为底层机制的,差点儿所有的操作都是转调用hash table提供的接口.因为插入无法存储同样的键值,所以hash_set的插入操作所有都使用hash tab ...
- DOM中的动态NodeList与静态NodeList
GitHub版本号: https://github.com/cncounter/translation/blob/master/tiemao_2014/NodeList/NodeList.md 副标题 ...