【Unity3D】Bloom特效
1 Bloom 特效原理
Bloom 特效是指:将画面中较亮的区域向外扩散,造成一种朦脓的效果。实现 Bloom 特效,一般要经过 3 个阶段处理:亮区域检测、高斯模糊、Bloom 合成。
本文完整资源见→Unity3D Bloom 特效。
1)亮区域检测
根据亮度阈值检测亮区,如下从原图中提取亮区域。
原图:
亮区域:

2)高斯模糊
对亮区域进行高斯模糊(原理见→高斯模糊特效),使得亮区域往外扩散,并产生朦脓效果。
亮区域高斯模糊:

3)Bloom 合成
将高斯模糊处理后的亮区域图像与原图像叠加。
Bloom图像合成:

2 代码实现
Bloom.cs
using UnityEngine;
[ExecuteInEditMode] // 编辑态可以查看脚本运行效果
[RequireComponent(typeof(Camera))] // 需要相机组件
public class Bloom : MonoBehaviour {
private Material material = null; // 材质
[Range(0, 4)]
public int iterations = 3; // 高斯模糊迭代次数
[Range(0.2f, 3.0f)]
public float blurSpread = 0.6f; // 每次迭代纹理坐标偏移的速度
[Range(1, 8)]
public int downSample = 2; // 降采样比率
[Range(0.0f, 4.0f)]
public float luminanceThreshold = 0.6f; // 亮度阈值
private void Start() {
material = new Material(Shader.Find("MyShader/Bloom"));
material.hideFlags = HideFlags.DontSave;
}
void OnRenderImage(RenderTexture src, RenderTexture dest) {
if (material != null) {
material.SetFloat("_LuminanceThreshold", luminanceThreshold); // 设置亮度阈值
int rtW = src.width/downSample; // 降采样的纹理宽度
int rtH = src.height/downSample; // 降采样的纹理高度
RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
buffer0.filterMode = FilterMode.Bilinear; // 滤波模式设置为双线性
Graphics.Blit(src, buffer0, material, 0);
for (int i = 0; i < iterations; i++) {
material.SetFloat("_BlurSize", 1.0f + i * blurSpread);
RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
Graphics.Blit(buffer0, buffer1, material, 1); // 渲染垂直的Pass(高斯模糊)
RenderTexture.ReleaseTemporary(buffer0);
buffer0 = buffer1;
buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
Graphics.Blit(buffer0, buffer1, material, 2); // 渲染垂直的Pass(高斯模糊)
RenderTexture.ReleaseTemporary(buffer0);
buffer0 = buffer1;
}
material.SetTexture("_Bloom", buffer0); // 将高斯模糊处理后的纹理设置给_Bloom
Graphics.Blit(src, dest, material, 3);
RenderTexture.ReleaseTemporary(buffer0);
} else {
Graphics.Blit(src, dest);
}
}
}
Bloom.shader
Shader "MyShader/Bloom" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {} // 主纹理
_Bloom ("Bloom (RGB)", 2D) = "black" {} // Bloom处理需要的纹理(即高斯模糊处理后的纹理)
_LuminanceThreshold ("Luminance Threshold", Float) = 0.5 // 亮度阈值
_BlurSize ("Blur Size", Float) = 1.0 // 模糊尺寸(纹理坐标的偏移量)
}
SubShader {
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex; // 主纹理
half4 _MainTex_TexelSize; // _MainTex的像素尺寸大小, float4(1/width, 1/height, width, height)
sampler2D _Bloom; // Bloom处理需要的纹理(即高斯模糊处理后的纹理)
float _LuminanceThreshold; // 亮度阈值
float _BlurSize; // 模糊尺寸(纹理坐标的偏移量)
fixed luminance(fixed4 color) { // 计算亮度
return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
// 采样纹理的亮度减去亮度阈值, 小于0的值将取0
fixed4 fragExtractBright(v2f_img i) : SV_Target { // v2f_img为内置结构体, 里面只包含pos和uv
fixed4 c = tex2D(_MainTex, i.uv);
fixed val = saturate(luminance(c) - _LuminanceThreshold);
return c * val;
}
struct v2fBloom { // v2fBloom之所以不用v2f_img替代, 因为v2fBloom.uv是四维的, 而v2f_img.uv是二维的
float4 pos : SV_POSITION; // 裁剪空间顶点坐标
half4 uv : TEXCOORD0; // 纹理uv坐标
};
v2fBloom vertBloom(appdata_img v) {
v2fBloom o;
o.pos = UnityObjectToClipPos (v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
o.uv.xy = v.texcoord;
o.uv.zw = v.texcoord;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0.0)
o.uv.w = 1.0 - o.uv.w; // 平台差异化处理
#endif
return o;
}
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 {
CGPROGRAM
#pragma vertex vert_img // 使用内置的vert_img顶点着色器
#pragma fragment fragExtractBright
ENDCG
}
UsePass "MyShader/GaussianBlur/GAUSSIAN_BLUR_VERTICAL" // 垂直高斯模糊处理
UsePass "MyShader/GaussianBlur/GAUSSIAN_BLUR_HORIZONTAL" // 水平高斯模糊处理
Pass {
CGPROGRAM
#pragma vertex vertBloom
#pragma fragment fragBloom
ENDCG
}
}
FallBack Off
}
说明: vert_img 是 Unity 内置的顶点着色器,v2f_img 是 Unity 内置的结构体变量,vert_img 和 v2f_img 的实现见→Shader常量、变量、结构体、函数。
GaussianBlur.shader
Shader "MyShader/GaussianBlur" { // 高斯模糊
Properties{
_MainTex("Base (RGB)", 2D) = "white" {} // 主纹理
_BlurSize("Blur Size", Float) = 1.0 // 模糊尺寸(纹理坐标的偏移量)
}
SubShader{
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex; // 主纹理
half4 _MainTex_TexelSize; // _MainTex的像素尺寸大小, float4(1/width, 1/height, width, height)
float _BlurSize; // 模糊尺寸(纹理坐标的偏移量)
struct v2f {
float4 pos : SV_POSITION; // 模型空间顶点坐标
half2 uv[5]: TEXCOORD0; // 5个邻域的纹理坐标
};
v2f vertBlurVertical(appdata_img v) { // 垂直模糊顶点着色器
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
half2 uv = v.texcoord;
o.uv[0] = uv;
o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
return o;
}
v2f vertBlurHorizontal(appdata_img v) { // 水平模糊顶点着色器
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
half2 uv = v.texcoord;
o.uv[0] = uv;
o.uv[1] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
o.uv[2] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
return o;
}
fixed4 fragBlur(v2f i) : SV_Target {
float weight[3] = {0.4026, 0.2442, 0.0545}; // 大小为5的一维高斯核,实际只需记录3个权值
fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];
for (int j = 1; j < 3; j++) {
sum += tex2D(_MainTex, i.uv[j * 2 - 1]).rgb * weight[j]; // 中心右侧或下侧的纹理*权值
sum += tex2D(_MainTex, i.uv[j * 2]).rgb * weight[j]; // 中心左侧或上侧的纹理*权值
}
return fixed4(sum, 1.0);
}
ENDCG
ZTest Always Cull Off ZWrite Off
Pass {
NAME "GAUSSIAN_BLUR_VERTICAL"
CGPROGRAM
#pragma vertex vertBlurVertical
#pragma fragment fragBlur
ENDCG
}
Pass {
NAME "GAUSSIAN_BLUR_HORIZONTAL"
CGPROGRAM
#pragma vertex vertBlurHorizontal
#pragma fragment fragBlur
ENDCG
}
}
FallBack "Diffuse"
}
3 运行效果
调整模糊迭代次数 iterations 由 0 ~ 4 变化,效果如下:

