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

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

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

计算方法:

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

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

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

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

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

控制脚本:

 using UnityEngine;

 public class BloomCtrl : ScreenEffectBase
{
private const string _LuminanceThreshold = "_LuminanceThreshold";
private const string _BlurSize = "_BlurSize";
private const string _Bloom = "_Bloom"; [Range(, )]
public int iterations = ;
[Range(0.2f, 3.0f)]
public float blurSize = 0.6f;
[Range(, )]
public int dowmSample = ;
[Range(0.0f, 4.0f)]
public float luminanceThreshold = 0.6f;//控制Bloom效果的亮度阈值,因为亮度值大多数时不大于1,故该值超过1时一般无效果,但开启HDR后图像的亮度取值范围将扩大 private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (Material != null)
{
Material.SetFloat(_LuminanceThreshold, luminanceThreshold); int rth = source.height / dowmSample;
int rtw = source.width / dowmSample; RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, );
buffer0.filterMode = FilterMode.Bilinear; //第1个Pass中提取纹理亮部,存到buffer0中,以便后面进行高斯模糊处理
Graphics.Blit(source, buffer0,Material,); for(int i = ; i < iterations; i++)
{
Material.SetFloat(_BlurSize, blurSize*i+1.0f); //第2,3个Pass中对亮部分别进行纵向和横向的渲染处理(高斯模糊)
RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, );
Graphics.Blit(buffer0, buffer1, Material,);
RenderTexture.ReleaseTemporary(buffer0);//临时创建的渲染纹理不能直接释放 x: buffer0.Release(); buffer0 = RenderTexture.GetTemporary(rtw, rth, );
Graphics.Blit(buffer1, buffer0, Material, );
RenderTexture.ReleaseTemporary(buffer1);
} //第4个Pass将buffer0高斯模糊后的结果传给_Bloom以进行最后的混合
Material.SetTexture(_Bloom, buffer0);
Graphics.Blit(source,destination,Material,);//注意这里用原始纹理作为源纹理而不是buffer0,因为buffer0已经作为另一个参数进行了传递,而这里还需要原始的纹理以进行混合
RenderTexture.ReleaseTemporary(buffer0);
}
else
Graphics.Blit(source, destination);
}
}

基类脚本见:

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

Shader脚本:

 Shader "MyUnlit/Bloom"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Bloom("Bloom",2D)="black"{}
_LuminanceThreshold("Luminance Threshold",Float)=0.5
_BlurSize("Blur Size",Float)=1.0
}
SubShader
{
CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex;
half4 _MainTex_TexelSize;
sampler2D _Bloom;
float _LuminanceThreshold;
float _BlurSize; struct v2f
{
half2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
}; struct v2fBloom
{
//half4是因为这里还要存储_Bloom纹理
half4 uv:TEXCOORD0;
float4 pos:SV_POSITION;
}; v2f vert(appdata_img v)
{
v2f o;
o.pos=UnityObjectToClipPos(v.vertex);
o.uv=v.texcoord;
return o;
} v2fBloom vertBloom(appdata_img v)
{
v2fBloom o;
o.pos=UnityObjectToClipPos(v.vertex); //xy存储主纹理,zw存储_Bloom纹理,这样不必再申请额外空间
o.uv.xy=v.texcoord;
o.uv.zw=v.texcoord; //纹理坐标平台差异化判断,主要针对DirectX,因为DirectX与OpenGL纹理坐标原点不同(分别在左上和左下)
//同时Unity平台对于主纹理已经进行过内部处理,因此这里只需要对_Bloom纹理进行平台检测和翻转
//主要表现为进行y轴方向的翻转(因为y轴方向相反),对于_Bloom纹理来说也就是w
#if UNITY_UV_STARTS_AT_TOP
if(_MainTex_TexelSize.y<){
o.uv.w=1.0-o.uv.w;
}
#endif return o;
} //提取超过亮度阈值的图像
fixed4 fragExtractBright(v2f i):SV_Target
{
fixed4 col=tex2D(_MainTex,i.uv);
fixed val=clamp(Luminance(col)-_LuminanceThreshold,0.0,1.0);
return col*val;
} //对xy和zw对应的纹理采样进行混合
fixed4 fragBloom(v2fBloom i):SV_Target
{
return tex2D(_MainTex,i.uv.xy)+tex2D(_Bloom,i.uv.zw);
} ENDCG ZTest Always
Cull Off
ZWrite Off //Pass 1:提亮部
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment fragExtractBright
ENDCG
} //Pass 2,3:高斯模糊,这里直接调用以前写的Pass
UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V" UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H" //Pass 4:混合原图和模糊后亮部
Pass
{
CGPROGRAM
#pragma vertex vertBloom
#pragma fragment fragBloom
ENDCG
}
}
Fallback Off
}

