【Unity】URP屏幕后处理UI模糊效果实现

 这里Canvas(1)设置为Overlay能渲染出指定UI高清,其他UI模糊,然而这做法非常不好,如果此时再打开UI 以及 关闭模糊效果 要将这些置顶UI 恢复到原本Canvas里,也就是要管理2套Canvas

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;public class Blur : ScriptableRendererFeature
{[Serializable] //序列化 会在ForwardRenderer下创建Blur时看到m_Data就是它public class BlurData{//blur材质public Material material;public RenderPassEvent renderPassEvent = RenderPassEvent.AfterRenderingPostProcessing;//渲染次数,次数越大图像会越模糊[Range(0, 4)]public int iterations = 3;//模糊采样间距,越大越模糊[Range(0.2f, 3.0f)]public float blurSpread = 0.6f;//缩小比例(2代表缩小1/2) 越大越模糊,性能越好,但是会逐渐像素化![Range(1, 8)]public int downSample = 2;}public class BlurRenderPass : ScriptableRenderPass{private BlurData m_Data; //ForwardRenderer下Blur(ScriptableRendererFeature)资源的序列化参数数据private RenderTargetIdentifier m_Source;//屏幕图private RenderTargetHandle m_Buffer0;//缓冲区1private RenderTargetHandle m_Buffer1;//缓冲区2private int m_BlurSize = Shader.PropertyToID("_BlurSize");public BlurRenderPass(BlurData data){this.m_Data = data;}public void Setup(RenderTargetIdentifier cameraColorTarget){m_Buffer0.Init("_Buffer0");m_Buffer1.Init("_Buffer1");this.m_Source = cameraColorTarget;//该pass所在管线 ForwardRenderer 所处的摄像机主纹理}public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor){var width = cameraTextureDescriptor.width / m_Data.downSample;var height = cameraTextureDescriptor.height / m_Data.downSample;cmd.GetTemporaryRT(m_Buffer0.id, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);cmd.GetTemporaryRT(m_Buffer1.id, width, height, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32);}public override void FrameCleanup(CommandBuffer cmd){cmd.ReleaseTemporaryRT(m_Buffer0.id);cmd.ReleaseTemporaryRT(m_Buffer1.id);}public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){var mat = m_Data.material;if (mat == null) return;//renderingData.cameraData.camera 可获取摄像机判定哪个摄像机才进行处理渲染(每个摄像机都会进一遍pass 如果摄像机有多个且都有这个Blur(ScriptableRendererFeature资源)CommandBuffer cmd = CommandBufferPool.Get("MyBlurCmd"); //从池获取一个cmd 命名为MyBlurCmd 能在FrameDebugger看到cmd.Blit(m_Source, m_Buffer0.Identifier());//将摄像机图渲染至buffer0//开始iterations次渲染,每次都会进行2次Pass操作:横向、纵向(谁先谁后都无所谓for (int i = 0; i < m_Data.iterations; i++){mat.SetFloat(m_BlurSize, 1.0f + i * m_Data.blurSpread);//指定采样间距,逐级递增的形式cmd.Blit(m_Buffer0.Identifier(), m_Buffer1.Identifier(), mat, 0);var tmp = m_Buffer0;m_Buffer0 = m_Buffer1; //注意最终都会将渲染结果输出到m_Buffer0m_Buffer1 = tmp;}cmd.Blit(m_Buffer0.Identifier(), m_Source); //将最终结果渲染到摄像机上//执行cmdcontext.ExecuteCommandBuffer(cmd);//清空回收cmdcmd.Clear();CommandBufferPool.Release(cmd);}}public BlurData data = new BlurData();private BlurRenderPass m_Pass;public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){var src = renderer.cameraColorTarget;m_Pass.Setup(src); //设置摄像机输出的颜色纹理renderer.EnqueuePass(m_Pass); //入队渲染pass}public override void Create(){m_Pass = new BlurRenderPass(data); //创建一个passm_Pass.renderPassEvent = data.renderPassEvent; //设置pass的渲染时机在某个节点后(导致问题,无法类似grab一样在某一个UI渲染时进行渲染 而必须等到所有UI渲染完成才进行渲染。。//无法做到置顶UI高清,底下UI模糊的效果.//所以下一步是思考如何实现这个吧..}
}

