Unity Shader 屏幕后效果——Bloom外发光

Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成。

一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客:

https://www.cnblogs.com/koshio0219/p/11152534.html

计算方法:

总共需要用到4个Pass,它们的顺序如下:

Pass 1:得到纹理的亮度值(灰度值),由此计算出亮部区域,传递给一个临时的新纹理,这里叫_Bloom

Pass 2,3:单独对_Bloom进行高斯模糊(纵横),_Bloom纹理更新

Pass 4:混合原始纹理和_Bloom纹理,得到最终效果

为了得到更为细致的Bloom效果,建议将游戏的颜色空间由默认的伽马空间转为线性空间,必要时还可开启HDR

控制脚本:

 1 using UnityEngine;
 2
 3 public class BloomCtrl : ScreenEffectBase
 4 {
 5     private const string _LuminanceThreshold = "_LuminanceThreshold";
 6     private const string _BlurSize = "_BlurSize";
 7     private const string _Bloom = "_Bloom";
 8
 9     [Range(0, 4)]
10     public int iterations = 3;
11     [Range(0.2f, 3.0f)]
12     public float blurSize = 0.6f;
13     [Range(1, 8)]
14     public int dowmSample = 2;
15     [Range(0.0f, 4.0f)]
16     public float luminanceThreshold = 0.6f;//控制Bloom效果的亮度阈值,因为亮度值大多数时不大于1,故该值超过1时一般无效果,但开启HDR后图像的亮度取值范围将扩大
17
18     private void OnRenderImage(RenderTexture source, RenderTexture destination)
19     {
20         if (Material != null)
21         {
22             Material.SetFloat(_LuminanceThreshold, luminanceThreshold);
23
24             int rth = source.height / dowmSample;
25             int rtw = source.width / dowmSample;
26
27             RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
28             buffer0.filterMode = FilterMode.Bilinear;
29
30             //第1个Pass中提取纹理亮部,存到buffer0中,以便后面进行高斯模糊处理
31             Graphics.Blit(source, buffer0,Material,0);
32
33             for(int i = 0; i < iterations; i++)
34             {
35                 Material.SetFloat(_BlurSize, blurSize*i+1.0f);
36
37                 //第2,3个Pass中对亮部分别进行纵向和横向的渲染处理(高斯模糊)
38                 RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, 0);
39                 Graphics.Blit(buffer0, buffer1, Material,1);
40                 RenderTexture.ReleaseTemporary(buffer0);//临时创建的渲染纹理不能直接释放 x: buffer0.Release();
41
42                 buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
43                 Graphics.Blit(buffer1, buffer0, Material, 2);
44                 RenderTexture.ReleaseTemporary(buffer1);
45             }
46
47             //第4个Pass将buffer0高斯模糊后的结果传给_Bloom以进行最后的混合
48             Material.SetTexture(_Bloom, buffer0);
49             Graphics.Blit(source,destination,Material,3);//注意这里用原始纹理作为源纹理而不是buffer0,因为buffer0已经作为另一个参数进行了传递,而这里还需要原始的纹理以进行混合
50             RenderTexture.ReleaseTemporary(buffer0);
51         }
52         else
53             Graphics.Blit(source, destination);
54     }
55 }

Shader脚本:

  1 Shader "MyUnlit/Bloom"
  2 {
  3     Properties
  4     {
  5         _MainTex ("Texture", 2D) = "white" {}
  6         _Bloom("Bloom",2D)="black"{}
  7         _LuminanceThreshold("Luminance Threshold",Float)=0.5
  8         _BlurSize("Blur Size",Float)=1.0
  9     }
 10     SubShader
 11     {
 12         CGINCLUDE
 13
 14         #include "UnityCG.cginc"
 15
 16         sampler2D _MainTex;
 17         half4 _MainTex_TexelSize;
 18         sampler2D _Bloom;
 19         float _LuminanceThreshold;
 20         float _BlurSize;
 21
 22         struct v2f
 23         {
 24            half2 uv : TEXCOORD0;
 25            float4 pos : SV_POSITION;
 26         };
 27
 28         struct v2fBloom
 29         {
 30            //half4是因为这里还要存储_Bloom纹理
 31            half4 uv:TEXCOORD0;
 32            float4 pos:SV_POSITION;
 33         };
 34
 35         v2f vert(appdata_img v)
 36         {
 37            v2f o;
 38            o.pos=UnityObjectToClipPos(v.vertex);
 39            o.uv=v.texcoord;
 40            return o;
 41         }
 42
 43         v2fBloom vertBloom(appdata_img v)
 44         {
 45            v2fBloom o;
 46            o.pos=UnityObjectToClipPos(v.vertex);
 47
 48            //xy存储主纹理,zw存储_Bloom纹理,这样不必再申请额外空间
 49            o.uv.xy=v.texcoord;
 50            o.uv.zw=v.texcoord;
 51
 52            //纹理坐标平台差异化判断,主要针对DirectX,因为DirectX与OpenGL纹理坐标原点不同(分别在左上和左下)
 53            //同时Unity平台对于主纹理已经进行过内部处理,因此这里只需要对_Bloom纹理进行平台检测和翻转
 54            //主要表现为进行y轴方向的翻转(因为y轴方向相反),对于_Bloom纹理来说也就是w
 55            #if UNITY_UV_STARTS_AT_TOP
 56            if(_MainTex_TexelSize.y<0){
 57                   o.uv.w=1.0-o.uv.w;
 58            }
 59            #endif
 60
 61            return o;
 62         }
 63
 64         //提取超过亮度阈值的图像
 65         fixed4 fragExtractBright(v2f i):SV_Target
 66         {
 67             fixed4 col=tex2D(_MainTex,i.uv);
 68             fixed val=clamp(Luminance(col)-_LuminanceThreshold,0.0,1.0);
 69             return col*val;
 70         }
 71
 72         //对xy和zw对应的纹理采样进行混合
 73         fixed4 fragBloom(v2fBloom i):SV_Target
 74         {
 75             return tex2D(_MainTex,i.uv.xy)+tex2D(_Bloom,i.uv.zw);
 76         }
 77
 78         ENDCG
 79
 80         ZTest Always
 81         Cull Off
 82         ZWrite Off
 83
 84         //Pass 1:提亮部
 85         Pass
 86         {
 87             CGPROGRAM
 88             #pragma vertex vert
 89             #pragma fragment fragExtractBright
 90             ENDCG
 91         }
 92
 93         //Pass 2,3:高斯模糊,这里直接调用以前写的Pass
 94         UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V"
 95
 96         UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H"
 97
 98         //Pass 4:混合原图和模糊后亮部
 99         Pass
100         {
101             CGPROGRAM
102             #pragma vertex vertBloom
103             #pragma fragment fragBloom
104             ENDCG
105         }
106     }
107     Fallback Off
108 }