效果如下:

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

  1. Unity Shader 屏幕后效果——颜色校正

    屏幕后效果指的是,当前整个场景图已经渲染完成输出到屏幕后,再对输出的屏幕图像进行的操作. 在Unity中,一般过程通常是: 1.建立用于处理效果的shader和临时材质,给shader脚本传递需要控制 ...

  2. Unity Shader 屏幕后效果——边缘检测

    关于屏幕后效果的控制类详细见之前写的另一篇博客: https://www.cnblogs.com/koshio0219/p/11131619.html 这篇主要是基于之前的控制类,实现另一种常见的屏幕 ...

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

    Unity内置的雾效需要在每个shader中分别编写,造成了极大的不便.这里利用屏幕后处理产生可单独控制且自由度更高的雾效. 屏幕后雾效的本质在于,通过深度纹理重构出每个像素在世界空间中的位置,根据得 ...

  4. Unity Shader 屏幕后效果——高斯模糊

    高斯模糊是图像模糊处理中非常经典和常见的一种算法,也是Bloom屏幕效果的基础. 实现高斯模糊同样用到了卷积的概念,关于卷积的概念和原理详见我的另一篇博客: https://www.cnblogs.c ...

  5. Unity Shader 屏幕后效果——景深

    景深效果的原理是,在摄像机的近裁剪平面和远裁剪平面之间可以设置一个焦距,在这个距离所在的平面上的物体最为清晰,而这个距离之前或之后的物体成像是一种模糊状态(根据距离逐渐模糊,最终达到最为模糊的状态). ...

  6. Unity Shader 屏幕后效果——摄像机运动模糊(速度映射图实现)

    速度映射图主要是为了得到每个像素相对于前一帧的运动矢量,其中一种方法是使用摄像机的深度纹理来推导. 推导过程如下: 先由深度纹理逆推出NDC(归一化的设备坐标)下的顶点坐标,利用VP矩阵(视角*投影矩 ...

  7. Unity Shader实现描边效果

    http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用S ...

  8. Unity Shader 之 透明效果

    透明效果 透明效果一般有两种实现方法: 第一种,使用透明度测试(Alpha Test) 第二种,使用透明度混合(Alpha Blending) 透明度测试和透明度混合机制: 透明度测试(Alpha T ...

  9. Unity实现屏幕抖动效果(通过Camera Viewpoint实现)

    由于游戏死亡时一般都需要屏幕抖一下下. 所以百度了下相关写法,发现方法很多~~~ 找来找去,找到个简单粗暴地,啥都不需要,一个脚本拖动到Camera上就可以了 略微修改了一点点,share一下 usi ...

随机推荐

  1. 基本认证(Basic Authorization)

    ---------------------------------- import arcpy from base64 import encodestring username = 'xxx' pas ...

  2. Java学习——内存机制

    Java学习——内存机制 摘要:本文主要介绍了Java的内存机制. 部分内容来自以下博客: https://www.cnblogs.com/xrq730/p/4827590.html https:// ...

  3. Spring Boot MVC 使用 JSP 作为模板

    Spring Boot 默认使用 Thymeleaf 作为模板引擎,直接在 template 目录中存放 JSP 文件并不能正常访问,需要在 main 目录下新建一个文件夹来存放 JSP 文件,而且需 ...

  4. MTSC2019大会日程重磅发布,腾讯WeTest独家Topic大揭秘!

    WeTest 导读 中国移动互联网测试开发大会 Mobile Testing Summit China(简称 MTSC)是由国内最大的移动测试技术社区 TesterHome 发起的软件测试行业技术会议 ...

  5. php对象复制、clone、浅复制与深复制实例详解

    php对象复制.clone.浅复制与深复制实例详解 一.用clone(克隆)来复制对象$obj1 = new Object();$obj2 = clone $obj1;clone方法会触发对象里定义的 ...

  6. SpringMVC 之 上传文件

    一.需求: 利用SpringMVC实现上传文件的功能 二.思路: 1.我们可以在SpringMVC中,通过配置一个MultipartResolver来上传文件. 2.通过MultipartFile f ...

  7. Python乘法口诀表

    乘法口诀表 print("乘法口诀表") for i in range(1,10):     for j in range(1,i+1):         print(str(i) ...

  8. CSS3 边框 border-image

    border-image:xx xx xx 是一系列参数的简写,该属性将图片作为边框修饰 border-image-source:url(border.png); 图片url地址 border-ima ...

  9. C语言的暂停

    #include<stdio.h> int main(void) { printf("Hello, World!\n"); system("pause&quo ...

  10. 201871010117-石欣钰《面向对象程序设计(java)》第十一周学习总结

    博文正文开头格式:(2分) 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.co ...