【Unity3D】Bloom特效

news2024/11/23 18:36:09

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);
			//return 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 变化,效果如下: 

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

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

相关文章

OS-内存管理1- 4种基本管理方式(连续分配,页式,段式,段页)。

一&#xff0c;内存管理四种方式。 二&#xff0c;连续分配管理方式。 连续分配方式&#xff1a;为用户分配连续的内存空间。 1.单一连续分配方式 2.固定分区分配方式 3.动态分区分配方式 4.三种连续分配方式的对比。 三&#xff0c;基于页式存储管理。 1.页式 为进一步提高…

嵌入式系统中I2C总线通信基本方法

将 I2C spec 文章总结为一篇&#xff0c;目录如下 I2C Introduction I2C Architecture I2C Transfer I2C Synchronization And Arbitration I2C Hs-mode1、I2C Introduction 1、I2C 历史 I2C&#xff1a;Inter-Integrated Circuit&#xff0c;集成电路总线。 I2C 是 Philips…

部分网络结构记录

CVPR 2022 | Mobile-Former来了&#xff01;微软提出&#xff1a;MobileNetTransformer轻量化并行网络 文章链接: CVPR 2022 | Mobile-Former来了&#xff01;微软提出&#xff1a;MobileNetTransformer轻量化并行网络 - 知乎 (zhihu.com) Mobile-Former架构图 Mobile-Form…

Mybatis学习笔记一

目录 一、Mybatis特性二、快速入门1.导入依赖2.mybatis-config.xml配置3.创建mapper接口4.创建MyBatis的映射文件5.通过junit测试功能 三、MyBatis获取参数值的两种方式&#xff08;重点&#xff09;1.单个字面量类型的参数2.多个字面量类型的参数3.map集合类型的参数4.实体类类…

【六一特别文章】Python编写一个六一儿童节问答小游戏及趣味比赛

随着六一儿童节的到来&#xff0c;我们可以为孩子们编写一个有趣的小游戏&#xff0c;让他们在游戏中学习有关六一儿童节的知识。本文将介绍如何用Python编写一个六一儿童节问答小游戏及趣味比赛。 首先&#xff0c;我们需要准备一些有关六一儿童节的问题和答案。这里我准备了…

云原生之docker详解

目录 1.云原生概念 1.1 云原生定义 1.2 云原生元素 1.2.1 微服务 1.2.2 DevOps 1.2.3 持续交付 1.2.4 容器化 2. Docker 2.1 Docker概述 2.1.1 Docker 定义 2.1.2 Docker应用场景 2.1.3 Docker的架构 2.2 Docker命令 2.2.1 docker进程相关命令 2.2.2 docker镜像…

htmlCSS-----CSS选择器(下)

目录 前言&#xff1a; 2.高级选择器 &#xff08;1&#xff09;子代选择器 &#xff08;2&#xff09;伪类选择器 &#xff08;3&#xff09;后代选择器 &#xff08;4&#xff09;兄弟选择器 相邻兄弟选择器 通用兄弟选择器 &#xff08;5&#xff09;并集选择器 &am…

测试进阶必备,这5款http接口自动化测试工具真的很香

现在市场上能做接口自动化测试的工具有很多&#xff0c;一搜一大把&#xff0c;让人眼花缭乱。我们去选择对应实现方式时&#xff0c;不管是框架体系还是成熟稳定的工具&#xff0c;核心目的都是期望引入的技术能在最低投入的情况下达到最优效果。 那么我们选择依据出来了&…

LearnOpenGL-高级OpenGL-9.几何着色器

本人初学者&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 文章目录 几何着色器使用几何着色器造几个房子爆破物体法向量可视化 几何着色器 简介 在顶点和片段着色器之间有一个可选的几何着色器几何着色器的输入是一个图元&#xff08;如点或三角形&#xff09;的一…

【02】STM32·HAL库开发-Cortex-M系列介绍 | Cortex内核分类及特征 | Cortex-M3/M4/M7介绍

目录 1.ARM公司&#xff08;了解&#xff09;2.Cortex内核分类及特征&#xff08;了解&#xff09;3.Cortex-M3/4/7介绍&#xff08;了解&#xff09; 1.ARM公司&#xff08;了解&#xff09; ARM的R是RISC&#xff08;精简指令集计算机&#xff09;的缩写。ARM公司只做内核设计…

