unity 背景模糊_unity 抓帧 背景模糊-程序员宅基地

技术标签: unity  背景模糊  景深  

shader代码

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'


Shader "Unlit/DoFShader"
{
//-----------------------------------【属性 || Properties】------------------------------------------    
    Properties  
    {  
        //主纹理  
        _MainTex("Base (RGB)", 2D) = "white" {}  
    }  
  
    //----------------------------------【子着色器 || SubShader】---------------------------------------    
    SubShader  
    {  
        ZWrite Off  
        Blend Off  
  
        //---------------------------------------【通道0 || Pass 0】------------------------------------  
        //通道0:降采样通道 ||Pass 0: Down Sample Pass  
        Pass  
        {  
            ZTest Off  
            Cull Off  
  
            CGPROGRAM  
  
            //指定此通道的顶点着色器为vert_DownSmpl  
            #pragma vertex vert_DownSmpl  
            //指定此通道的像素着色器为frag_DownSmpl  
            #pragma fragment frag_DownSmpl  
  
            ENDCG  
  
        }  
  
        //---------------------------------------【通道1 || Pass 1】------------------------------------  
        //通道1:垂直方向模糊处理通道 ||Pass 1: Vertical Pass  
        Pass  
        {  
            ZTest Always  
            Cull Off  
  
            CGPROGRAM  
  
            //指定此通道的顶点着色器为vert_BlurVertical  
            #pragma vertex vert_BlurVertical  
            //指定此通道的像素着色器为frag_Blur  
            #pragma fragment frag_Blur  
  
            ENDCG  
        }  
  
        //---------------------------------------【通道2 || Pass 2】------------------------------------  
        //通道2:水平方向模糊处理通道 ||Pass 2: Horizontal Pass  
        Pass  
        {  
            ZTest Always  
            Cull Off  
  
            CGPROGRAM  
  
            //指定此通道的顶点着色器为vert_BlurHorizontal  
            #pragma vertex vert_BlurHorizontal  
            //指定此通道的像素着色器为frag_Blur  
            #pragma fragment frag_Blur  
  
            ENDCG  
        }  
    }  
  
  
    //-------------------------CG着色语言声明部分 || Begin CG Include Part----------------------    
    CGINCLUDE  
  
    //【1】头文件包含 || include  
    #include "UnityCG.cginc"  
  
    //【2】变量声明 || Variable Declaration  
    sampler2D _MainTex;  
    //UnityCG.cginc中内置的变量,纹理中的单像素尺寸|| it is the size of a texel of the texture  
    uniform half4 _MainTex_TexelSize;  
    //C#脚本控制的变量 || Parameter  
    uniform half _DownSampleValue;  
  
    //【3】顶点输入结构体 || Vertex Input Struct  
    struct VertexInput  
    {  
        //顶点位置坐标  
        float4 vertex : POSITION;  
        //一级纹理坐标  
        half2 texcoord : TEXCOORD0;  
    };  
  
    //【4】降采样输出结构体 || Vertex Input Struct  
    struct VertexOutput_DownSmpl  
    {  
        //像素位置坐标  
        float4 pos : SV_POSITION;  
        //一级纹理坐标(右上)  
        half2 uv20 : TEXCOORD0;  
        //二级纹理坐标(左下)  
        half2 uv21 : TEXCOORD1;  
        //三级纹理坐标(右下)  
        half2 uv22 : TEXCOORD2;  
        //四级纹理坐标(左上)  
        half2 uv23 : TEXCOORD3;  
    };  
  
  
    //【5】准备高斯模糊权重矩阵参数7x4的矩阵 ||  Gauss Weight  
    static const half4 GaussWeight[7] =  
    {  
        half4(0.0205,0.0205,0.0205,0),  
        half4(0.0855,0.0855,0.0855,0),  
        half4(0.232,0.232,0.232,0),  
        half4(0.324,0.324,0.324,1),  
        half4(0.232,0.232,0.232,0),  
        half4(0.0855,0.0855,0.0855,0),  
        half4(0.0205,0.0205,0.0205,0)  
    };  
  
  
    //【6】顶点着色函数 || Vertex Shader Function  
    VertexOutput_DownSmpl vert_DownSmpl(VertexInput v)  
    {  
        //【6.1】实例化一个降采样输出结构  
        VertexOutput_DownSmpl o;  
  
        //【6.2】填充输出结构  
        //将三维空间中的坐标投影到二维窗口    
        o.pos = UnityObjectToClipPos(v.vertex);  
        //对图像的降采样:取像素上下左右周围的点,分别存于四级纹理坐标中  
        o.uv20 = v.texcoord + _MainTex_TexelSize.xy* half2(0.5h, 0.5h);;  
        o.uv21 = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h, -0.5h);  
        o.uv22 = v.texcoord + _MainTex_TexelSize.xy * half2(0.5h, -0.5h);  
        o.uv23 = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h, 0.5h);  
  
        //【6.3】返回最终的输出结果  
        return o;  
    }  
  
    //【7】片段着色函数 || Fragment Shader Function  
    fixed4 frag_DownSmpl(VertexOutput_DownSmpl i) : SV_Target  
    {  
        //【7.1】定义一个临时的颜色值  
        fixed4 color = (0,0,0,0);  
  
        //【7.2】四个相邻像素点处的纹理值相加  
        color += tex2D(_MainTex, i.uv20);  
        color += tex2D(_MainTex, i.uv21);  
        color += tex2D(_MainTex, i.uv22);  
        color += tex2D(_MainTex, i.uv23);  
  
        //【7.3】返回最终的平均值  
        return color / 4;  
    }  
  
    //【8】顶点输入结构体 || Vertex Input Struct  
    struct VertexOutput_Blur  
    {  
        //像素坐标  
        float4 pos : SV_POSITION;  
        //一级纹理(纹理坐标)  
        half4 uv : TEXCOORD0;  
        //二级纹理(偏移量)  
        half2 offset : TEXCOORD1;  
    };  
  
    //【9】顶点着色函数 || Vertex Shader Function  
    VertexOutput_Blur vert_BlurHorizontal(VertexInput v)  
    {  
        //【9.1】实例化一个输出结构  
        VertexOutput_Blur o;  
  
        //【9.2】填充输出结构  
        //将三维空间中的坐标投影到二维窗口    
        o.pos = UnityObjectToClipPos(v.vertex);  
        //纹理坐标  
        o.uv = half4(v.texcoord.xy, 1, 1);  
        //计算X方向的偏移量  
        o.offset = _MainTex_TexelSize.xy * half2(1.0, 0.0) * _DownSampleValue;  
  
        //【9.3】返回最终的输出结果  
        return o;  
    }  
  
    //【10】顶点着色函数 || Vertex Shader Function  
    VertexOutput_Blur vert_BlurVertical(VertexInput v)  
    {  
        //【10.1】实例化一个输出结构  
        VertexOutput_Blur o;  
  
        //【10.2】填充输出结构  
        //将三维空间中的坐标投影到二维窗口    
        o.pos = UnityObjectToClipPos(v.vertex);  
        //纹理坐标  
        o.uv = half4(v.texcoord.xy, 1, 1);  
        //计算Y方向的偏移量  
        o.offset = _MainTex_TexelSize.xy * half2(0.0, 1.0) * _DownSampleValue;  
  
        //【10.3】返回最终的输出结果  
        return o;  
    }  
  
    //【11】片段着色函数 || Fragment Shader Function  
    half4 frag_Blur(VertexOutput_Blur i) : SV_Target  
    {  
        //【11.1】获取原始的uv坐标  
        half2 uv = i.uv.xy;  
  
        //【11.2】获取偏移量  
        half2 OffsetWidth = i.offset;  
        //从中心点偏移3个间隔,从最左或最上开始加权累加  
        half2 uv_withOffset = uv - OffsetWidth * 3.0;  
  
        //【11.3】循环获取加权后的颜色值  
        half4 color = 0;  
        for (int j = 0; j< 7; j++)  
        {  
            //偏移后的像素纹理值  
            half4 texCol = tex2D(_MainTex, uv_withOffset);  
            //待输出颜色值+=偏移后的像素纹理值 x 高斯权重  
            color += texCol * GaussWeight[j];  
            //移到下一个像素处,准备下一次循环加权  
            uv_withOffset += OffsetWidth;  
        }  
  
        //【11.4】返回最终的颜色值  
        return color;  
    }  
  
    //-------------------结束CG着色语言声明部分  || End CG Programming Part------------------               
    ENDCG  
  
    FallBack Off  

}


