UnityShader实例15:屏幕特效之Bloom
http://blog.csdn.net/u011047171/article/details/48522073
Bloom特效
概述
Bloom特效与HDR特效的异同
那么HDR与bloom效果的差别到底在什么地方呢?
第一,HDR效果就是超亮的光照与超暗的黑暗的某种结合,这个效果是光照产生的,强度、颜色等方面是游戏程序可动态控制的,是一种即时动态光影;bloom效果则是物体本身发出的光照,仅仅是将光照范围调高到过饱和,是游戏程序无法动态控制的,是一种全屏泛光。
第二,bloom效果无需HDR就可以实现,但是bloom效果是很受限的,它只支持8位RGBA,而HDR最高支持到32位RGBA。
第三,bloom效果的实现很简单,比如《半条命2》的MOD就是一个很小的很简单的MOD,而且bloom效果不受显卡的规格的限制,你甚至可以在TNT显卡上实现bloom效果(当然效果很差)!而HDR,必须是6XXX以上的显卡才能够实现,这里的HDR是指nVIDIA的HDR。这时有必要谈nVIDIA和ATI的显卡所实现的HDR,两者还是有区别的,具体区别就很专业了,总之从真实性表现来看,nVIDIA的显卡实现的HDR更好一些。HDR是nVIDIA提出的概念,从技术上来讲,ATI当然无法严格克隆nVIDIA的技术,所以ATI的HDR是另一种途径实现的尽可能接近的HDR,不能算“真”HDR,据传ATI的R520能够真正实现FP16 HDR。
Bloom特效的实现流程
- 第一步: 先获取屏幕图像,然后对每个像素进行亮度检测,若大于某个阀值即保留原始颜色值,否则置为黑色;
- 第二步:对上一步获取的图像,做一个模糊,通常使用高斯模糊。
- 第三步:将模糊后的图片和原图片做一个加权和。
Bloom特效的shader实现
- struct v2f_withMaxCoords {
- half4 pos : SV_POSITION;
- half2 uv2[5] : TEXCOORD0;
- };
- //在vert函数里对uv坐标做了四次偏移,对原像素周围临近的像素采样
- v2f_withMaxCoords vertMax (appdata_img v)
- {
- v2f_withMaxCoords o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- o.uv2[0] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5,1.5);
- o.uv2[1] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5,1.5);
- o.uv2[2] = v.texcoord + _MainTex_TexelSize.xy * half2(-1.5,-1.5);
- o.uv2[3] = v.texcoord + _MainTex_TexelSize.xy * half2(1.5,-1.5);
- o.uv2[4] = v.texcoord ;
- return o;
- }
- //Frag函数用偏移的uv坐标采样,并且与原像素进行对比,如果亮度比原像素大,则取代原像素,因此亮部像素得到了扩展处理。这里ONE_MINUS_INTENSITY是由脚本传递过来的参数,用来控制bloom范围,功能就是讲低于这个值的像素设置为黑色。
- fixed4 fragMax ( v2f_withMaxCoords i ) : COLOR
- {
- fixed4 color = tex2D(_MainTex, i.uv2[4]);
- color = max(color, tex2D (_MainTex, i.uv2[0]));
- color = max(color, tex2D (_MainTex, i.uv2[1]));
- color = max(color, tex2D (_MainTex, i.uv2[2]));
- color = max(color, tex2D (_MainTex, i.uv2[3]));
- return saturate(color - ONE_MINUS_INTENSITY);
- }
- struct v2f_withBlurCoordsSGX
- {
- float4 pos : SV_POSITION;
- half2 offs[7] : TEXCOORD0;
- };
- //水平方向的像素偏移,用来做水平模糊
- v2f_withBlurCoordsSGX vertBlurHorizontalSGX (appdata_img v)
- {
- v2f_withBlurCoordsSGX o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- half2 netFilterWidth = _MainTex_TexelSize.xy * half2(1.0, 0.0) * _Parameter.x;
- o.offs[0] = v.texcoord + netFilterWidth;
- o.offs[1] = v.texcoord + netFilterWidth*2.0;
- o.offs[2] = v.texcoord + netFilterWidth*3.0;
- o.offs[3] = v.texcoord - netFilterWidth;
- o.offs[4] = v.texcoord - netFilterWidth*2.0;
- o.offs[5] = v.texcoord - netFilterWidth*3.0;
- o.offs[6] = v.texcoord;
- return o;
- }
- //垂直方向的像素偏移,用来做水平模糊
- v2f_withBlurCoordsSGX vertBlurVerticalSGX (appdata_img v)
- {
- v2f_withBlurCoordsSGX o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- half2 netFilterWidth = _MainTex_TexelSize.xy * half2(0.0, 1.0) * _Parameter.x;
- o.offs[0] = v.texcoord + netFilterWidth;
- o.offs[1] = v.texcoord + netFilterWidth*2.0;
- o.offs[2] = v.texcoord + netFilterWidth*3.0;
- o.offs[3] = v.texcoord - netFilterWidth;
- o.offs[4] = v.texcoord - netFilterWidth*2.0;
- o.offs[5] = v.texcoord - netFilterWidth*3.0;
- o.offs[6] = v.texcoord;
- return o;
- }
- //用vert传过来的uv坐标数组进行采样,并乘以对应的权重进行叠加,其结果是个近似高斯模糊。
- fixed4 fragBlurSGX ( v2f_withBlurCoordsSGX i ) : COLOR
- {
- fixed4 color = tex2D(_MainTex, i.offs[6]) * curve[3];
- color += tex2D(_MainTex, i.offs[0])*curve[2];
- color += tex2D(_MainTex, i.offs[1])*curve[1];
- color += tex2D(_MainTex, i.offs[2])*curve[0];
- color += tex2D(_MainTex, i.offs[3])*curve[2];
- color += tex2D(_MainTex, i.offs[4])*curve[1];
- color += tex2D(_MainTex, i.offs[5])*curve[0];
- return color;
- }
- struct v2f_simple {
- half4 pos : SV_POSITION;
- half4 uv : TEXCOORD0;
- };
- //考虑到D3D9的uv坐标Y轴是反转的,因此需要做个判断进行调整,防止图像倒转。
- v2f_simple vertBloom (appdata_img v)
- {
- v2f_simple o;
- o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
- o.uv = v.texcoord.xyxy;
- #if SHADER_API_D3D9
- if (_MainTex_TexelSize.y < 0.0)
- o.uv.w = 1.0 - o.uv.w;
- #endif
- return o;
- }
- fixed4 fragBloom ( v2f_simple i ) : COLOR
- {
- fixed4 color = tex2D(_MainTex, i.uv.xy);
- color += tex2D(_Bloom, i.uv.zw)*_Parameter.z*_ColorMix;
- return color;
- }
本例Bloom特效的shader部分关键代码就是这么多,这里就不贴出完整代码了,有需要的同学可以到文章末尾点积链接下载,在完整代码里,我们使用了CGINCLUDE和ENDCG模块化的方式组织代码,减少了一定代码量,并且是代码的可读性更好,方便C#脚本调用。
C#脚本
- void OnRenderImage (RenderTexture sourceTexture, RenderTexture destTexture)
- {
- #if UNITY_EDITOR
- FindShaders ();
- CheckSupport ();
- CreateMaterials ();
- #endif
- if(threshold != 0 && intensity != 0){
- int rtW = sourceTexture.width/4;
- int rtH = sourceTexture.height/4;
- BloomMaterial.SetColor ("_ColorMix", colorMix);
- BloomMaterial.SetVector ("_Parameter", new Vector4(BlurSize*1.5f, 0.0f, intensity,0.8f - threshold));
- // material.SetFloat("_blurSize",BlurSize);
- RenderTexture rtTempA = RenderTexture.GetTemporary (rtW, rtH, 0,rtFormat);
- rtTempA.filterMode = FilterMode.Bilinear;
- RenderTexture rtTempB = RenderTexture.GetTemporary (rtW, rtH, 0,rtFormat);
- rtTempA.filterMode = FilterMode.Bilinear;
- Graphics.Blit (sourceTexture, rtTempA,BloomMaterial,0);
- Graphics.Blit (rtTempA, rtTempB, BloomMaterial,1);
- RenderTexture.ReleaseTemporary(rtTempA);
- rtTempA = RenderTexture.GetTemporary (rtW, rtH, 0, rtFormat);
- rtTempB.filterMode = FilterMode.Bilinear;
- Graphics.Blit (rtTempB, rtTempA, BloomMaterial,2);
- BloomMaterial.SetTexture ("_Bloom", rtTempA);
- Graphics.Blit (sourceTexture, destTexture, BloomMaterial,3);
- RenderTexture.ReleaseTemporary(rtTempA);
- RenderTexture.ReleaseTemporary(rtTempB);
- }
- else{
- Graphics.Blit(sourceTexture, destTexture);
- }
- }
本例实现的效果如图
总结
下载链接:
UnityShader实例15:屏幕特效之Bloom的更多相关文章
- UnityShader实例13:屏幕特效之均值模糊(Box Blur)
均值模糊(Box Blur) 概述 因为公司手游项目需求.须要一个适合手机平台的模糊效果,同一时候须要开放一个參数便于调节模糊值.我首先想到的就是ps里面的均值模糊. 查资料能够知道均值模糊是一种高速 ...
- UnityShader之屏幕特效基础
1.什么是屏幕特效 我们这里讲的屏幕特效技术,指的是在渲染完整个场景后得到的屏幕图象的基础上,再对这个屏幕图像做一系列处理,实现出屏幕特效,使用这种技术可以为屏幕画面增添各种风格的艺术效果,比如泛光. ...
- Unity shader(CG) 写一个 散色、折射、反射、菲涅尔、gamma、简单后期屏幕特效
http://www.lai18.com/content/506918.html 1.自生要求是很重要的,当然不是什么强迫工作之类的,而是自己有限的能力上不断的扩展兴趣上的内容. 2.用生活的眼光去发 ...
- Android实例-获取屏幕的物理分辨率
相关资料: http://blog.qdac.cc/?p=1161 实例代码: unit Unit1; interface uses System.SysUtils, System.Types, Sy ...
- UnityShader实例09:Stencil Buffer&Stencil Test
http://blog.csdn.net/u011047171/article/details/46928463 Stencil Buffer&Stencil Test 在开始前先吐槽下uni ...
- 【html】【15】特效篇--分页
下载参考: http://aspx.sc.chinaz.com/query.aspx?keyword=%E5%88%86%E9%A1%B5&classID=&page=1 实例: h ...
- 简单的javascript实例一(时钟特效)
方便以后copy 时钟特效 <html> <head> <meta http-equiv="Content-Type" content="t ...
- UnityShader - 模拟动态光照特效
模型贴片 + 特效Shader = 动态光照特效 效果是这样的: 做法简单粗暴,直接使用模型贴片: shader上使用了noise只是提供一种思路,也有更简单的方法代替
- [Xcode 实际操作]九、实用进阶-(15)屏幕截屏:截取当前屏幕上的显示内容
目录:[Swift]Xcode实际操作 本文将演示如何截取屏幕画面,并将截取图片,存入系统相册. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UI ...
随机推荐
- 九度OJ 1181:遍历链表 (链表、排序)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2733 解决:1181 题目描述: 建立一个升序链表并遍历输出. 输入: 输入的每个案例中第一行包括1个整数:n(1<=n<=1 ...
- [IOS]从零开始搭建基于Xcode7的IOS开发环境和免开发者帐号真机调试运行第一个IOS程序HelloWorld
首先这篇文章比较长,若想了解Xcode7的免开发者帐号真机调试运行IOS程序的话,直接转到第五部分. 转载请注明原文地址:http://www.cnblogs.com/litou/p/4843772. ...
- struts2 获取表单数据封装到list和map集合
一.获取封装表单数据到list集合 示例 获取用户输入的用户名和密码并输出用户名. jsp页面 list[0]表示list中的第一个user对象 Java代码 二.封装表单数据到map集合 示例 获取 ...
- SpringMVC的第一个入门案例
用户提交一个请求,服务器端处理器在接收到这个请求后,给出一条欢迎信息,在页面中显示. 第一步:导入jar包 在原有Springjar包基础上添加2个jar包 spring-webmvc-4.2.0.R ...
- [闲来无事,从头再来][C51篇]导读
目 的: 通过学习C51,熟悉单片机,熟悉C语言,熟悉单片机系统的外部电路. 方 法: 通过看书和使用板子做实验来进行学习 参考资料: <新概念51单片机C语言教程& ...
- memset使用
void memset(void s, int ch, size_t n); 函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 ...
- t-sql判断数据库对象是否存在
1 系统表sys.sysobjects 在数据库中创建的每个对象(例如约束.默认值.日志.规则以及存储过程)都对应一行,详细介绍参考MSDN 2 OBJECTPROPERTY 返回当前数据库中架构范围 ...
- link_to嵌套
= link_to theses_path, :class=>"btn" do .text-center 购买
- Flex自定义组件开发
一般情况下需要组件重写都是由于以下2个原因:1.在FLEX已有组件无法满足业务需求,或是需要更改其可视化外观等特性时,直接进行继承扩展.2.为了模块化设计或进一步重用,需要对FLEX组件进行组合.而F ...
- c的详细学习(3)数据的输入输出
c语言没有专门的数据输入输出语句,而是通过调用系统提供的的标准输入/输出库函数来实现数据的输入和输出. (1)数据的输出: 注意:在使用标准的输入输出库函数时,使用编译预处理命令“#inclu ...