Shader代码实现模糊 

//注意 注释掉的CGINCLUDE CDEND UnityCG.cginc 等一系列带cg或注释的方法都是传统CG管线的内容
// 新内容会是HLSLxxx字眼形式出现 (目的是演示如何将CG代码改为URP管线代码)
Shader "MilkShader/Twently/G_GaussianBlur"
{Properties{_MainTex("Texture", 2D) = "white" {}//采样间距系数_BlurSize("Blur Size", Float) = 1.0}SubShader{Tags { "RenderType" = "Opaque" }LOD 100//CGINCLUDE ... ENDCG 是一种组织结构,放在它里面的方法可以被任意Pass直接使用..相当于所有Pass都会有这些内容//CGINCLUDE //CGHLSLINCLUDE//#include "UnityCG.cginc" //CG#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"sampler2D _MainTex;half4 _MainTex_TexelSize;float _BlurSize;//URP下没有appdata_img结构 要自定义struct a2v{float4 vertex : POSITION;float2 texcoord : TEXCOORD0;};struct v2f{float4 pos : SV_POSITION;half2 uv[5] : TEXCOORD0;};//我们只需要appdata_img内置结构的数据传入即可(有顶点、纹理坐标)v2f vertBlurVertical(a2v v) {v2f o;//o.pos = UnityObjectToClipPos(v.vertex); //CGVertexPositionInputs vertexInputs = GetVertexPositionInputs(v.vertex.xyz);o.pos = vertexInputs.positionCS;half2 uv = v.texcoord;//纵向的5个像素点纹理坐标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(a2v v) {v2f o;//o.pos = UnityObjectToClipPos(v.vertex); //CGVertexPositionInputs vertexInputs = GetVertexPositionInputs(v.vertex.xyz);o.pos = vertexInputs.positionCS;half2 uv = v.texcoord;//横向的5个像素点纹理坐标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;}//无论是纵向还是横向,它们都会使用这个片元着色器,处理手法一样half4 fragBlur(v2f i) : SV_Target{float weight[3] = {0.4026, 0.2442, 0.0545};//采样RGB然后进行乘以对应的权重累加到sumhalf3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];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 half4(sum, 1.0);}//ENDCG //CGENDHLSL//上面都是INCLUDE内容即下面Pass都可使用的内容//标配写法ZTest Always Cull Off ZWrite Off//第一个PASS,纵向模糊处理Pass{NAME "GAUSSIAN_BLUR_VERTICAL"//CGPROGRAM //CGHLSLPROGRAM//纵向的顶点着色器#pragma vertex vertBlurVertical//片元着色器#pragma fragment fragBlur//ENDCG //CGENDHLSL}//第二个Pass 横向模糊处理Pass{NAME "GAUSSIAN_BLUR_HORIZONTAL"//CGPROGRAMHLSLPROGRAM//横向的顶点着色器#pragma vertex vertBlurHorizontal//片元着色器#pragma fragment fragBlur//ENDCGENDHLSL}}//完成SubShaderFallback Off
}

1个Canvas和2个摄像机

主要以上内容,实际上就是因为Render Pass Event是只能After Rendering Transpanrets在透明物体渲染完成后进行屏幕后处理模糊,导致无法实现置顶UI高清,底下UI模糊的需求,如果可以控制这个后处理时机是在置顶UI渲染之前进行后处理,等后处理完成后再渲染指定UI 那就可以,然而...

TODO!!!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javaee spring 静态代理

静态代理 package com.test.staticProxy;public interface IUsersService {public void insert(); }package com.test.staticProxy;//目标类 public class UsersService implements IUsersService {Overridepublic void insert() {System.out.println("添加用户");…

设计模式—观察者模式(Observer)

目录 思维导图 一、什么是观察者模式&#xff1f; 二、有什么优点吗&#xff1f; 三、有什么缺点吗&#xff1f; 四、什么时候使用观察者模式&#xff1f; 五、代码展示 ①、双向耦合的代码 ②、解耦实践一 ③、解耦实践二 ④、观察者模式 六、这个模式涉及到了哪些…

信息技术02--初/高中--分类选择题(377道题与解析)

文章目录 第一章 办公软件 1-96第二章 信息技术基础 1-41第三章 计算机系统基础 1-28第四章 多媒体技术 1-115第五章 计算机网络技术 1-50第六章 信息安全 1-3第七章 算法与程序简介 1-13第八章 数据结构 1-2第九章 数据库技术 1-20第十章 练习 1-9 第一章 办公软件 1-96 1、某…

Qt按钮按动、划过背景设置

title: Qt按钮按动、划过背景设置 date: 2023-08-30 19:29:49 tags: Qt按钮按钮背景设置按钮动态效果 categories:Qt学习之路 给按钮添加背景后&#xff0c;原先按钮的按动效果就没了&#xff0c;&#xff08;按钮没有反馈&#xff0c;我的手就会一直在抖&#xff0c;哈哈哈哈…

WebVR — 网络虚拟现实

推荐&#xff1a;使用 NSDT编辑器 快速搭建3D应用场景 虚拟现实设备 随着Oculus Rift和许多其他生产设备即将上市&#xff0c;未来看起来很光明——我们已经有足够的技术来使VR体验“足够好”&#xff0c;可以玩游戏。有许多设备可供选择&#xff1a;像Oculus Rift或HTC Vive这…

JavaScript实现系统级别的取色器、EyeDropper、try、catch、finally

文章目录 效果图htmlJavaScript关键代码EyeDroppertry...catch颜色值相减(色差)的传送门 效果图 html <div class"d_f fd_c ai_c"><button id"idBtn" class"cursor_pointer">开始取色</button><div id"idBox" c…

C++学习笔记总结练习:多态与虚函数

1 多态 多态分类 静态多态&#xff0c;是只在编译期间确定的多态。静态多态在编译期间&#xff0c;根据函数参数的个数和类型推断出调用的函数。静态多态有两种实现的方式 重载。&#xff08;函数重载&#xff09;模板。 动态多态&#xff0c;是运行时多态。通过虚函数机制实…

软件工程(十八) 行为型设计模式(四)

1、状态模式 简要说明 允许一个对象在其内部改变时改变它的行为 速记关键字 状态变成类 类图如下 状态模式主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。比如订单从待付款到待收货的咋黄台发生变化,执行的逻辑是不一样的。 所以我们将状态抽象为一…

Android OTA 相关工具(六) 使用 lpmake 打包生成 super.img

我在 《Android 动态分区详解(二) 核心模块和相关工具介绍》 介绍过 lpmake 工具&#xff0c;这款工具用于将多个分区镜像打包生成一个 Android 专用的动态分区镜像&#xff0c;一般称为 super.img。Android 编译时&#xff0c;系统会自动调用 lpmake 并传入相关参数来生成 sup…

Blender里复制对象动画

假设在Blender里有2个对象&#xff0c;其中一个添加了动画&#xff0c;另外一个没有添加动画&#xff0c;那么如何把已有的动画拷贝到没有动画的对象上呢&#xff1f; 分为2步&#xff1a; 先选中没有动画的对象&#xff0c;再按shift键选中有动画的对象&#xff0c;此时2个对…

前端(十六)——微信小程序语音转文字,文字转语音功能的实现

&#x1f60a;博主&#xff1a;小猫娃来啦 &#x1f60a;文章核心&#xff1a;微信小程序语音转文字&#xff0c;文字转语音功能的实现 文章目录 资源下载链接最关键的问题控制台报错30003语音转文字文字转语音效果图应用场景作用和优势实现思路 资源下载链接 CSDN资源下载&am…

5、Spring之Bean生命周期源码解析(销毁)

Bean的销毁过程 Bean销毁是发送在Spring容器关闭过程中的。 在Spring容器关闭时,比如: AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = (UserService) context.getBean("userSe…