using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace LeTai.Effects
|
|
{
|
|
public class ScalableBlur : IBlurAlgorithm
|
|
{
|
|
Material material;
|
|
ScalableBlurConfig config;
|
|
|
|
const int BLUR_PASS = 0;
|
|
const int CROP_BLUR_PASS = 1;
|
|
|
|
Material Material
|
|
{
|
|
get
|
|
{
|
|
if (material == null)
|
|
Material = new Material(Shader.Find("Hidden/EfficientBlur"));
|
|
|
|
return material;
|
|
}
|
|
set => material = value;
|
|
}
|
|
|
|
~ScalableBlur()
|
|
{
|
|
if (!material) return;
|
|
|
|
if (Application.isPlaying)
|
|
Object.Destroy(material);
|
|
else
|
|
Object.DestroyImmediate(material);
|
|
}
|
|
|
|
public void Configure(BlurConfig config)
|
|
{
|
|
this.config = (ScalableBlurConfig) config;
|
|
}
|
|
|
|
public void Blur(CommandBuffer cmd,
|
|
RenderTargetIdentifier src,
|
|
Rect srcCropRegion,
|
|
RenderTexture target)
|
|
{
|
|
float radius = config.Radius;
|
|
Material.SetFloat(ShaderProperties.blurRadius, radius);
|
|
Material.SetVector(ShaderProperties.blurTextureCropRegion, srcCropRegion.ToMinMaxVector());
|
|
|
|
int firstDownsampleFactor = config.Iteration > 0 ? 1 : 0;
|
|
int stepCount = Mathf.Max(config.Iteration * 2 - 1, 1);
|
|
|
|
int firstIRT = ShaderProperties.intermediateRT[0];
|
|
CreateTempRenderTextureFrom(cmd, firstIRT, target, firstDownsampleFactor);
|
|
|
|
// cmd.BlitFullscreenTriangle(src, firstIRT, Material, CROP_BLUR_PASS);
|
|
cmd.Blit(src, firstIRT, Material, CROP_BLUR_PASS);
|
|
|
|
for (var i = 1; i < stepCount; i++)
|
|
{
|
|
BlurAtDepth(cmd, i, target);
|
|
}
|
|
|
|
// cmd.BlitFullscreenTriangle(ShaderProperties.intermediateRT[stepCount - 1], target, Material, BLUR_PASS);
|
|
cmd.Blit(ShaderProperties.intermediateRT[stepCount - 1], target, Material, BLUR_PASS);
|
|
|
|
CleanupIntermediateRT(cmd, stepCount);
|
|
}
|
|
|
|
protected virtual void BlurAtDepth(CommandBuffer cmd, int depth, RenderTexture baseTexture)
|
|
{
|
|
int sizeLevel = Utility.SimplePingPong(depth, config.Iteration - 1) + 1;
|
|
sizeLevel = Mathf.Min(sizeLevel, config.MaxDepth);
|
|
CreateTempRenderTextureFrom(cmd, ShaderProperties.intermediateRT[depth], baseTexture, sizeLevel);
|
|
|
|
// cmd.BlitFullscreenTriangle(
|
|
cmd.Blit(
|
|
ShaderProperties.intermediateRT[depth - 1],
|
|
ShaderProperties.intermediateRT[depth],
|
|
Material,
|
|
0
|
|
);
|
|
}
|
|
|
|
static void CreateTempRenderTextureFrom(CommandBuffer cmd,
|
|
int nameId,
|
|
RenderTexture src,
|
|
int downsampleFactor)
|
|
{
|
|
int w = src.width >> downsampleFactor; //= width / 2^downsample
|
|
int h = src.height >> downsampleFactor;
|
|
|
|
cmd.GetTemporaryRT(nameId, w, h, 0, FilterMode.Bilinear, src.format);
|
|
}
|
|
|
|
static void CleanupIntermediateRT(CommandBuffer cmd, int amount)
|
|
{
|
|
for (var i = 0; i < amount; i++)
|
|
{
|
|
cmd.ReleaseTemporaryRT(ShaderProperties.intermediateRT[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|