【Unity3D】高斯模糊特效

news2024/12/26 23:22:28

1 高斯模糊原理

        边缘检测特效中使用了卷积运算进行了边缘检测,本文实现的高斯模糊特效同样使用了卷积运算,关于卷积核和卷积运算的概念,读者可以参考边缘检测特效。

        本文完整资源见→Unity3D高斯模糊特效。

        我们将用于模糊处理的卷积核称为模糊算子,它一般满足以下条件:

  • 卷积核中权值上下对称、左右对称;
  • 卷积核中每个权值大于或等于 0,小于 1;
  • 卷积核中所有权值之和为 1。

        我们将所有权值都为 1 / n(n 为权值个数)的卷积核称为平均模糊算子;将权值随位置变化且符合高斯分布(或正太分布)的卷积核称为高斯模糊算子(或高斯核),它较好地模拟了邻域中每个像素对当前处理像素的影响程度(距离越近,影响越大)。高斯方程如下:

         σ 是标准差,其值越大,高斯分布函数的图像越矮胖,一般取值为 1,x、y 为当前位置到卷积核中心的整数距离。要构建一个高斯核,我们只需要计算高斯核中各个位置对应的高斯值。为了保证模糊处理后的图像不会变暗,我们需要对高斯核中的元素进行归一化,即将所有元素都除以它们的权值和,从而保证归一化后的权值和为 1。因此,高斯函数中 e 前面的系数不会对高斯核产生任何影响,在计算高斯核的过程中可以省去。

        高斯核的维数越高,模糊程度越大。使用一个 n * n 的卷积核,需要进行 n * n * w * h 次纹理采样(w、h 分别为图像的宽高),为节省性能,我们将二维高斯核拆分为 2 个一维高斯核,采样次数只需要 2 * n * w * h 次。进一步观察到,2 个高斯核中包含了很多重复权重。对于一个大小为 5 的一维高斯核,实际只需记录 3 个权值即可。

2 代码实现

        GaussianBlur.cs

using UnityEngine;

[ExecuteInEditMode] // 编辑态可以查看脚本运行效果
[RequireComponent(typeof(Camera))] // 需要相机组件
public class GaussianBlur : MonoBehaviour {
	[Range(0, 4)]
	public int iterations = 3; // 高斯模糊迭代次数
	[Range(0.2f, 3.0f)]
	public float blurSpread = 0.6f; // 每次迭代纹理坐标偏移的速度
	[Range(1, 8)]
	public int downSample = 2; // 降采样比率
	private Material material = null; // 材质

	private void Start() {
		material = new Material(Shader.Find("MyShader/GaussianBlur"));
		material.hideFlags = HideFlags.DontSave;
	}

	void OnRenderImage(RenderTexture src, RenderTexture dest) {
		if (material != null) {
			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);
			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, 0); // 渲染垂直的Pass
				RenderTexture.ReleaseTemporary(buffer0);
				buffer0 = buffer1;
				buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
				Graphics.Blit(buffer0, buffer1, material, 1); // 渲染水平的Pass
				RenderTexture.ReleaseTemporary(buffer0);
				buffer0 = buffer1;
			}
			Graphics.Blit(buffer0, dest);
			RenderTexture.ReleaseTemporary(buffer0);
		} else {
			Graphics.Blit(src, dest);
		}
	}
}

        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 运行效果

        1)原图

        2)模糊处理

        调整模糊迭代次数 iterations 由 0 ~ 4 变化,效果如下:

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

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

相关文章

C++模拟牛顿力学(2D)

简介 如何用计算机来模拟真实世界呢&#xff1f;计算机最大的功能是计算&#xff0c;而物理学的种种公式就把现实世界中的物理规律以数学的语言描绘了出来&#xff0c;从而使我们可以通过计算大致模拟现实世界的物体运动。因此不难想到把物理学定律&#xff08;这里用的是牛顿…

SAP-MM-维护物料主数据的类(Class)和特性(Characteristic)

一&#xff0e;说明 物料主数据有千个左右条目&#xff0c;但仍不能满足各类物料自有特性的描述&#xff0c;为此SAP启用了类&#xff08;Class&#xff09;和特性&#xff08;Characteristic&#xff09;&#xff0c;并在物料主数据的分类视图&#xff08;Characteristic&…

推荐一款免费开源的代码质量分析工具

文章目录 一、简介二、环境安装三、使用说明四、其他报错UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe6 in position 29: ordinal not in range(128)**linux:****windos:** 五、安全编程规范 一、简介 Flawfinder是一款开源的关于C/C静态扫描分析工具&#xf…

C++入门——关键字|命名空间|输入输出

前言&#xff1a; 今天我们又开启了一个崭新的大门——C面向对象编程语言&#xff0c;C是怎么来的呢&#xff1f;答案是&#xff1a;因为C语言的有很多不足&#xff0c;我们的祖师爷用着不爽&#xff0c;就不断更改&#xff0c;就改出来了一门新的语言&#xff0c;C。C语言兼容…

黑客常用的十大工具(附工具安装包),你知道几款?

注&#xff1a;本文总结白帽黑客常用的十大工具。文档仅供参考&#xff0c;不得用于非法用途&#xff0c;否则后果自负。 1 Nmap nmap是一个网络连接端扫描软件&#xff0c;用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端&#xff0c;并且推断计算机运行哪个…

谈谈开源的利弊和国内的开源 ——《新程序员005:开源深度指南 新金融背后的科技力量》书评

