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

news2024/11/19 19:22:28

 这里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;//缓冲区1
        private RenderTargetHandle m_Buffer1;//缓冲区2

        private 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_Buffer0
                m_Buffer1 = tmp;
            }
            cmd.Blit(m_Buffer0.Identifier(), m_Source); //将最终结果渲染到摄像机上
            //执行cmd
            context.ExecuteCommandBuffer(cmd);
            //清空回收cmd
            cmd.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); //创建一个pass
        m_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 //CG
		HLSLINCLUDE
		//#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); //CG
			VertexPositionInputs 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); //CG
			VertexPositionInputs 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然后进行乘以对应的权重累加到sum
			half3 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 //CG
		ENDHLSL

		//上面都是INCLUDE内容即下面Pass都可使用的内容
		//标配写法
		ZTest Always Cull Off ZWrite Off
		//第一个PASS,纵向模糊处理
		Pass
		{
			NAME "GAUSSIAN_BLUR_VERTICAL"

			//CGPROGRAM //CG
			HLSLPROGRAM

			//纵向的顶点着色器
			#pragma vertex vertBlurVertical
			//片元着色器
			#pragma fragment fragBlur

			//ENDCG //CG
			ENDHLSL
		}
		//第二个Pass 横向模糊处理
		Pass
		{
			NAME "GAUSSIAN_BLUR_HORIZONTAL"

			//CGPROGRAM
			HLSLPROGRAM

			//横向的顶点着色器
			#pragma vertex vertBlurHorizontal
			//片元着色器
			#pragma fragment fragBlur

			//ENDCG
			ENDHLSL
		}
	}//完成SubShader
	Fallback Off
}

1个Canvas和2个摄像机

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

TODO!!!

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

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

相关文章

Flink 如何处理反压?

分析&回答 什么是反压&#xff08;backpressure&#xff09; 反压通常是从某个节点传导至数据源并降低数据源&#xff08;比如 Kafka consumer&#xff09;的摄入速率。反压意味着数据管道中某个节点成为瓶颈&#xff0c;处理速率跟不上上游发送数据的速率&#xff0c;而…

15种下载文件的方法文件下载方法汇总超大文件下载

15种下载文件的方法&文件下载方法汇总&超大文件下载 15种下载文件的方法Pentesters经常将文件上传到受感染的盒子以帮助进行权限提升&#xff0c;或者保持在计算机上的存在。本博客将介绍将文件从您的计算机移动到受感染系统的15种不同方法。对于那些在盒子上存在且需要…

【java】解决sprintboot项目开发遇到的问题

目录 一、java: 程序包org.junit.jupiter.api不存在 二、Cannot resolve com.mysql:mysql-connector-j:unknown 三、Unsatisfied dependency expressed through bean property sqlSessionFactory; nested exception is org.springframework 四、org.apache.ibatis.binding…

SpringCloudAlibaba常用操作

SpringCloudAlibaba常用操作 微服务概念 1.1 单体、分布式、集群 单体 ⼀个系统业务量很⼩的时候所有的代码都放在⼀个项⽬中就好了&#xff0c;然后这个项⽬部署在⼀台服务器上就 好了。整个项⽬所有的服务都由这台服务器提供。这就是单机结构。 单体应⽤开发简单,部署测试…

mvc 异常处理源码解析(3)

目录 准备源码跟踪ExceptionHandlerExceptionResolver初始化ExceptionHandlerExceptionResolver注入ExceptionHandlerExceptionResolver中exceptionHandlerAdviceCache初始化ExceptionHandlerMethodResolver中mappedMethods初始化 结尾 准备 准备一个controller类, 里面抛出一…

Revit SDK 介绍:CreateAirHandler 创建户式风管机

前言 这个例子介绍如何通过 API 创建一个户式风管机族的内容&#xff0c;包含几何和接头。 内容 效果 核心逻辑 必须打开机械设备的族模板创建几何实体来表示风管机创建风机的接头 创建几何实体来表示风管机 例子中创建了多个拉伸&#xff0c;下面仅截取一段代码&#xff…

OpenGL-入门-BMP像素图glReadPixels(1)实现读取屏幕中间的颜色和获取屏幕上鼠标点击位置的颜色

glReadPixels函数用于从帧缓冲区中读取像素数据。它可以用来获取屏幕上特定位置的像素颜色值或者获取一块区域内的像素数据。下面是该函数的基本语法&#xff1a; void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *da…