c#代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


//设置在编辑模式下也执行该脚本  
[ExecuteInEditMode]
//添加选项到菜单中  
[AddComponentMenu("Unlit/DoFShader")]  
public class MyDepthOfField : MonoBehaviour {


//-------------------变量声明部分-------------------  
#region Variables


//指定Shader名称  
private string ShaderName = "Unlit/DoFShader";


//着色器和材质实例  
public Shader CurShader;
private Material CurMaterial;


//几个用于调节参数的中间变量  
public static int ChangeValue;
public static float ChangeValue2;
public static int ChangeValue3;


//降采样次数  
[Range(0, 6), Tooltip("[降采样次数]向下采样的次数。此值越大,则采样间隔越大,需要处理的像素点越少,运行速度越快。")]
public int DownSampleNum = 2;
//模糊扩散度  
[Range(0.0f, 20.0f), Tooltip("[模糊扩散度]进行高斯模糊时,相邻像素点的间隔。此值越大相邻像素间隔越远,图像越模糊。但过大的值会导致失真。")]
public float BlurSpreadSize = 3.0f;
//迭代次数  
[Range(0, 8), Tooltip("[迭代次数]此值越大,则模糊操作的迭代次数越多,模糊效果越好,但消耗越大。")]
public int BlurIterations = 3;


#endregion


//-------------------------材质的get&set----------------------------  
#region MaterialGetAndSet
Material material
{
get
{
if (CurMaterial == null)
{
CurMaterial = new Material(CurShader);
CurMaterial.hideFlags = HideFlags.HideAndDontSave;
}
return CurMaterial;
}
}
#endregion


#region Functions
//-----------------------------------------【Start()函数】---------------------------------------------    
// 说明:此函数仅在Update函数第一次被调用前被调用  
//--------------------------------------------------------------------------------------------------------  
void Start()
{
//依次赋值  
ChangeValue = DownSampleNum;
ChangeValue2 = BlurSpreadSize;
ChangeValue3 = BlurIterations;


//找到当前的Shader文件  
CurShader = Shader.Find(ShaderName);


//判断当前设备是否支持屏幕特效  
if (!SystemInfo.supportsImageEffects)
{
enabled = false;
return;
}
}


//-------------------------------------【OnRenderImage()函数】------------------------------------    
// 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果  
//--------------------------------------------------------------------------------------------------------  
void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
{
//着色器实例不为空,就进行参数设置  
if (CurShader != null)
{
//【0】参数准备  
//根据向下采样的次数确定宽度系数。用于控制降采样后相邻像素的间隔  
float widthMod = 1.0f / (1.0f * (1 << DownSampleNum));
//Shader的降采样参数赋值  
material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod);
//设置渲染模式:双线性  
sourceTexture.filterMode = FilterMode.Bilinear;
//通过右移,准备长、宽参数值  
int renderWidth = sourceTexture.width >> DownSampleNum;
int renderHeight = sourceTexture.height >> DownSampleNum;


// 【1】处理Shader的通道0,用于降采样 ||Pass 0,for down sample  
//准备一个缓存renderBuffer,用于准备存放最终数据  
RenderTexture renderBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);
//设置渲染模式:双线性  
renderBuffer.filterMode = FilterMode.Bilinear;
//拷贝sourceTexture中的渲染数据到renderBuffer,并仅绘制指定的pass0的纹理数据  
Graphics.Blit(sourceTexture, renderBuffer, material, 0);


//【2】根据BlurIterations(迭代次数),来进行指定次数的迭代操作  
for (int i = 0; i < BlurIterations; i++)
{
//【2.1】Shader参数赋值  
//迭代偏移量参数  
float iterationOffs = (i * 1.0f);
//Shader的降采样参数赋值  
material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod + iterationOffs);


// 【2.2】处理Shader的通道1,垂直方向模糊处理 || Pass1,for vertical blur  
// 定义一个临时渲染的缓存tempBuffer  
RenderTexture tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);
// 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass1的纹理数据  
Graphics.Blit(renderBuffer, tempBuffer, material, 1);
//  清空renderBuffer  
RenderTexture.ReleaseTemporary(renderBuffer);
// 将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0和pass1的数据已经准备好  
renderBuffer = tempBuffer;