效果如下:

原文地址:https://www.cnblogs.com/koshio0219/p/11169122.html

时间: 2024-08-09 02:28:21

Unity Shader 屏幕后效果——Bloom外发光的相关文章

Unity Shader 屏幕后效果——全局雾

Unity内置的雾效需要在每个shader中分别编写,造成了极大的不便.这里利用屏幕后处理产生可单独控制且自由度更高的雾效. 屏幕后雾效的本质在于,根据深度纹理重构每个像素在世界空间中的位置,利用得到的坐标计算出一个雾效系数,最终利用雾效系数与雾的颜色相乘并与原始颜色进行插值运算得出最终效果. float3 afterFog=f*fogColor+(1-f)*origColor; 上面的插值运算中f代表雾效系数,它有多种计算方法: 1.线性计算: f=(dmax-Abs(z))/dmax-dmi

Unity Shader实现描边效果

http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用Shader实现描边效果,一起来看看吧. 最近又跑回去玩了玩<剑灵>,虽然出了三年了,感觉在现在的网游里面画面仍然算很好的了,剑灵里面走近或者选中NPC的一瞬间,NPC就会出现描边效果,不过这个描边效果是渐变的,会很快减弱最后消失(抓了好久才抓住一张图....) 还有就是最常见的LOL中的塔,我们把

Unity Shader 模型流光效果

Shader "Custom/FlowColor" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _FlowColor("Flow Color", Color) = (1,1,1,1) _FlowRange("Flow Range", Float) = 0.01 } SubShader { Pass { Tags { "Queue&

Unity shader实现水效果(折射,反射,波浪,1.菲尼尔,深度颜色)

整个实现过程,包括水面的UV流动,折射,反射,根据深度进行透明值处理等等 原文地址:https://www.cnblogs.com/ubanck/p/9606626.html

Unity shader学习之屏幕后期效果之调整屏幕亮度,饱和度,对比度

Unity的屏幕后期处理效果,使用MonoBehaviour.OnRenderImage来实现. 如代码如下: PostEffectRenderer: 1 using UnityEngine; 2 3 [RequireComponent(typeof(Camera))] 4 public abstract class PostEffectRenderer : GameBehaviour 5 { 6 protected abstract string ShaderName { get; } 7 8

【Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://blog.csdn.net/poem_qianmo/article/details/51871531 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 本文工程使用的Unity3D版本: 5.2.1  本篇文章将分析如何在Unity中基于Shader实现高斯模糊屏幕后期特效. 首先放出最终的实现效果.如下几幅图,是在Unity中使用本文所实现的Shader得到的高斯模糊屏幕

【Unity Shader】(九) ------ 高级纹理之渲染纹理及镜子与玻璃效果的实现

笔者使用的是 Unity 2018.2.0f2 + VS2017,建议读者使用与 Unity 2018 相近的版本,避免一些因为版本不一致而出现的问题. [Unity Shader](三) ------ 光照模型原理及漫反射和高光反射的实现 [Unity Shader](四) ------ 纹理之法线纹理.单张纹理及遮罩纹理的实现 [Unity Shader](五) ------ 透明效果之半透明效果的实现及原理 [Unity Shader](六) ------ 复杂的光照(上) [Unity

【我的书】Unity Shader的书 — 目录(2016.1.29更新)

写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shader的艰难,在群里也见了很多人提出的问题.我觉得学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么好处呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader初学者,但要: 有一定的

【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)

写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shader的艰难,在群里也见了非常多人提出的问题. 我认为学习Shader还是一件有规律可循的事情,但问题是中文资料难觅,而大家又不愿意去看英文...这对我有什么优点呢?强迫我对知识进行梳理,对细节问题把握更清楚. 第二个原因你懂的. 关于本书的定位问题: 面向Unity Shader刚開始学习的人,但要