【TA100】Bloom算法

news2024/12/29 9:15:59

一、什么是Bloom算法

1、首先看一下Bloom效果长什么样

在这里插入图片描述

2、什么是Bloom

● Bloom,也称辉光,是一种常见的屏幕效果
● 模拟摄像机的一种图像效果,让画面中较亮的区域“扩散”到周围的区域中,造成一种朦胧的效果
● 可以让物体具有真实的明亮效果
● 可以实现光晕效果
在这里插入图片描述

3、Bloom的实现原理

①Bloom实现原理
● 实现思路:
○ 1.提取原图较亮区域(利用阈值)
○ 2.模糊该图像
○ 3.与原图混合/叠加
在这里插入图片描述

● /在HDR和LDR的那节课中也提到过bloom,我直接把当时的作的一张流程图摘过来以供参考:
○
②前置知识1:HDR和LDR
● HDR和LDR分别是是高动态范围和低动态范围的缩写
● LDR
○ jpg、png格式图片
○ RGB在[0,1]

● HDR
○ HDR、EXR格式图片
○ 可以超过1
● 因为自然界中的亮度差异是很大的(比如蜡烛的光强度约为15,而太阳的强度约为10w),只用LDR的话很多效果完全表现不出来

③前置知识2:高斯模糊
● 实现图像模糊的一种方式
● 高斯模糊:
○ 利用高斯核进行卷积运算,得到模糊的图像
在这里插入图片描述
高斯核
○ 高斯核:
■ 通过高斯函数定义的卷积核
○ 核中心:(0,0)
○ 核大小:3x3
○ 标准方差σ:1.5
○ 计算步骤:
■ 将(x,y)带入公式中,计算出权重值,(权重值代表当前处理像素的影响程度,离中心越近权重越大)
■ 为了保证卷积后图像不变暗,需要对高斯核进行归一化处理(每个权重除以所有权重的和)
请添加图片描述
在这里插入图片描述
● 补充:
○ 参考:GAMES101-L6内容
○ 滤波(Filtering)
■ 滤波就是抹掉特殊频率的东西
■ 不同滤波的效果:
● 高通滤波 = 边界
● 低通滤波 = 模糊
在这里插入图片描述

○ 滤波(Filtering)=卷积(Convolution)=平均(Averaging)
○ 卷积操作的定义
■ ①原始信号的任意一个位置,取其周围的平均
■ ②作用在一个信号上,用一种滤波操作,得到一个结果Result

三、 Bloom算法的应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
四、Reference
● 图片参考:· https://unsplash.com/·
● 自行拍摄项目参考:· https://github.com/keijiro/KinoBloom· https://github.com/MarcusXie3D/FastBloomForMobiles
● 资料参考:
○ learnopengl:https://learnopengl.com/Advanced-Lighting/Bloom·
○ Unity Shader入门精要:12.5 Bloom效果·
○ https://en.wikipedia.org/wiki/Bloom_(shader_effect)
○ https://en.wikipedia.org/wiki/High_dynamic_range
○ https://zhuanlan.zhihu.com/p/76505536