// 【2.3】处理Shader的通道2,竖直方向模糊处理 || Pass2,for horizontal blur  
// 获取临时渲染纹理  
tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);
// 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass2的纹理数据  
Graphics.Blit(renderBuffer, tempBuffer, CurMaterial, 2);


//【2.4】得到pass0、pass1和pass2的数据都已经准备好的renderBuffer  
// 再次清空renderBuffer  
RenderTexture.ReleaseTemporary(renderBuffer);
// 再次将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0、pass1和pass2的数据都已经准备好  
renderBuffer = tempBuffer;
}


//拷贝最终的renderBuffer到目标纹理,并绘制所有通道的纹理到屏幕  
Graphics.Blit(renderBuffer, destTexture);
//清空renderBuffer  
RenderTexture.ReleaseTemporary(renderBuffer);


}


//着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的  
else
{
//直接拷贝源纹理到目标渲染纹理  
Graphics.Blit(sourceTexture, destTexture);
}
}




//-----------------------------------------【OnValidate()函数】--------------------------------------    
// 说明:此函数在编辑器中该脚本的某个值发生了改变后被调用  
//--------------------------------------------------------------------------------------------------------  
void OnValidate()
{
//将编辑器中的值赋值回来,确保在编辑器中值的改变立刻让结果生效  
ChangeValue = DownSampleNum;
ChangeValue2 = BlurSpreadSize;
ChangeValue3 = BlurIterations;
}


//-----------------------------------------【Update()函数】--------------------------------------    
// 说明:此函数每帧都会被调用  
//--------------------------------------------------------------------------------------------------------  
void Update()
{
//若程序在运行,进行赋值  
if (Application.isPlaying)
{
//赋值  
DownSampleNum = ChangeValue;
BlurSpreadSize = ChangeValue2;
BlurIterations = ChangeValue3;
}
//若程序没有在运行,去寻找对应的Shader文件  
#if UNITY_EDITOR
if (Application.isPlaying != true)
{
CurShader = Shader.Find(ShaderName);
}
#endif


}


//-----------------------------------------【OnDisable()函数】---------------------------------------    
// 说明:当对象变为不可用或非激活状态时此函数便被调用    
//--------------------------------------------------------------------------------------------------------  
void OnDisable()
{
if (CurMaterial)
{
//立即销毁材质实例  
DestroyImmediate(CurMaterial);
}


}


#endregion  

}


效果图



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_18638761/article/details/79472124

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan