2025-06-07 17:43:34 +08:00

145 lines
6.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
//设置在编辑模式下也执行该脚本
//[ExecuteInEditMode]
//添加选项到菜单中
[AddComponentMenu("RapidBlurEffect")]
public class RapidBlurEffectUtlis : MonoBehaviour
{
static class Uniforms
{
internal static readonly int _DownSampleValue = Shader.PropertyToID("_DownSampleValue");
}
//-------------------变量声明部分-------------------
#region Variables
//指定Shader名称
private string ShaderName = "Learning Unity Shader/Lecture 15/RapidBlurEffect";
public Shader CurShader;
//着色器和材质实例
private Material CurMaterial;
//降采样次数
[Range(0, 6), Tooltip("[降采样次数],,,")]
public int DownSampleNum = 2;
//模糊扩散度
[Range(0.0f, 20.0f), Tooltip("[模糊扩散度]")]
public float BlurSpreadSize = 2.0f;
//迭代次数
[Range(0, 8), Tooltip("[迭代次数],")]
public int BlurIterations = 2;
#endregion
public void SetShader(Shader s)
{
CurShader = s;
}
Material material
{
get
{
if (CurMaterial == null && CurShader != null)
{
CurMaterial = new Material(CurShader);
CurMaterial.hideFlags = HideFlags.HideAndDontSave;
}
return CurMaterial;
}
}
#region Functions
//-----------------------------------------【Start()函数】---------------------------------------------
// 说明此函数仅在Update函数第一次被调用前被调用
//--------------------------------------------------------------------------------------------------------
void Start()
{
//判断当前设备是否支持屏幕特效
if (!SystemInfo.supportsImageEffects)
{
enabled = false;
return;
}
}
//-------------------------------------【OnRenderImage()函数】------------------------------------
// 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果
//--------------------------------------------------------------------------------------------------------
void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
{
//着色器实例不为空,就进行参数设置
if (material != null)
{
//【0】参数准备
//根据向下采样的次数确定宽度系数。用于控制降采样后相邻像素的间隔
float widthMod = 1.0f / (1.0f * (1 << DownSampleNum));
//Shader的降采样参数赋值
//material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod);
material.SetFloat(Uniforms._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);
material.SetFloat(Uniforms._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, material, 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);
}
}
#endregion
}