Shader "Unlit/DS_Bloom"
{
    Properties
    {
        // _MainTex为渲染纹理,变量名固定不能改变
        //模糊结果、阈值、模糊半径的变量名与C#脚本中的对应
        _MainTex ("Texture", 2D) = "white" {}
        _Bloom ("Bloom (RGB)", 2D) = "black" {} //高斯模糊后的结果
		_LuminanceThreshold ("Luminance Threshold", Float) = 0.5 //阈值
		_BlurSize ("Blur Size", Float) = 1.0 //模糊半径
    }
    SubShader
    {
        //用CGINCLUDE和ENDCG
        //Unity会把它们之间的代码插入到每一个pass中,已达到声明一遍,多次使用的目的。
        CGINCLUDE
        #include "UnityCG.cginc"

        //声明属性和C#脚本中用到的变量
        sampler2D _MainTex;
		half4 _MainTex_TexelSize;//纹素大小
		sampler2D _Bloom;
		float _LuminanceThreshold;
		float _BlurSize;

        //########第1个pass使用########
        //输出结构
        struct v2fExtractBright {
			float4 pos : SV_POSITION; 
			half2 uv : TEXCOORD0;
		};
        
        //顶点着色器
        v2fExtractBright vertExtractBright(appdata_img v) {
        	//appdata_img是官方提供的输入结构,只包含图像处理时必须的顶点坐标和uv等变量
			v2fExtractBright o;
			o.pos = UnityObjectToClipPos(v.vertex);
			o.uv = v.texcoord;	 
			return o;
		}
        
        // 明亮度公式
        // 在RGB模式下,像素亮度的计算公式为:L=R*0.30+G*0.59+B*0.11,简称305911公式
		fixed luminance(fixed4 color) {
        	//计算得到像素的亮度值
			return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; 
		}
        
        //片元着色器->提取高亮区域
        fixed4 fragExtractBright(v2fExtractBright i) : SV_Target {
        	fixed4 c = tex2D(_MainTex, i.uv);// 贴图采样
			
			// 调用luminance得到采样后像素的亮度值,再减去阈值
			// 使用clamp函数将结果截取在[0,1]范围内
			//clamp() 函数的作用是把一个值限制在一个上限和下限之间,当这个值超过最小值和最大值的范围时,在最小值和最大值之间选择一个值使用
			fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0);
			// 将val与原贴图采样得到的像素值相乘,得到提取后的亮部区域
			return c * val;
		}

        
        //########第2、3个pass使用########
        //输出结构
        struct v2fBlur {
			float4 pos : SV_POSITION;
        	half2 uv[5]: TEXCOORD0;
			// 此处定义5维数组用来计算5个纹理坐标
        	// 由于卷积核大小为5x5的二维高斯核可以拆分两个大小为5的一维高斯核
        	// uv[0]存储了当前的采样纹理
        	// uv[1][2][3][4]为高斯模糊中对邻域采样时使用的纹理坐标
		};
        
        //顶点着色器->计算竖直方向进行高斯模糊的uv
        v2fBlur vertBlurVertical(appdata_img v) {
			
			v2fBlur o;
			o.pos = UnityObjectToClipPos(v.vertex);//将顶点从模型空间变换到裁剪空间下
			half2 uv = v.texcoord;
			o.uv[0] = uv;
        	//uv[0]就是(0,0)
        	//对竖直方向进行模糊
			//对应到邻域就是下边的情况
        	//uv[1],向上挪动1个单位(0, 1)
        	//uv[2],向下挪动1个单位(0, -1)
        	//uv[3],向上挪动2个单位(0, 2)
        	//uv[3],向下挪动2个单位(0, -2)
        	//最后乘上模糊半径作为参数控制
			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;
		}
        
        //顶点着色器->计算水平方向进行高斯模糊的uv
        v2fBlur vertBlurHorizontal(appdata_img v) {
			v2fBlur o;
			o.pos = UnityObjectToClipPos(v.vertex);
			half2 uv = v.texcoord;
        	o.uv[0] = uv;
        	//uv[0]就是(0,0)
        	//对水平方向进行模糊
			//同理,uv[1]到[4]分别对应(1, 0)、(-1, 0)、(2, 0)、(-2, 0)
			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(v2fBlur i) : SV_Target {
			float weight[3] = {0.4026, 0.2442, 0.0545};
        	// 因为二维高斯核具有可分离性,而分离得到的一维高斯核具有对称性
			// 所以只需要在数组存放三个高斯权重即可
			
			fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];
        	// 结果值sum初始化为当前的像素值乘以它对应的权重值

        	// 进行卷积运算,根据对称性完成两次循环
			// 第一次循环计算第二个和第三个格子内的结果
			// 第二次循环计算第四个和第五个格子内的结果
			for (int it = 1; it < 3; it++) {
				sum += tex2D(_MainTex, i.uv[it*2-1]).rgb * weight[it];
				sum += tex2D(_MainTex, i.uv[it*2]).rgb * weight[it];
			}
			
			return fixed4(sum, 1.0);// 返回滤波后的结果
		}

        
        //########第4个pass使用########
        //输出结构
        struct v2fBloom {
			float4 pos : SV_POSITION; 
			half4 uv : TEXCOORD0;
		};

        //顶点着色器
        v2fBloom vertBloom(appdata_img v) {
			v2fBloom o;
			o.pos = UnityObjectToClipPos (v.vertex);
			
			o.uv.xy = v.texcoord; //xy分量为_MainTex的纹理坐标		
			o.uv.zw = v.texcoord; //zw分量为_Bloom的纹理坐标
			
			// 平台差异化处理
        	//判断y是否小于0,如果是就进行翻转处理
			#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,提取较亮区域
        Pass{
            CGPROGRAM
			#pragma vertex vertExtractBright
			#pragma fragment fragExtractBright
            ENDCG
        }
	    
    	//第二个pass,进行竖直方向高斯模糊
    	Pass{
            CGPROGRAM
			#pragma vertex vertBlurVertical
			#pragma fragment fragBlur
            ENDCG
        }
    	
    	//第三个pass,进行水平方向高斯模糊
    	Pass{
            CGPROGRAM
			#pragma vertex vertBlurHorizontal
			#pragma fragment fragBlur
            ENDCG
        }
    	
    	//第四个pass,混合高亮区域和原图
    	Pass{
            CGPROGRAM
			#pragma vertex vertBloom
			#pragma fragment fragBloom
            ENDCG
        }
    }
	FallBack Off
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/688598.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[JVM]再聊 CMS 收集器

题目之所以是再聊,是因为以前聊过: [JVM]聊聊 CMS 收集器 最近又看了下这块的知识,打算把 CMS/标记-清除/GC Roots/引用 这些知识串起来 我依旧可能写的不是很好,降低下期待 GC 算法 CMS 是基于 标记-清除 算法来做的,那我们就先从 GC 算法开始聊 GC 算法有: 标记-清除 标…

一篇博客教会你使用Docker部署Redis哨兵

文章目录 主数据库配置文件启动实例容器虚拟IP 从数据库配置文件启动实例 主从数据库查看主数据库查看从数据库 哨兵配置文件启动哨兵查看哨兵 哨兵机制哨兵选举选举日志重启主数据库 今天我们学习使用 Docker 部署 Redis 的主从复制&#xff0c;并部署 Redis 哨兵&#xff0c;…

Linux学习之grub配置文件介绍

grub配置文件 /etc/default/grub这个文件里边有一些简单的grub配置。 可以看到/etc/default/grub文件里有GRUB_CMDLINE_LINUX"crashkernelauto rhgb quiet idlehalt biosdevname0 net.ifnames0 consoletty0 consolettyS0,115200n8 noibrs nvme_core.io_timeout429496729…

全网独家--【图像色彩增强】方法梳理和问题分析

文章目录 图像增强图像色彩增强问题可视化比较 难点色彩空间大&#xff0c;难以准确表征&#xff1f;不同场景差异大&#xff0c;难以自适应&#xff1f;计算量大&#xff0c;但应用场景往往实时性要求高&#xff1f; 方法传统方法深度学习逐像素预测3D LUT模仿ISP 个人思考批判…

2.数据的类型、数据的输入输出

2.数据的类型、数据的输入输出 2.1 数据类型-常量-变量(整型-浮点-字符)2.1.1 数据类型2.1.2 常量2.1.3 变量2.1.4 整型类型2.1.5 浮点型数据2.1.6 字符型数据字符型常量字符型变量 2.1.7 字符串型常量 2.2 混合运算-printf讲解 2.1 数据类型-常量-变量(整型-浮点-字符) 2.1.1…

shell脚本怎么获取当前脚本名称(获取脚本文件名)$(basename “$0“)(basename命令:去除字符串路径部分、去除后缀)

文章目录 shell脚本如何获取当前执行脚本名称解释&#xff1a;$(basename "$0")$0&#xff08;当前脚本的名称&#xff0c;带脚本与工作目录之间的相对路径&#xff09;basename&#xff08;去除字符串路径部分&#xff09;示例 拓展&#xff1a;basename命令的完整用…

项目引入多个连接池,导致使用其他连接池,maven分析学习

第一步在命令行中执行 mvn dependency:tree > excludeParentstart.log如果你的settings文件不是项目使用的setting配置&#xff0c;那么就使用下面的命令 mvn -gs 你的路径/apache-maven-3.8.2/conf/settings-person.xml dependency:tree > excludeParentstart.log然后…

Spring学习---上篇

文章目录 1、Spring1.1、简介1.2、优点1.3、Spring的组成1.4、拓展 2、IOC理论推导3、IOC的本质3.1、IOC概念3.2、IoC是Spring框架的核心内容 3、HelloSpring3.1、实现3.2、思考 4、IOC创建对象的方式5、Spring配置5.1、别名&#xff08;alias&#xff09;5.2、Bean的配置5.3、…

Multi-class classification without multi-class labels (ICLR 2019)

Multi-class classification without multi-class labels (ICLR 2019) 摘要 这项工作提出了针对多分类的新策略&#xff0c;不需要具体的类别标签&#xff0c;取而代之是利用样本之间的两两相似度&#xff0c;这是一种弱化的标注方式。所提方法称作元分类学习&#xff0c;为两…

ModaHub魔搭社区:向量数据库Milvus使用 MySQL 管理元数据教程

目录 使用 MySQL 管理元数据 常见问题 数据管理相关博客 使用 MySQL 管理元数据 Milvus 默认使用 SQLite 作为元数据后台管理服务&#xff0c;SQLite 内嵌于 Milvus 进程中&#xff0c;无需启动额外服务。但是在生产环境中&#xff0c;基于可靠性的考虑&#xff0c;我们强烈…

【数据库管理】十分钟了解啥是三级封锁协议、X锁和S锁

一.为什么要用锁 在多用户共享系统中&#xff0c;许多事务可能同时对同一数据进行操作&#xff0c;称为“并发操作”&#xff0c;此时数据库管理系统的并发控制子系统负责协调并发事务的执行&#xff0c;保证数据库的完整性不受破坏&#xff0c;同时避免用户得到不正确的数据。…

Spring框架概括

spring是什么&#xff1f; Spring是2003年兴起的&#xff0c;它是一个轻量级的&#xff0c;非侵入式的IOC和AOP的一站式框架&#xff0c;为简化企业级应用开发。 它的特点&#xff1a; 轻量级&#xff1a;指的是核心jar包比较小的。 非侵入式的&#xff1a;框架代码不会侵入…

Java——《面试题——MQ篇》

前文 java——《面试题——基础篇》 Java——《面试题——JVM篇》 Java——《面试题——多线程&并发篇》 Java——《面试题——Spring篇》 Java——《面试题——SpringBoot篇》 Java——《面试题——MySQL篇》​​​​​​ Java——《面试题——SpringCloud》 Java…

KingFusion3.6是什么?

哈喽&#xff0c;大家好&#xff0c;我是雷工&#xff01; 今天继续学习KingFusion3.6&#xff0c;以下为学习笔记。 一、KingFusion3.6简介 1、管控一体化全组态平台KingFusion3.6是一款面向工业企业执行层的生产信息化管理系统。 2、KingFusion3.6基于“全组态”技术&#…

使用ROS功能包camera_calibration进行单目相机和双目相机的内参和外参标定

1.概述 本文总结使用ROS标定单目和双目相机的过程&#xff0c;同时提供生成棋盘格文件的方法。 参考链接&#xff1a; [1]使用ros标定相机的内参和外参 [2]ROS下采用camera_calibration进行双目相机标定 2.生成棋盘格文件 棋盘格可以自己买一个&#xff0c;或者打印一个粘在…

日本团队推出 AI 恋爱游戏:主角穿什么,玩家说了算

女主穿什么&#xff0c;还能由玩家决定&#xff1f;&#xff01; IT之家6月25日消息&#xff0c;来自日本的一个两人团队近期发布了一段视频&#xff0c;展示了一款正在开发中的基于 AI 的恋爱游戏。 在游戏初期&#xff0c;女主角会以黑色剪影的形式出现&#xff0c;针对女主…

紫云谷游记

先说重点&#xff0c;TLNR 1.早点去&#xff0c;方便找地方停车&#xff0c;坐渡船不用排队太久。 2.景区里的饭没外面的好吃。 3.溯溪回来再在游泳池游泳&#xff0c;溯溪凉快&#xff0c;游泳太晒。 4.溯溪真的好爽。 导航&#xff1a; 紫云谷乘船码头停车场 景区介绍就不多说…

常见电池容量概念

嵌入式软件做产品一定要考虑功耗问题 功耗是多少&#xff0c;装上电池能用多久。 1、毫安时和毫瓦时 毫安时&#xff08;mAh&#xff09;和毫瓦时&#xff08;mWh&#xff09;是两个不同的物理量&#xff0c;它们分别表示电量和能量的度量单位。下面图片搜18650得到不同结果&…

Elasticsearch介绍与应用

Elasticsearch介绍与应用 Elasticsearch的官方文档。 Elasticsearch官网参考文档&#xff1a;https://www.elastic.co/guide/index.html Elasticsearch官方下载地址&#xff1a;https://www.elastic.co/cn/downloads/elasticsearch mvnrepository依赖库地址&#xff1a;http…

你对工作队列了解多少?Linux中断处理中的workqueue介绍

Linux中断处理中的workqueue介绍 一、workqueue的作用及在Linux中断处理中的应用1.1、workqueue的概述1.2、workqueue在Linux中断处理中的作用 二、workqueue的实现原理2.1、工作队列和工作者线程的关系2.2、工作队列的创建和销毁2.3、工作者线程的创建和销毁2.4、扩展知识&…