【Unity Shaders】Using Textures for Effects —— 实现Photoshop的色阶效果
本系列主要参考《Unity Shaders and Effects Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。
这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。
========================================== 分割线 ==========================================
考虑到法向贴图(normal mapping)和程序贴图纹理(procedural textures)两节的内容要么很常见或者很少使用,因此我决定偷懒先不看了。
写在前面
终于到了Using Textures for Effects的最后一节!这次主要讲一个小技巧,用Shader实现Photoshop的色阶效果。
如果你曾经做过图像编辑工作,例如给你们家的一张合影调色啊,制作游戏贴等,那么你一定明白使用色阶来全局调整图像的重要性和实用性。现在,可以告诉你,你完全可以使用Shaders来创建类似Photoshop色阶的效果。
Photoshop里所有的图像编辑工具和混合模型就是一系列数学操作的结果。从本质上来说,我们是在对像素值与其他某些量进行乘法、加法、除法、或者比较等操作,来得到最后的返回值。这个返回值就是新图像的一个像素值。
当然,我们可以写一大本书来仅仅描述Photoshop效果使用的数学技巧,但这里,我们仅仅关注色阶这一块。在本书的第十章,Screen Effects with Unity Render Textures中,将会涉及更多的高级混合模式。(噢,第十章感觉好远的样子。)
准备工作
实现
- 向Shader添加下列新的properties:
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {} //Add the Input Levels Values
_inBlack ("Input Black", Range(0, 255)) = 0
_inGamma ("Input Gamma", Range(0, 2)) = 1.61
_inWhite ("Input White", Range(0, 255)) = 255 //Add the Output Levels
_outWhite ("Output White", Range(0, 255)) = 255
_outBlack ("Output Black", Range(0, 255)) = 0
} - 在CGPROGRAM命令下声明上述各个properties的变量:
CGPROGRAM
#pragma surface surf Lambert sampler2D _MainTex; //Add these variables
//to the CGPROGRAM
float _inBlack;
float _inGamma;
float _inWhite;
float _outWhite;
float _outBlack; - 创建一个新的函数float GetPixelLevel(float pixelColor),它的参数为原帖图RGB通道中一个通道的像素值,返回经过调整色阶后的新的该通道像素值。
float GetPixelLevel(float pixelColor)
{
float pixelResult;
pixelResult = (pixelColor * 255.0);
pixelResult = max(0, pixelResult - _inBlack);
pixelResult = saturate(pow(pixelResult / (_inWhite - _inBlack), _inGamma));
pixelResult = (pixelResult * (_outWhite - _outBlack) + _outBlack)/255.0;
return pixelResult;
} - 修改surf函数,重新计算RGB通道的像素值。
//Create a variable to store
//a pixel channel from our _MainTex texture
float outRPixel = GetPixelLevel(c.r); float outGPixel = GetPixelLevel(c.g); float outBPixel = GetPixelLevel(c.b); - 最后,输出新的像素值。
o.Albedo = float3(outRPixel,outGPixel,outBPixel);
o.Alpha = c.a;
Shader "Custom/PhotoshopLevels" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
//Add the Input Levels Values
_inBlack ("Input Black", Range(0, 255)) = 0
_inGamma ("Input Gamma", Range(0, 2)) = 1.61
_inWhite ("Input White", Range(0, 255)) = 255
//Add the Output Levels
_outWhite ("Output White", Range(0, 255)) = 255
_outBlack ("Output Black", Range(0, 255)) = 0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
//Add these variables
//to the CGPROGRAM
float _inBlack;
float _inGamma;
float _inWhite;
float _outWhite;
float _outBlack;
struct Input {
float2 uv_MainTex;
};
float GetPixelLevel(float pixelColor)
{
float pixelResult;
pixelResult = (pixelColor * 255.0);
pixelResult = max(0, pixelResult - _inBlack);
pixelResult = saturate(pow(pixelResult / (_inWhite - _inBlack), _inGamma));
pixelResult = (pixelResult * (_outWhite - _outBlack) + _outBlack)/255.0;
return pixelResult;
}
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
//Create a variable to store
//a pixel channel from our _MainTex texture
float outRPixel = GetPixelLevel(c.r);
float outGPixel = GetPixelLevel(c.g);
float outBPixel = GetPixelLevel(c.b);
o.Albedo = float3(outRPixel,outGPixel,outBPixel);
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
前后效果对比如下所示(左边为使用Diffuse Shader,右边为使用PhotoshopLevels Shader):
解释
pixelResult = (pixelColor * 255.0);
然后,我们减去_inBlack属性值,来使像素变暗。我们还要确保减去后的值不会小于0.0,因此使用max函数。
pixelResult = max(0, pixelResult - _inBlack);
接下来,我们用(_inWhite - _inBlack)来得到新的white point值,并和pixelResult做除法。这相比与我们直接除以_inWhite,会调高像素的亮度,使它变得更亮。 然后使用_inGamma进行乘方操作。
pixelResult = saturate(pow(pixelResult / (_inWhite - _inBlack), _inGamma));
最后,我们使用_outWhite和_outBlack来修改像素值,以便可以从全局上控制最小像素值(_outBlack)和最大像素值(_outWhite)。得到的结果需要除以255.0,来使得输出值的范围重新映射到0.0到1.0。
pixelResult = (pixelResult * (_outWhite - _outBlack) + _outBlack)/255.0;
【Unity Shaders】Using Textures for Effects —— 实现Photoshop的色阶效果的更多相关文章
- 【Unity Shaders】ShadowGun系列之一——飞机坠毁的浓烟效果
写在前面 最近一直在思考下面的学习该怎么进行,当然自己有在一边做项目一边学OpenGL,偶尔翻翻论文之类的.但是,写shader是一个需要实战和动手经验的过程,而模仿是前期学习的必经之路.很多人都会问 ...
- 【Unity Shaders】Using Textures for Effects介绍
本系列主要参考<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】使用Unity Render Textures实现画面特效——建立画面特效脚本系统
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- 【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...
- 【Unity Shaders】《Unity Shaders and Effects Cookbook》总结篇
我的唠叨 不知不觉,从发表第一篇关于<Unity Shaders and Effects Cookbook>已经快十个月了.一开始的初衷就是学习笔记,毕竟将来回过头去看的时候,再看英文难免 ...
- 【Unity Shaders】Lighting Models —— 衣服着色器
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
随机推荐
- GrideSearchCV 优化算法参数
很多机器学习算法有参数,比如 linear_model.LogisticRegression()中有参数C. sklearn中的GrideSearchCV可方便调参过程.如下: import nump ...
- Java数据库开发(一)之——JDBC连接数据库
一.MySQL数据库 1.创建数据库 CREATE DATABASE jdbc CHARACTER SET 'utf8'; 2.建表 CREATE TABLE user ( id int(10) NO ...
- Go 语言变量作用域
作用域为已声明标识符所表示的常量.类型.变量.函数或包在源代码中的作用范围. Go 语言中变量可以在三个地方声明: 函数内定义的变量称为局部变量 函数外定义的变量称为全局变量 函数定义中的变量称为形式 ...
- MyEclipse的Debug模式启动缓慢
打开breakpoints veiw,右键-> Remove all,重启下服务器就OK了 -–下面有个"顶"字,你懂得O(∩_∩)O哈哈~ -–乐于分享,共同进步! -–更 ...
- 使用 纯JQuery 进行 表单 验证
对于JavaScript而言,进行表单数据的验证可谓是很有必要的,而且一般我们都会在网页上先进行一下表单验证,然后服务器端再次进行验证,来确保用户提交数据的准确性.下面就来分享一个JQuery实现的表 ...
- Swift函数柯里化(Currying)简谈
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 下面简单说说Swift语言中的函数柯里化.简单的说就是把接收多 ...
- 01_Eclipse的使用方法
1 选择工作站 Workspace:表示工作站 2 切换工作站 选择工作站的方式:File->SwitchWorkspace 这里选择其他的工作站 清除工作站的方式: 找到MyEclips ...
- Servlet之Response对象
下面的方法可用于在 Servlet 程序中设置 HTTP 响应报头.这些方法通过HttpServletResponse 对象可用. 1 String encodeRedirectURL(Stri ...
- Dynamics CRM2015 The plug-in type does not exist in the specified assembly问题的解决方法
在用插件工具PluginProfiler调试时,报"The plug-in type xxxx does not exist in the specified assembly" ...
- GDAL不支持创建PCIDSK的面状矢量格式
最近在使用GDAL创建PCIDSK格式的矢量数据,发现创建点和线的矢量数据都没问题,创建面状的只有属性表没有图形.在GDAL官网说明也写的是支持的,地址为:http://www.gdal.org/fr ...