LeetCode——字母异位词分组(中等)

题目 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat&quo…

java八股文面试[多线程]——Synchronized优化手段:锁膨胀、锁消除、锁粗化和自适应自旋锁

1.锁膨胀 &#xff08;就是锁升级&#xff09; 我们先来回顾一下锁膨胀对 synchronized 性能的影响&#xff0c;所谓的锁膨胀是指 synchronized 从无锁升级到偏向锁&#xff0c;再到轻量级锁&#xff0c;最后到重量级锁的过程&#xff0c;它叫锁膨胀也叫锁升级。 JDK 1.6 之前…

springdoc-openapi-ui 整合 knife,多模块分组,脚手架

pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…

2023年京东箱包行业数据分析(京东数据运营)

当前&#xff0c;旅游业全面复苏&#xff0c;这一现象也带动了周边产业的火爆。在全国游客的出行热带动下&#xff0c;箱包产业迎来消费热潮。 根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;2023年7月&#xff0c;京东箱包大盘整体的销量为266万&#xff0c;同比增长…

知识图谱笔记:TransH

1 TransE存在的问题 一对多 假设有一个关系 "是父亲"&#xff0c;其中一个父亲&#xff08;头实体&#xff09;可能有多个孩子&#xff08;尾实体&#xff09; 父亲 A -> 孩子 1父亲 A -> 孩子 2在 TransE 中&#xff0c;这两个关系会被建模为&#xff1a; A是…

【pytorch】tensorboard + transforms的使用

一、tensorboard的使用 1. 加载一张图片转化为tensor类型&#xff0c;并通过tenboard可视化 from PIL import Image from torch.utils.tensorboard import SummaryWriter from torchvision import transformsimg_path "dataset/train/ants_image/0013035.jpg"img …

ESXi 6.7添加螃蟹2.5g网卡支持

安装了ESXi 6.7&#xff0c;结果机器两块网卡只能识别一块&#xff0c;然后想着不能让另一块浪费啊&#xff0c;开始折腾&#xff0c;看着网上都是找的驱动然后封装进iso&#xff0c;可是我已经装完了&#xff0c;怎么办&#xff0c;然后找到了下面解决方法 1.找驱动 下载RTL81…

DEAP库文档教程四——操作与算法

本节将将在初始化的基础上&#xff0c;进一步说明操作与算法。 1、Using the Toolbox toolbox(base.Toolbox())是包含所有进化操作的工具箱&#xff0c;从目标初始化到适应度计算。它允许在每个算法中实现简单的构造。toolbox基本上由两种方法组成&#xff0c;register()和un…

工服穿戴检测联动门禁开关算法

工服穿戴检测联动门禁开关算法通过yolov8深度学习框架模型&#xff0c;工服穿戴检测联动门禁开关算法能够准确识别和检测作业人员是否按照规定进行工服着装&#xff0c;只有当人员合规着装时&#xff0c;算法会发送开关量信号给门禁设备&#xff0c;使门禁自动打开。YOLO的结构…

msvcp71.dll丢失怎样修复和msvcr71.dll丢失的解决方法介绍

今天&#xff0c;我将为大家分享一个关于电脑msvcp71.dll丢失的问题及其解决方法。希望这些方法能够帮助到正面临同样问题的朋友们。 首先&#xff0c;让我们来了解一下msvcp71.dll丢失的原因。msvcp71.dll是Microsoft Visual C 2008 Redistributable Package的一个组件&#…

内网隧道代理技术(十九)之 CS工具自带上线不出网机器

CS工具自带上线不出网机器 如图A区域存在一台中转机器,这台机器可以出网,这种是最常见的情况。我们在渗透测试的过程中经常是拿下一台边缘机器,其有多块网卡,边缘机器可以访问内网机器,内网机器都不出网。这种情况下拿这个边缘机器做中转,就可以使用CS工具自带上线不出网…

leetcode55.跳跃游戏 【贪心】

题目&#xff1a; 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例…

DEAP库文档教程二-----创建类型

本节将展示如何通过creator创建类型以及如何使用toolbox进行初始化。 1、Fitness 已经提供的Fitness类是一个抽象类&#xff0c;它需要weight来使得它成为一个函数。一个最小化的适应度是通过负权重构建的&#xff0c;而一个最大化适应度则需要正权重。 creator.create(&quo…