声明:本文转自【Unity3D】Bloom特效。
【Unity3D】Bloom特效的更多相关文章
- Unity3d粒子特效:制作火焰效果
效果 分析 真实的火焰效果,通常包括:火.火光.火星等组成部分,而火焰对周围环境的烘焙,可以通过灯光实现,如点光源. 针对火焰组成部分,我们可以创建对应的粒子系统组件,实现相应的效果,如下图所示: 1 ...
- UnityShader实例15:屏幕特效之Bloom
http://blog.csdn.net/u011047171/article/details/48522073 Bloom特效 概述 Bloom,又称“全屏泛光”,是游戏中 ...
- 【Unity3D】基于粒子系统实现烟花特效
1 需求实现 粒子系统ParticleSystem 中介绍了粒子初始化.粒子发射.发射器形状.渲染器.碰撞.子发射器.拖尾等粒子系统的基本用法,本节将基于粒子系统实现烟花特效. 实现需求如下( ...
- 【Unity3D】 Unity Chan项目分享
写在前面 之前的一个博文里分享了日本Unity酱的项目,如果大家有去仔细搜Unity酱的话,就会发现日本Unity官方还放出了一个更完整的Unity酱的项目,感觉被萌化了!(事实上,Unity日本经常 ...
- Unity shader学习之屏幕后期处理效果之Bloom效果
Bloom特效是游戏中常见的一种屏幕效果.这种特效可以模拟真实摄像机的一种图像效果,它让画面中较亮的区域“扩散”到周围的区域中,造成一种朦胧的效果. Bloom的实现原理很简单,首先根据一个阈值提取出 ...
- HDR和bloom效果的区别和关系
什么是HDR? 谈论游戏画面时常说的HDR到底是什么呢?HDR,本身是High-Dynamic Range(高动态范围)的缩写,这本来是一个CG概念.HDR的含义,简单说,就是超越普通的 ...
- Metropolis Light Transport学习与实现
这段时间一直在看Metropolis Light Transport(简称mlt),现利用这篇博文把之前看资料已经coding上的一些体会记录下来. 1.Before MLT 在MLT算法被提出之前, ...
- Unity中HDR外发光的使用
1.使用标准材质,设置好Emission外发光 2.Camera下打开HDR,加上Bloom特效 最终效果 如果只勾选HDR,只会有高光感,不会有外发光 注意,正向光照下打开HDR不可用抗锯齿,否则切 ...
- Unity塔防游戏开发
Unity3D塔防开发流程 配置环境及场景搭建编程语言:C#,略懂些许设计模式,如果不了解设计模式,BUG More开发工具:Unity3D编辑器.Visual Studio编译器开发建议:了解Uni ...
- Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果
建立一个基本的屏幕后处理脚本系统 屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效.使用这种技术,可以为游戏画面添加更多艺术效果,例如景深. ...
随机推荐
- CSS - 正确解决 float 高度坍塌的问题
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta cha ...
- [转帖]JMeter 5.5 使用详解(持续更新中......)
https://blog.csdn.net/qq_45138120/article/details/124056704?ops_request_misc=%257B%2522request%255Fi ...
- [转帖]查看堆内对象的工具:jmap
文章目录 用途 命令格式 示例 一,no option 二,heap 三,histo[:live] 四,clstats 五,finalizerinfo 六,dump:<dump-options& ...
- [转帖]Nginx四层负载均衡详解
https://developer.aliyun.com/article/885599?spm=a2c6h.24874632.expert-profile.315.7c46cfe9h5DxWK 202 ...
- [转贴]中国铁塔发布2020年中期财报:营收、利润双增,高效支撑5G规模建设
中国铁塔发布2020年中期财报:营收.利润双增,高效支撑5G规模建设 https://tech.sina.com.cn/roll/2020-08-11/doc-iivhuipn8046256.sh ...
- 浪潮的CS5260F CS5260H CS5260Z
助力国产操作系统新生态!麒麟信安与东方通.浪潮.新华三.长城超云等多家生态伙伴完成产品兼容性认证 作者:湖南麒麟信安科技股份有限公司时间:2022-03-11 16:28:11 我要发布 关键词: 国 ...
- es6默认传参 es5的默认传参
在默认传参在实际中座中还是用的比较多的. 它可以用来解决,用户没有给定值的时候,默认给一个指定的值. es6默认传参 es5的默认传参 //es6 function say(a = 4) { cons ...
- 手撕Vue-编译模板数据
经上一篇编译指令数据后,我们已经可以将指令数据编译成具体需要展示的数据了,上一篇只是编译了指令数据,还没有编译模板数据,这一篇我们就来编译模板数据. 也就是 {{}} 这种模板的形式我们该如何编译,其 ...
- 4.基于Label studio的训练数据标注指南:情感分析任务观点词抽取、属性抽取
情感分析任务Label Studio使用指南 1.基于Label studio的训练数据标注指南:信息抽取(实体关系抽取).文本分类等 2.基于Label studio的训练数据标注指南:(智能文档) ...
- 从嘉手札<2023-11-01>
最近心态不好,如同此刻的天气,浓雾扰扰,看不见前途未来,也想不起过去. 一则是研究没有进展,二则是感情纷扰,其实再多的纷扰也都不过是自己内心的那层桎梏,可人不能总能保持理性的: 就像很多快乐的事情是简 ...