感谢CSDN的送测 《新程序员005&#xff1a;开源深度指南 & 新金融背后的科技力量》 是一本以计算机编程和金融科技为主题的杂志书&#xff0c;由中国最大的开源社区之一的开源社主办&#xff0c;内容丰富多样&#xff0c;包括了众多知名开源项目和工具的介绍&#xff0c;同…

第 3 章:使用 Vue 脚手架

目录 具体步骤 模板项目的结构&#xff08;脚手架文件结构&#xff09; Vue脚手架报错 修改方案&#xff1a; 关于不同版本的Vue vue.config.js配置文件 ref属性 props配置项 mixin(混入) 插件 小结&#xff1a; scoped样式 小结&#xff1a; Todo-list 案例 小结…

kafka重点问题解答-----kafka 的设计架构

1. kafka 都有哪些特点&#xff1f; 高吞吐量&#xff0c;低延迟 可以热扩展 并发度高 具有容错性(挂的只剩1台也能正常跑) 可靠性高 2. 请简述你在哪些场景下会选择 kafka&#xff1f; kafka的一些应用 日志收集&#xff1a;一个公司可以用kafka可以收集各种服务的log&…

自学黑客(网络安全/web渗透),一般人我还是劝你算了吧

由于我之前写了不少网络安全技术相关的文章&#xff0c;不少读者朋友知道我是从事网络安全相关的工作&#xff0c;于是经常有人私信问我&#xff1a; 我刚入门网络安全&#xff0c;该怎么学&#xff1f; 要学哪些东西&#xff1f; 有哪些方向&#xff1f; 怎么选&a…

chatgpt赋能python:Python分解三位数:打造高效的数学学习工具

Python分解三位数&#xff1a;打造高效的数学学习工具 介绍 Python是一种动态、解释型、高级编程语言&#xff0c;广泛应用于数据分析、人工智能、机器学习等领域。在数学教育中&#xff0c;Python也是一个非常好的工具&#xff0c;可以帮助学生更好地理解数学知识和提高解题…

Linux内核模块开发 第 6 章

The Linux Kernel Module Programming Guide Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang译 断水客&#xff08;WaterCutter&#xff09; 6 字符设备驱动 include/linux/fs.h 中定义了结构体 file_operations &#xff0c;这个结构体包含指…

深度学习论文分享(三)Look More but Care Less in Video Recognition(NIPS2022)

深度学习论文分享&#xff08;三&#xff09;Look More but Care Less in Video Recognition&#xff08;NIPS2022&#xff09; 前言Abstract1. Introduction2 Related Work2.1 Video Recognition2.2 Redundancy in Data&#xff08;数据冗余&#xff09; 3 Methodology3.1 Arc…

Apache 虚拟主机企业应用

企业真实环境中&#xff0c; 一台服务器发布单个网站非常浪费资源&#xff0c;所以一台 web 服务器上会发布多个网站少则2~3个多则 30多个网站 在一台服务器上发布多网站&#xff0c;也称之为部署多个虚拟主机&#xff0c; Web 虚拟主机配置方法有以下 种&#xff1a; 1、基于单…

基于机器学习的内容推荐算法及其心理学、社会学影响闲谈

基于机器学习的内容推荐算法目前在各类内容类APP中使用的非常普遍。在购物、时尚、新闻咨询、学习等领域&#xff0c;根据用户的喜好&#xff0c;进行较为精准的用户画像与内容推荐。此类算法不但可以较为准确的分析用户的特征&#xff0c;如年龄、性别等&#xff0c;还能通过长…

QT项目实战(视频播放器)

文章目录 前言一、QMediaPlayer二、QVideoWidget三、QAudioOutput四、播放器代码实现五、最终效果总结 前言 本篇文章将使用QT6.4来实现一个简单视频播放器&#xff0c;在QT中使用一个视频播放器还是非常简单的。那么下面就让我们一起来实现这个视频播放器吧。 一、QMediaPla…

深度学习应用篇-计算机视觉-图像增广[1]:数据增广、图像混叠、图像剪裁类变化类等详解

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

基于VGG16实现宝石图像分类任务(acc 84%)--paddle paddle

作业&#xff1a;补充网络定义部分&#xff0c;使用卷积神经网络实现宝石分类 要求&#xff1a;1.补充完成CNN的网络结构定义方法实现宝石识别 2.可尝试不同网络结构、参数等力求达到更好的效果 卷积神经网络 卷积神经网络是提取图像特征的经典网络&#xff0c;其结构一般包…

【hello C++】类和对象(下)

目录 1. 再谈构造函数 1.1 构造函数体赋值 1.2 初始化列表 1.3 explicit关键字 2. static成员 2.1 概念 2.2 特性 3. 友元 3.1 友元函数 3.2 友元类 4. 内部类 5.匿名对象 6.拷贝对象时的一些编译器优化 7. 再次理解类和对象 1. 再谈构造函数 1.1 构造函数体赋值 在创建对象…

Spring Boot项目使用 jasypt 加密组件进行加密(例如:数据库、服务的Key、等等进行加密)

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

【018】C++的指针数组和数组指针

C 指针数组和数组指针 引言一、指针数组1.1、数值的指针数组1.2、字符的指针数组1.3、二维字符数组 二、指针的指针三、数组指针3.1、数组首元素地址和数组首地址3.2、数组指针的使用示例3.3、二维数组和数组指针的关系 四、多维数组的物理存储总结 引言 &#x1f4a1; 作者简介…