数学模型在水环境影响评价、防洪评价与排污口论证项目中的应用

数学模型在水环境评价、防洪评价和排污口论证等领域中的重要作用&#xff0c;随着人类活动的不断增加和环境问题的日益突出&#xff0c;对水资源和水环境的保护与管理变得至关重要。为了更好地理解和应对这些挑战&#xff0c;数学模型成为一种强大的工具&#xff0c;能够提供量…

ubuntu22.04使用kk安装kubernates1.20.4和kubesphere3.1.1

注意 存储空间不够可能安装失败 环境 master 192.168.1.108node1 192.168.1.106node2 192.168.1.102 root ssh登录 sudo passwd root sudo apt install openssh-server # 定位 /PermitRootLogin 添加 PermitRootLogin yes # 注释掉#PermitRootLogin prohibit-password #St…

【Jenkins+Ant+Jmeter】持续集成接口测试平台搭建

一、环境准备&#xff1a; 1、JDK&#xff1a;Java Downloads | Oracle 2、Jmeter&#xff1a;Apache JMeter - Download Apache JMeter 3、Ant&#xff1a;Apache Ant - Binary Distributions 4、Jenkins&#xff1a;Jenkins 二、Jemter脚本准备&#xff1a; 1、脚本目录&a…

PyTorch实验—回归任务

PyTorch回归任务 回归任务概述&#xff1a;通过pytorch搭建神经网络&#xff0c;进行气温的预测 回归任务可以看作 y kx b y为需要进行回归预测的值 下面对实验步骤进行整理 导入相关的库 import numpy as np import pandas as pd import matplotlib.pyplot as plt import…

张小飞的Java之路——第四十四章——其他流对象

写在前面&#xff1a; 视频是什么东西&#xff0c;有看文档精彩吗&#xff1f; 视频是什么东西&#xff0c;有看文档速度快吗&#xff1f; 视频是什么东西&#xff0c;有看文档效率高吗&#xff1f; 诸小亮&#xff1a;这一节&#xff0c;我们介绍一下其他不常用的流对象 …

SAP-MM-分割评估-评估类型-评估类别

同一物料的使用&#xff0c;既有“自制品”&#xff0c;又有“外购品”&#xff0c;并且其来源不同&#xff0c;如同一外购品由不同的供应商提供&#xff0c;价格也不相同。也就是说:同一物料有不同的价值指派&#xff0c;即在不同的条件下&#xff0c;同一物料可能有不同的价值…

智能型数字档案馆构建设想

档案作为企业正式权威的数据资源&#xff0c;具有其历史传承和凭证唯一性等特点&#xff0c;随着企业的数字化转型&#xff0c;档案工作更需要数字化转型&#xff0c;档案管理与利用急需借助信息技术手段来管理好和记录好&#xff0c;急需挖掘档案资源&#xff0c;发挥其价值&a…

01.硬盘启动盘,加载操作系统

硬盘启动盘&#xff0c;加载操作系统 模拟硬盘加载操作系统 环境&#xff1a; VMware16 Ubuntu16.04 qemu bochs 2.7 参考: 启动&#xff0c;BIOS&#xff0c;MBR 硬盘控制器主要端口寄存器 《操作系统真相还原》 1.系统开机流程 暂不构建中断向量表&#xff0c;直接加载MBR …

Knowledge Distillation: A Survey

本文是蒸馏学习综述系列的第一篇文章&#xff0c;主要是针对2021年 IJCV Knowledge Distillation: A Survey的一个翻译。 知识蒸馏&#xff1a;综述 摘要1 引言2 知识2.1 基于响应的知识2.2 基于特征的知识2.3 基于关系的知识 3 蒸馏方案3.1 离线蒸馏3.2 在线蒸馏3.3 自蒸馏 4…

你真的了解epoll吗?深入epoll的五个问题

由于epoll用的比较多&#xff0c;最近看到一些网友关于epoll的问答&#xff0c;所以我就想整理成一篇文章&#xff0c;这样看起来和理解起来都方便一些。 问题1&#xff1a;什么是epoll的ET/LT模式&#xff0c;select/poll支持吗&#xff1f; ET是edge trigger&#xff0c;也…